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) <charles@karney.com>
00006  * http://charles.karney.info/geographic
00007  * and licensed under the LGPL.
00008  *
00009  * Compile with
00010  *
00011  *   g++ -g -O3 -I.. -o GeoConvert GeoConvert.cpp GeoCoords.cpp MGRS.cpp UTMUPS.cpp DMS.cpp Constants.cpp TransverseMercator.cpp PolarStereographic.cpp
00012  *
00013  * See \ref geoconvert for usage information.
00014  **********************************************************************/
00015 
00016 #include <iostream>
00017 #include <sstream>
00018 #include <string>
00019 #include <stdexcept>
00020 #include <iomanip>
00021 #include "GeographicLib/GeoCoords.hpp"
00022 
00023 int usage(int retval) {
00024   ( retval ? std::cerr : std::cout ) <<
00025 "Usage: GeoConvert [-g|-d|-u|-m|-c] [-p prec] [-z zone] [-s] [-h]\n\
00026 $Id: GeoConvert.cpp 6559 2009-02-28 16:49:53Z ckarney $\n\
00027 \n\
00028 Convert geographic coordinates to\n\
00029 \n\
00030     -g latitude and longitude (decimal degrees), default output\n\
00031     -d latitude and longitude (degrees mins secs)\n\
00032     -u UTM or UPS\n\
00033     -m MGRS\n\
00034     -c meridian convergence and scale\n\
00035 \n\
00036 The WGS84 model of the earth is used.  Geographic coordinates are given on\n\
00037 standard input as:\n\
00038 \n\
00039 Latitude and longitude (decimal degrees or degrees minutes seconds).  d,\n\
00040 ', and \" are used to denote degrees, minutes, and seconds, with the least\n\
00041 significant designator optional.  Latitude is given first unless a\n\
00042 hemisphere is specified, e.g., the following are all equivalent\n\
00043 \n\
00044     33.3 44.4\n\
00045     E44.4 N33.3\n\
00046     33d18'N 44d24'E\n\
00047     44d24 33d18N\n\
00048 \n\
00049 UTM or UPS given as zone+hemisphere easting northing or easting northing\n\
00050 zone+hemisphere.  The zone is absent for a UPS specification.  E.g.,\n\
00051 \n\
00052     38N 444140.54 3684706.36\n\
00053     444140.54 3684706.36 38N\n\
00054     S 2173854.98 2985980.58\n\
00055     2173854.98 2985980.58 S\n\
00056 \n\
00057 MRGS is used to specify the center of a grid square, e.g.,\n\
00058 \n\
00059     38SMB4484\n\
00060     38SMB44140847064\n\
00061 \n\
00062 -p prec (default 0) sets the precision relative to 1m.  This gives the\n\
00063 number of digits after the decimal point for UTM/UPS.  The number of digits\n\
00064 per coordinate for MGRS is 5 + prec.  For decimal degrees, the number of\n\
00065 digits after the decimal point is 5 + prec.  For DMS (degree, minute,\n\
00066 seconds) output, the number of digits after the decimal point in the\n\
00067 seconds components is 1 + prec; if this is negative then use minutes (prec\n\
00068 = -2 or -3) or degrees (prec <= -4) as the least significant component.\n\
00069 Print convergence, resp. scale, with 5 + prec, resp. 7 + prec, digits after\n\
00070 the decimal point.  The minimum value of prec is -5 and the maximum is 9\n\
00071 for UTM/UPS, 9 for decimal degrees, 10 for DMS, 6 for MGRS, and 8 for\n\
00072 convergence and scale.\n\
00073 \n\
00074 MGRS coordinates are given by truncating (instead of rounding) the\n\
00075 coordinates to the requested precision.  For example is prec = -3, the\n\
00076 result is the 1km square enclosing the position.\n\
00077 \n\
00078 Convergence is the bearing of grid north given as degrees clockwise from\n\
00079 true north.\n\
00080 \n\
00081 UTM/UPS and MGRS are given in zone of the input if applicable, otherwise in\n\
00082 the standard zone.\n\
00083 \n\
00084 -z zone sets the zone for output.  Use zone = 0 to specify UPS.\n\
00085 \n\
00086 -s uses the standard zone.\n\
00087 \n\
00088 For example, the point\n\
00089 \n\
00090     79.9S 6.1E\n\
00091 \n\
00092 corresponds to possible MGRS coordinates\n\
00093 \n\
00094     32CMS4324728161 (standard UTM zone = 32)\n\
00095     31CEM6066227959 (neighboring UTM zone = 31)\n\
00096       BBZ1945517770 (neighboring UPS zone)\n\
00097 \n\
00098 then\n\
00099     echo 79.9S 6.1E      | GeoConvert -p -3 -m       ==> 32CMS4328\n\
00100     echo 31CEM6066227959 | GeoConvert -p -3 -m       ==> 31CEM6027\n\
00101     echo 31CEM6066227959 | GeoConvert -p -3 -m -s    ==> 32CMS4328\n\
00102     echo 31CEM6066227959 | GeoConvert -p -3 -m -z 0  ==>   BBZ1917\n\
00103 \n\
00104 -h prints this help.\n";
00105   return retval;
00106 }
00107 
00108 int main(int argc, char* argv[]) {
00109   enum { GEOGRAPHIC, DMS, UTMUPS, MGRS, CONVERGENCE };
00110   int outputmode = GEOGRAPHIC;
00111   int prec = 0;
00112   int zone = -2;                // -2 = track input, -1 = standard
00113 
00114   for (int m = 1; m < argc; ++m) {
00115     std::string arg = std::string(argv[m]);
00116     if (arg == "-g")
00117       outputmode = GEOGRAPHIC;
00118     else if (arg == "-d")
00119       outputmode = DMS;
00120     else if (arg == "-u")
00121       outputmode = UTMUPS;
00122     else if (arg == "-m")
00123       outputmode = MGRS;
00124     else if (arg == "-c")
00125       outputmode = CONVERGENCE;
00126     else if (arg == "-p") {
00127       if (++m == argc) return usage(1);
00128       std::string a = std::string(argv[m]);
00129       std::istringstream str(a);
00130       if (!(str >> prec)) return usage(1);
00131     } else if (arg == "-z") {
00132       if (++m == argc) return usage(1);
00133       std::string a = std::string(argv[m]);
00134       std::istringstream str(a);
00135       if (!(str >> zone)) return usage(1);
00136     } else if (arg == "-s")
00137       zone = -1;
00138     else
00139       return usage(arg != "-h");
00140   }
00141 
00142   GeographicLib::GeoCoords p;
00143   std::string s;
00144   std::string os;
00145   int retval = 0;
00146   if (!(zone >= -2 && zone <= 60)) {
00147     std::cerr << "Zone " << zone << "not in [0, 60]\n";
00148     return 1;
00149   }
00150   while (std::getline(std::cin, s)) {
00151     try {
00152       p.Reset(s);
00153       if (zone != -2)
00154         p.SetAltZone(zone);
00155       switch (outputmode) {
00156       case GEOGRAPHIC:
00157         os = p.GeoRepresentation(prec);
00158         break;
00159       case DMS:
00160         os = p.DMSRepresentation(prec);
00161         break;
00162       case UTMUPS:
00163         os = p.AltUTMUPSRepresentation(prec);
00164         break;
00165       case MGRS:
00166         os = p.AltMGRSRepresentation(prec);
00167         break;
00168       case CONVERGENCE:
00169         {
00170           double
00171             gamma = p.AltConvergence(),
00172             k = p.AltScale();
00173           std::ostringstream ss;
00174           ss << std::fixed
00175              << std::setprecision(std::max(-5, std::min(8, prec)) + 5) << gamma
00176              << " "
00177              << std::setprecision(std::max(-5, std::min(8, prec)) + 7) << k;
00178           os = ss.str();
00179         }
00180       }
00181     }
00182     catch (std::out_of_range& e) {
00183       // Write error message cout so output lines match input lines
00184       os = std::string("ERROR: ") + e.what();
00185       retval = 1;
00186     }
00187     std::cout << os << std::endl;
00188   }
00189   return retval;
00190 }