GeographicLib
1.21
|
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 }