GeographicLib  1.21
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-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 Geod \
00011  *       Geod.cpp \
00012  *       ../src/DMS.cpp \
00013  *       ../src/Geodesic.cpp \
00014  *       ../src/GeodesicLine.cpp
00015  *
00016  * See the <a href="Geod.1.html">man page</a> for usage
00017  * information.
00018  **********************************************************************/
00019 
00020 #include <iostream>
00021 #include <sstream>
00022 #include <string>
00023 #include <sstream>
00024 #include <fstream>
00025 #include <GeographicLib/Geodesic.hpp>
00026 #include <GeographicLib/GeodesicLine.hpp>
00027 #include <GeographicLib/DMS.hpp>
00028 #include <GeographicLib/Utility.hpp>
00029 
00030 #include "Geod.usage"
00031 
00032 typedef GeographicLib::Math::real real;
00033 
00034 std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep) {
00035   using namespace GeographicLib;
00036   return dms ?
00037     DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) + " " +
00038     DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
00039     DMS::Encode(lat, prec + 5, DMS::NUMBER) + " " +
00040     DMS::Encode(lon, prec + 5, DMS::NUMBER);
00041 }
00042 
00043 std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
00044   using namespace GeographicLib;
00045   return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
00046     DMS::Encode(azi >= 180 ? azi - 360 : azi, prec + 5, DMS::NUMBER);
00047 }
00048 
00049 std::string DistanceStrings(real s12, real a12,
00050                             bool full, bool arcmode, int prec, bool dms) {
00051   using namespace GeographicLib;
00052   std::string s;
00053   if (full || !arcmode)
00054     s += Utility::str<real>(s12, prec);
00055   if (full)
00056     s += " ";
00057   if (full || arcmode)
00058     s += DMS::Encode(a12, prec + 5, dms ? DMS::NONE : DMS::NUMBER);
00059   return s;
00060 }
00061 
00062 real ReadDistance(const std::string& s, bool arcmode) {
00063   using namespace GeographicLib;
00064   return arcmode ? DMS::DecodeAngle(s) : Utility::num<real>(s);
00065 }
00066 
00067 int main(int argc, char* argv[]) {
00068   try {
00069     using namespace GeographicLib;
00070     bool linecalc = false, inverse = false, arcmode = false,
00071       dms = false, full = false;
00072     real
00073       a = Constants::WGS84_a<real>(),
00074       f = Constants::WGS84_f<real>();
00075     real lat1, lon1, azi1, lat2, lon2, azi2, s12, m12, a12, M12, M21, S12;
00076     real azi2sense = 0;
00077     int prec = 3;
00078     std::string istring, ifile, ofile, cdelim;
00079     char lsep = ';', dmssep = char(0);
00080 
00081     for (int m = 1; m < argc; ++m) {
00082       std::string arg(argv[m]);
00083       if (arg == "-i") {
00084         inverse = true;
00085         linecalc = false;
00086       } else if (arg == "-a")
00087         arcmode = true;
00088       else if (arg == "-l") {
00089         inverse = false;
00090         linecalc = true;
00091         if (m + 3 >= argc) return usage(1, true);
00092         try {
00093           DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
00094                             lat1, lon1);
00095           azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
00096         }
00097         catch (const std::exception& e) {
00098           std::cerr << "Error decoding arguments of -l: " << e.what() << "\n";
00099           return 1;
00100         }
00101         m += 3;
00102       } else if (arg == "-e") {
00103         if (m + 2 >= argc) return usage(1, true);
00104         try {
00105           a = Utility::num<real>(std::string(argv[m + 1]));
00106           f = Utility::fract<real>(std::string(argv[m + 2]));
00107         }
00108         catch (const std::exception& e) {
00109           std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
00110           return 1;
00111         }
00112         m += 2;
00113       }
00114       else if (arg == "-d") {
00115         dms = true;
00116         dmssep = '\0';
00117       } else if (arg == "-:") {
00118         dms = true;
00119         dmssep = ':';
00120       } else if (arg == "-b")
00121         azi2sense = 180;
00122       else if (arg == "-f")
00123         full = true;
00124       else if (arg == "-p") {
00125         if (++m == argc) return usage(1, true);
00126         try {
00127           prec = Utility::num<int>(std::string(argv[m]));
00128         }
00129         catch (const std::exception&) {
00130           std::cerr << "Precision " << argv[m] << " is not a number\n";
00131           return 1;
00132         }
00133       } else if (arg == "--input-string") {
00134         if (++m == argc) return usage(1, true);
00135         istring = argv[m];
00136       } else if (arg == "--input-file") {
00137         if (++m == argc) return usage(1, true);
00138         ifile = argv[m];
00139       } else if (arg == "--output-file") {
00140         if (++m == argc) return usage(1, true);
00141         ofile = argv[m];
00142       } else if (arg == "--line-separator") {
00143         if (++m == argc) return usage(1, true);
00144         if (std::string(argv[m]).size() != 1) {
00145           std::cerr << "Line separator must be a single character\n";
00146           return 1;
00147         }
00148         lsep = argv[m][0];
00149       } else if (arg == "--comment-delimiter") {
00150         if (++m == argc) return usage(1, true);
00151         cdelim = argv[m];
00152       } else if (arg == "--version") {
00153         std::cout
00154           << argv[0]
00155           << ": $Id: 68e3a8ec4a5717094498179912279a756f6e3f8b $\n"
00156           << "GeographicLib version " << GEOGRAPHICLIB_VERSION_STRING << "\n";
00157         return 0;
00158       } else
00159         return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
00160     }
00161 
00162     if (!ifile.empty() && !istring.empty()) {
00163       std::cerr << "Cannot specify --input-string and --input-file together\n";
00164       return 1;
00165     }
00166     if (ifile == "-") ifile.clear();
00167     std::ifstream infile;
00168     std::istringstream instring;
00169     if (!ifile.empty()) {
00170       infile.open(ifile.c_str());
00171       if (!infile.is_open()) {
00172         std::cerr << "Cannot open " << ifile << " for reading\n";
00173         return 1;
00174       }
00175     } else if (!istring.empty()) {
00176       std::string::size_type m = 0;
00177       while (true) {
00178         m = istring.find(lsep, m);
00179         if (m == std::string::npos)
00180           break;
00181         istring[m] = '\n';
00182       }
00183       instring.str(istring);
00184     }
00185     std::istream* input = !ifile.empty() ? &infile :
00186       (!istring.empty() ? &instring : &std::cin);
00187 
00188     std::ofstream outfile;
00189     if (ofile == "-") ofile.clear();
00190     if (!ofile.empty()) {
00191       outfile.open(ofile.c_str());
00192       if (!outfile.is_open()) {
00193         std::cerr << "Cannot open " << ofile << " for writing\n";
00194         return 1;
00195       }
00196     }
00197     std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
00198 
00199     const Geodesic geod(a, f);
00200     GeodesicLine l;
00201     if (linecalc)
00202       l = geod.Line(lat1, lon1, azi1);
00203 
00204     // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
00205     // 10^-11 sec (= 0.3 nm).
00206     prec = std::min(10, std::max(0, prec));
00207     std::string s;
00208     int retval = 0;
00209     while (std::getline(*input, s)) {
00210       try {
00211         std::string eol("\n");
00212         if (!cdelim.empty()) {
00213           std::string::size_type m = s.find(cdelim);
00214           if (m != std::string::npos) {
00215             eol = " " + s.substr(m) + "\n";
00216             s = s.substr(0, m);
00217           }
00218         }
00219         std::istringstream str(s);
00220         if (inverse) {
00221           std::string slat1, slon1, slat2, slon2;
00222           if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
00223             throw GeographicErr("Incomplete input: " + s);
00224           std::string strc;
00225           if (str >> strc)
00226             throw GeographicErr("Extraneous input: " + strc);
00227           DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00228           DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
00229           a12 = geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2,
00230                              m12, M12, M21, S12);
00231           if (full)
00232             *output << LatLonString(lat1, lon1, prec, dms, dmssep) << " ";
00233           *output << AzimuthString(azi1, prec, dms, dmssep) << " ";
00234           if (full)
00235             *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " ";
00236           *output << AzimuthString(azi2 + azi2sense, prec, dms, dmssep) << " "
00237                   << DistanceStrings(s12, a12, full, arcmode, prec, dms);
00238           if (full)
00239             *output << " " << Utility::str<real>(m12, prec)
00240                     << " " << Utility::str<real>(M12, prec+7)
00241                     << " " << Utility::str<real>(M21, prec+7)
00242                     << " " << Utility::str<real>(S12, std::max(prec-7, 0));
00243           *output << eol;
00244         } else {
00245           if (linecalc) {
00246             std::string ss12;
00247             if (!(str >> ss12))
00248               throw GeographicErr("Incomplete input: " + s);
00249             std::string strc;
00250             if (str >> strc)
00251               throw GeographicErr("Extraneous input: " + strc);
00252             s12 = ReadDistance(ss12, arcmode);
00253             if (arcmode)
00254               l.ArcPosition(s12, lat2, lon2, azi2, a12, m12, M12, M21, S12);
00255             else
00256               a12 = l.Position(s12, lat2, lon2, azi2, m12, M12, M21, S12);
00257           } else {
00258             std::string slat1, slon1, sazi1, ss12;
00259             if (!(str >> slat1 >> slon1 >> sazi1 >> ss12))
00260               throw GeographicErr("Incomplete input: " + s);
00261             std::string strc;
00262             if (str >> strc)
00263               throw GeographicErr("Extraneous input: " + strc);
00264             DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00265             azi1 = DMS::DecodeAzimuth(sazi1);
00266             s12 = ReadDistance(ss12, arcmode);
00267             if (arcmode)
00268               geod.ArcDirect(lat1, lon1, azi1, s12, lat2, lon2, azi2, a12,
00269                              m12, M12, M21, S12);
00270             else
00271               a12 = geod.Direct(lat1, lon1, azi1, s12, lat2, lon2, azi2,
00272                                 m12, M12, M21, S12);
00273           }
00274           if (arcmode)
00275             std::swap(s12, a12);
00276           if (full)
00277             *output << LatLonString(lat1, lon1, prec, dms, dmssep) << " "
00278                     << AzimuthString(azi1, prec, dms, dmssep) << " ";
00279           *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
00280                   << AzimuthString(azi2 + azi2sense, prec, dms, dmssep);
00281           if (full)
00282             *output << " "
00283                     << DistanceStrings(s12, a12, full, arcmode, prec, dms)
00284                     << " " << Utility::str<real>(m12, prec)
00285                     << " " << Utility::str<real>(M12, prec+7)
00286                     << " " << Utility::str<real>(M21, prec+7)
00287                     << " " << Utility::str<real>(S12, std::max(prec-7, 0));
00288           *output << eol;
00289         }
00290       }
00291       catch (const std::exception& e) {
00292         // Write error message cout so output lines match input lines
00293         *output << "ERROR: " << e.what() << "\n";
00294         retval = 1;
00295       }
00296     }
00297     return retval;
00298   }
00299   catch (const std::exception& e) {
00300     std::cerr << "Caught exception: " << e.what() << "\n";
00301     return 1;
00302   }
00303   catch (...) {
00304     std::cerr << "Caught unknown exception\n";
00305     return 1;
00306   }
00307 }