Geod.cpp

Go to the documentation of this file.
00001 /**
00002  * \file Geod.cpp
00003  * \brief Command line utility for geodesic calculations
00004  *
00005  * Copyright (c) Charles Karney (2009, 2010, 2011) <charles@karney.com>
00006  * and licensed under the LGPL.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  *
00009  * Compile with -I../include and link with Geodesic.o GeodesicLine.o DMS.o
00010  *
00011  * See the <a href="Geod.1.html">man page</a> for usage
00012  * information.
00013  **********************************************************************/
00014 
00015 #include "GeographicLib/Geodesic.hpp"
00016 #include "GeographicLib/GeodesicLine.hpp"
00017 #include "GeographicLib/DMS.hpp"
00018 #include <iostream>
00019 #include <sstream>
00020 
00021 #include "Geod.usage"
00022 
00023 typedef GeographicLib::Math::real real;
00024 
00025 std::string LatLonString(real lat, real lon, int prec, bool dms) {
00026   using namespace GeographicLib;
00027   return dms ?
00028     DMS::Encode(lat, prec + 5, DMS::LATITUDE) + " " +
00029     DMS::Encode(lon, prec + 5, DMS::LONGITUDE) :
00030     DMS::Encode(lat, prec + 5, DMS::NUMBER) + " " +
00031     DMS::Encode(lon, prec + 5, DMS::NUMBER);
00032 }
00033 
00034 std::string AzimuthString(real azi, int prec, bool dms) {
00035   using namespace GeographicLib;
00036   return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH) :
00037     DMS::Encode(azi >= 180 ? azi - 360 : azi, prec + 5, DMS::NUMBER);
00038 }
00039 
00040 std::string DistanceStrings(real s12, real a12,
00041                             bool full, bool arcmode, int prec, bool dms) {
00042   using namespace GeographicLib;
00043   std::string s;
00044   if (full || !arcmode)
00045     s += DMS::Encode(s12, prec, DMS::NUMBER);
00046   if (full)
00047     s += " ";
00048   if (full || arcmode)
00049     s += dms ? DMS::Encode(a12, prec + 5, DMS::NONE) :
00050       DMS::Encode(a12, prec + 5, DMS::NUMBER);
00051   return s;
00052 }
00053 
00054 real ReadDistance(const std::string& s, bool arcmode) {
00055   using namespace GeographicLib;
00056   return arcmode ? DMS::DecodeAngle(s) : DMS::Decode(s);
00057 }
00058 
00059 int main(int argc, char* argv[]) {
00060   using namespace GeographicLib;
00061   bool linecalc = false, inverse = false, arcmode = false,
00062     dms = false, full = false;
00063   real
00064     a = Constants::WGS84_a<real>(),
00065     r = Constants::WGS84_r<real>();
00066   real lat1, lon1, azi1, lat2, lon2, azi2, s12, m12, a12;
00067   real azi2sense = 0;
00068   int prec = 3;
00069 
00070   for (int m = 1; m < argc; ++m) {
00071     std::string arg(argv[m]);
00072     if (arg == "-i") {
00073       inverse = true;
00074       linecalc = false;
00075     } else if (arg == "-a")
00076       arcmode = true;
00077     else if (arg == "-l") {
00078       inverse = false;
00079       linecalc = true;
00080       if (m + 3 >= argc) return usage(1, true);
00081       try {
00082         DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
00083                           lat1, lon1);
00084         azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
00085       }
00086       catch (const std::exception& e) {
00087         std::cerr << "Error decoding arguments of -l: " << e.what() << "\n";
00088         return 1;
00089       }
00090       m += 3;
00091     } else if (arg == "-n") {   // Deprecated and so not documented
00092       a = 6378388;
00093       r = 297;
00094     } else if (arg == "-e") {
00095       if (m + 2 >= argc) return usage(1, true);
00096       try {
00097         a = DMS::Decode(std::string(argv[m + 1]));
00098         r = DMS::Decode(std::string(argv[m + 2]));
00099       }
00100       catch (const std::exception& e) {
00101         std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
00102         return 1;
00103       }
00104       m += 2;
00105     }
00106     else if (arg == "-d")
00107       dms = true;
00108     else if (arg == "-b")
00109       azi2sense = 180;
00110     else if (arg == "-f")
00111       full = true;
00112     else if (arg == "-p") {
00113       if (++m == argc) return usage(1, true);
00114       std::istringstream str(argv[m]);
00115       char c;
00116       if (!(str >> prec) || (str >> c)) {
00117           std::cerr << "Precision " << argv[m] << " is not a number\n";
00118           return 1;
00119       }
00120     } else if (arg == "--version") {
00121       std::cout
00122         << PROGRAM_NAME
00123         << ": $Id: Geod.cpp 6978 2011-02-21 22:42:11Z karney $\n"
00124         << "GeographicLib version " << GEOGRAPHICLIB_VERSION << "\n";
00125       return 0;
00126     } else
00127       return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
00128   }
00129 
00130   const Geodesic geod(a, r);
00131   GeodesicLine l;
00132   if (linecalc)
00133     l = geod.Line(lat1, lon1, azi1);
00134 
00135   // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
00136   // 10^-11 sec (= 0.3 nm).
00137   prec = std::min(10, std::max(0, prec));
00138   std::string s;
00139   int retval = 0;
00140   while (std::getline(std::cin, s)) {
00141     try {
00142       std::istringstream str(s);
00143       if (inverse) {
00144         std::string slat1, slon1, slat2, slon2;
00145         if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
00146           throw GeographicErr("Incomplete input: " + s);
00147         std::string strc;
00148         if (str >> strc)
00149           throw GeographicErr("Extraneous input: " + strc);
00150         DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00151         DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
00152         a12 = geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2, m12);
00153         if (full)
00154           std::cout << LatLonString(lat1, lon1, prec, dms) << " ";
00155         std::cout << AzimuthString(azi1, prec, dms) << " ";
00156         if (full)
00157           std::cout << LatLonString(lat2, lon2, prec, dms) << " ";
00158         std::cout << AzimuthString(azi2 + azi2sense, prec, dms) << " "
00159                   << DistanceStrings(s12, a12, full, arcmode, prec, dms) << " "
00160                   << DMS::Encode(m12, prec, DMS::NUMBER) << "\n";
00161       } else {
00162         if (linecalc) {
00163           std::string ss12;
00164           if (!(str >> ss12))
00165             throw GeographicErr("Incomplete input: " + s);
00166           std::string strc;
00167           if (str >> strc)
00168             throw GeographicErr("Extraneous input: " + strc);
00169           s12 = ReadDistance(ss12, arcmode);
00170           if (arcmode)
00171             l.ArcPosition(s12, lat2, lon2, azi2, a12, m12);
00172           else
00173             a12 = l.Position(s12, lat2, lon2, azi2, m12);
00174         } else {
00175           std::string slat1, slon1, sazi1, ss12;
00176           if (!(str >> slat1 >> slon1 >> sazi1 >> ss12))
00177             throw GeographicErr("Incomplete input: " + s);
00178           std::string strc;
00179           if (str >> strc)
00180             throw GeographicErr("Extraneous input: " + strc);
00181           DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00182           azi1 = DMS::DecodeAzimuth(sazi1);
00183           s12 = ReadDistance(ss12, arcmode);
00184           if (arcmode)
00185             geod.ArcDirect(lat1, lon1, azi1, s12, lat2, lon2, azi2, a12, m12);
00186           else
00187             a12 = geod.Direct(lat1, lon1, azi1, s12, lat2, lon2, azi2, m12);
00188         }
00189         if (arcmode)
00190           std::swap(s12, a12);
00191         if (full)
00192           std::cout << LatLonString(lat1, lon1, prec, dms) << " "
00193                     << AzimuthString(azi1, prec, dms) << " ";
00194         std::cout << LatLonString(lat2, lon2, prec, dms) << " "
00195                   << AzimuthString(azi2 + azi2sense, prec, dms);
00196         if (full)
00197           std::cout << " "
00198                     << DistanceStrings(s12, a12, full, arcmode, prec, dms);
00199         std::cout << " " << DMS::Encode(m12, prec, DMS::NUMBER) << "\n";
00200       }
00201     }
00202     catch (const std::exception& e) {
00203       // Write error message cout so output lines match input lines
00204       std::cout << "ERROR: " << e.what() << "\n";
00205       retval = 1;
00206     }
00207   }
00208   return retval;
00209 }