GeographicLib  1.21
GeoConvert.cpp
Go to the documentation of this file.
00001 /**
00002  * \file GeoConvert.cpp
00003  * \brief Command line utility for geographic coordinate conversions
00004  *
00005  * Copyright (c) Charles Karney (2008-2012) <charles@karney.com> and licensed
00006  * under the MIT/X11 License.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  *
00009  * Compile and link with
00010  *   g++ -g -O3 -I../include -I../man -o GeoConvert \
00011  *       GeoConvert.cpp \
00012  *       ../src/DMS.cpp \
00013  *       ../src/GeoCoords.cpp \
00014  *       ../src/MGRS.cpp \
00015  *       ../src/PolarStereographic.cpp \
00016  *       ../src/TransverseMercator.cpp \
00017  *       ../src/UTMUPS.cpp
00018  *
00019  * See the <a href="GeoConvert.1.html">man page</a> for usage
00020  * information.
00021  **********************************************************************/
00022 
00023 #include <iostream>
00024 #include <sstream>
00025 #include <string>
00026 #include <sstream>
00027 #include <fstream>
00028 #include <GeographicLib/GeoCoords.hpp>
00029 #include <GeographicLib/DMS.hpp>
00030 #include <GeographicLib/Utility.hpp>
00031 
00032 #include "GeoConvert.usage"
00033 
00034 int main(int argc, char* argv[]) {
00035   try {
00036     using namespace GeographicLib;
00037     typedef Math::real real;
00038     enum { GEOGRAPHIC, DMS, UTMUPS, MGRS, CONVERGENCE };
00039     int outputmode = GEOGRAPHIC;
00040     int prec = 0;
00041     int zone = UTMUPS::MATCH;
00042     bool centerp = true, swaplatlong = false;
00043     std::string istring, ifile, ofile, cdelim;
00044     char lsep = ';', dmssep = char(0);
00045 
00046     for (int m = 1; m < argc; ++m) {
00047       std::string arg(argv[m]);
00048       if (arg == "-g")
00049         outputmode = GEOGRAPHIC;
00050       else if (arg == "-d") {
00051         outputmode = DMS;
00052         dmssep = '\0';
00053       } else if (arg == "-:") {
00054         outputmode = DMS;
00055         dmssep = ':';
00056       } else if (arg == "-u")
00057         outputmode = UTMUPS;
00058       else if (arg == "-m")
00059         outputmode = MGRS;
00060       else if (arg == "-c")
00061         outputmode = CONVERGENCE;
00062       else if (arg == "-n")
00063         centerp = false;
00064       else if (arg == "-w")
00065         swaplatlong = true;
00066       else if (arg == "-p") {
00067         if (++m == argc) return usage(1, true);
00068         try {
00069           prec = Utility::num<int>(std::string(argv[m]));
00070         }
00071         catch (const std::exception&) {
00072           std::cerr << "Precision " << argv[m] << " is not a number\n";
00073           return 1;
00074         }
00075       } else if (arg == "-z") {
00076         if (++m == argc) return usage(1, true);
00077         std::string zonestr(argv[m]);
00078         try {
00079           bool northp;
00080           UTMUPS::DecodeZone(zonestr, zone, northp);
00081         }
00082         catch (const std::exception&) {
00083           std::istringstream str(zonestr);
00084           char c;
00085           if (!(str >> zone) || (str >> c)) {
00086             std::cerr << "Zone " << zonestr
00087                       << " is not a number or zone+hemisphere\n";
00088             return 1;
00089           }
00090           if (!(zone >= UTMUPS::MINZONE && zone <= UTMUPS::MAXZONE)) {
00091             std::cerr << "Zone " << zone << " not in [0, 60]\n";
00092             return 1;
00093           }
00094         }
00095       } else if (arg == "-s")
00096         zone = UTMUPS::STANDARD;
00097       else if (arg == "-t")
00098         zone = UTMUPS::UTM;
00099       else if (arg == "--input-string") {
00100         if (++m == argc) return usage(1, true);
00101         istring = argv[m];
00102       } else if (arg == "--input-file") {
00103         if (++m == argc) return usage(1, true);
00104         ifile = argv[m];
00105       } else if (arg == "--output-file") {
00106         if (++m == argc) return usage(1, true);
00107         ofile = argv[m];
00108       } else if (arg == "--line-separator") {
00109         if (++m == argc) return usage(1, true);
00110         if (std::string(argv[m]).size() != 1) {
00111           std::cerr << "Line separator must be a single character\n";
00112           return 1;
00113         }
00114         lsep = argv[m][0];
00115       } else if (arg == "--comment-delimiter") {
00116         if (++m == argc) return usage(1, true);
00117         cdelim = argv[m];
00118       } else if (arg == "--version") {
00119         std::cout
00120           << argv[0]
00121           << ": $Id: e39b9974b58d123fd979b1c3c086ae3ccccba72d $\n"
00122           << "GeographicLib version " << GEOGRAPHICLIB_VERSION_STRING << "\n";
00123         return 0;
00124       } else
00125         return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
00126     }
00127 
00128     if (!ifile.empty() && !istring.empty()) {
00129       std::cerr << "Cannot specify --input-string and --input-file together\n";
00130       return 1;
00131     }
00132     if (ifile == "-") ifile.clear();
00133     std::ifstream infile;
00134     std::istringstream instring;
00135     if (!ifile.empty()) {
00136       infile.open(ifile.c_str());
00137       if (!infile.is_open()) {
00138         std::cerr << "Cannot open " << ifile << " for reading\n";
00139         return 1;
00140       }
00141     } else if (!istring.empty()) {
00142       std::string::size_type m = 0;
00143       while (true) {
00144         m = istring.find(lsep, m);
00145         if (m == std::string::npos)
00146           break;
00147         istring[m] = '\n';
00148       }
00149       instring.str(istring);
00150     }
00151     std::istream* input = !ifile.empty() ? &infile :
00152       (!istring.empty() ? &instring : &std::cin);
00153 
00154     std::ofstream outfile;
00155     if (ofile == "-") ofile.clear();
00156     if (!ofile.empty()) {
00157       outfile.open(ofile.c_str());
00158       if (!outfile.is_open()) {
00159         std::cerr << "Cannot open " << ofile << " for writing\n";
00160         return 1;
00161       }
00162     }
00163     std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
00164 
00165     GeoCoords p;
00166     std::string s;
00167     std::string os;
00168     int retval = 0;
00169 
00170     while (std::getline(*input, s)) {
00171       std::string eol("\n");
00172       try {
00173         if (!cdelim.empty()) {
00174           std::string::size_type m = s.find(cdelim);
00175           if (m != std::string::npos) {
00176             eol = " " + s.substr(m) + "\n";
00177             s = s.substr(0, m);
00178           }
00179         }
00180         p.Reset(s, centerp, swaplatlong);
00181         p.SetAltZone(zone);
00182         switch (outputmode) {
00183         case GEOGRAPHIC:
00184           os = p.GeoRepresentation(prec, swaplatlong);
00185           break;
00186         case DMS:
00187           os = p.DMSRepresentation(prec, swaplatlong, dmssep);
00188           break;
00189         case UTMUPS:
00190           os = p.AltUTMUPSRepresentation(prec);
00191           break;
00192         case MGRS:
00193           os = p.AltMGRSRepresentation(prec);
00194           break;
00195         case CONVERGENCE:
00196           {
00197             real
00198               gamma = p.AltConvergence(),
00199               k = p.AltScale();
00200             os =
00201               Utility::str<real>(gamma, std::max(-5,std::min(8,prec))+5)
00202               + " " +
00203               Utility::str<real>(k, std::max(-5,std::min(8,prec))+7);
00204           }
00205         }
00206       }
00207       catch (const std::exception& e) {
00208         // Write error message to cout so output lines match input lines
00209         os = std::string("ERROR: ") + e.what();
00210         retval = 1;
00211       }
00212       *output << os << eol;
00213     }
00214     return retval;
00215   }
00216   catch (const std::exception& e) {
00217     std::cerr << "Caught exception: " << e.what() << "\n";
00218     return 1;
00219   }
00220   catch (...) {
00221     std::cerr << "Caught unknown exception\n";
00222     return 1;
00223   }
00224 }