00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <string>
00017 #include <iostream>
00018 #include <iomanip>
00019 #include <sstream>
00020 #include <stdexcept>
00021 #include "GeographicLib/Geodesic.hpp"
00022 #include "GeographicLib/DMS.hpp"
00023
00024 int usage(int retval) {
00025 ( retval ? std::cerr : std::cout ) <<
00026 "Usage: Geod [-l lat1 lon1 azi1 | -i] [-n] [-d] [-f] [-p prec] [-h]\n\
00027 $Id: Geod.cpp 6572 2009-03-01 22:41:48Z ckarney $\n\
00028 \n\
00029 Perform geodesic calculations.\n\
00030 \n\
00031 The shortest path between two points on the ellipsoid at (lat1, lon1)\n\
00032 and (lat2, lon2) is called the geodesic. Its length is s12 and the\n\
00033 geodesic from point 1 to point 2 has azimuths azi1 and azi2 at the two\n\
00034 end points.\n\
00035 \n\
00036 Geod operates in one of three modes:\n\
00037 \n\
00038 (1) It accepts lines on the standard input containing \"lat1 lon1 azi1\n\
00039 s12\" and prints \"lat2 lon2 azi2\" on standard output. This is the\n\
00040 direct geodesic calculation.\n\
00041 \n\
00042 (2) Command line arguments \"-l lat1 lon1 azi1\" specify a geodesic line.\n\
00043 Geod then accepts a sequence of s12 values (one per line) on\n\
00044 standard input and prints \"lat2 lon2 azi2\" for each. This generates\n\
00045 a sequence of points on a single geodesic.\n\
00046 \n\
00047 (3) With the -i command line argument, Geod performs the inverse\n\
00048 geodesic calculation. It reads lines containing \"lat1 lon1 lat2\n\
00049 lon2\" and prints the corresponding values of \"azi1 azi2 s12\".\n\
00050 \n\
00051 By default, the WGS84 ellipsoid is used. With the -n option, it uses\n\
00052 the international ellipsoid (major radius 6378388 m, inverse flattening\n\
00053 297).\n\
00054 \n\
00055 Output of angles is as decimal degrees. If -d is specified the output\n\
00056 is as degrees, minutes, seconds. Input can be in either style. d, ',\n\
00057 and \" are used to denote degrees, minutes, and seconds, with the least\n\
00058 significant designator optional. By default, latitude precedes\n\
00059 longitude for each point; however on input either may be given first by\n\
00060 appending N or S to the latitude and E or W to the longitude. s12 is\n\
00061 always given in meters.\n\
00062 \n\
00063 The output lines consist of the three quantities needs to complete the\n\
00064 specification of the geodesic. With the -f option, each line of output\n\
00065 is a complete geodesic specification consisting of seven quantities\n\
00066 \n\
00067 lat1 lon1 azi1 lat2 lon2 azi2 s12\n\
00068 \n\
00069 -p prec (default 3) gives the precision of the output relative to 1m.\n\
00070 The minimum value of prec is 0 (1 m accuracy) and the maximum value is\n\
00071 10 (0.1 nm accuracy, but then the last digits are unreliable).\n\
00072 \n\
00073 -h prints this help.\n";
00074 return retval;
00075 }
00076
00077
00078 std::string LatLonString(double lat, double lon, int prec, bool dms) {
00079 using namespace GeographicLib;
00080 if (dms)
00081 return
00082 DMS::Encode(lat, prec + 5, DMS::LATITUDE) + " " +
00083 DMS::Encode(lon, prec + 5, DMS::LONGITUDE);
00084 else {
00085 std::ostringstream os;
00086 os << std::fixed << std::setprecision(prec + 5)
00087 << lat << " " << lon;
00088 return os.str();
00089 }
00090 }
00091
00092 std::string AzimuthString(double azi, int prec, bool dms) {
00093 using namespace GeographicLib;
00094 if (dms)
00095 return DMS::Encode(azi, prec + 5, DMS::AZIMUTH);
00096 else {
00097 std::ostringstream os;
00098 os << std::fixed << std::setprecision(prec + 5)
00099 << azi;
00100 return os.str();
00101 }
00102 }
00103
00104 double ReadAzimuth(const std::string& s) {
00105 using namespace GeographicLib;
00106 DMS::flag ind;
00107 double azi = DMS::Decode(s, ind);
00108 if (!(azi >= -180 && azi <= 360))
00109 throw std::out_of_range("Azimuth " + s + " not in range [-180,360]");
00110 if (azi >= 180) azi -= 360;
00111 if (ind == DMS::LATITUDE)
00112 throw std::out_of_range("Azimuth " + s +
00113 " has a latitude hemisphere, N/S");
00114 return azi;
00115 }
00116
00117 int main(int argc, char* argv[]) {
00118 bool linecalc = false, inverse = false, international = false,
00119 dms = false, full = false;
00120 double lat1, lon1, azi1, lat2, lon2, azi2, s12;
00121 int prec = 3;
00122
00123 for (int m = 1; m < argc; ++m) {
00124 std::string arg = std::string(argv[m]);
00125 if (arg == "-i") {
00126 inverse = true;
00127 linecalc = false;
00128 } else if (arg == "-l") {
00129 inverse = false;
00130 linecalc = true;
00131 if (m + 3 >= argc) return usage(1);
00132 try {
00133 GeographicLib::DMS::DecodeLatLon(std::string(argv[m + 1]),
00134 std::string(argv[m + 2]),
00135 lat1, lon1);
00136 azi1 = ReadAzimuth(std::string(argv[m + 3]));
00137 m += 3;
00138 }
00139 catch (std::out_of_range& e) {
00140 std::cerr << "ERROR: " << e.what() << "\n";
00141 return usage(1);
00142 }
00143 } else if (arg == "-n")
00144 international = true;
00145 else if (arg == "-d")
00146 dms = true;
00147 else if (arg == "-f")
00148 full = true;
00149 else if (arg == "-p") {
00150 if (++m == argc) return usage(1);
00151 std::string a = std::string(argv[m]);
00152 std::istringstream str(a);
00153 if (!(str >> prec)) return usage(1);
00154 } else
00155 return usage(arg != "-h");
00156 }
00157
00158 const GeographicLib::Geodesic internat(6378388.0, 297.0);
00159 const GeographicLib::Geodesic& geod = international ? internat :
00160 GeographicLib::Geodesic::WGS84;
00161 GeographicLib::GeodesicLine l;
00162 if (linecalc)
00163 l = geod.Line(lat1, lon1, azi1);
00164
00165
00166
00167 prec = std::min(10, std::max(0, prec));
00168 std::cout << std::fixed << std::setprecision(prec);
00169 std::string s;
00170 int retval = 0;
00171 while (std::getline(std::cin, s)) {
00172 try {
00173 std::istringstream str(s);
00174 if (linecalc) {
00175 if (!(str >> s12))
00176 throw std::out_of_range("Incomplete input: " + s);
00177 l.Position(s12, lat2, lon2, azi2);
00178 if (full)
00179 std::cout << LatLonString(lat1, lon1, prec, dms) << " " <<
00180 AzimuthString(azi1, prec, dms) << " ";
00181 std::cout << LatLonString(lat2, lon2, prec, dms) << " " <<
00182 AzimuthString(azi2, prec, dms);
00183 if (full)
00184 std::cout << " " << s12;
00185 std::cout << "\n";
00186 } else if (inverse) {
00187 std::string slat1, slon1, slat2, slon2;
00188 if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
00189 throw std::out_of_range("Incomplete input: " + s);
00190 GeographicLib::DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00191 GeographicLib::DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
00192 geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2);
00193 if (full)
00194 std::cout << LatLonString(lat1, lon1, prec, dms) << " ";
00195 std::cout << AzimuthString(azi1, prec, dms) << " ";
00196 if (full)
00197 std::cout << LatLonString(lat2, lon2, prec, dms) << " ";
00198 std::cout << AzimuthString(azi2, prec, dms) << " " << s12 << "\n";
00199 } else {
00200 std::string slat1, slon1, sazi1;
00201 if (!(str >> slat1 >> slon1 >> sazi1 >> s12))
00202 throw std::out_of_range("Incomplete input: " + s);
00203 GeographicLib::DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
00204 azi1 = ReadAzimuth(sazi1);
00205 geod.Direct(lat1, lon1, azi1, s12, lat2, lon2, azi2);
00206 if (full)
00207 std::cout << LatLonString(lat1, lon1, prec, dms) << " " <<
00208 AzimuthString(azi1, prec, dms) << " ";
00209 std::cout << LatLonString(lat2, lon2, prec, dms) << " " <<
00210 AzimuthString(azi2, prec, dms);
00211 if (full)
00212 std::cout << " " << s12;
00213 std::cout << "\n";
00214 }
00215 }
00216 catch (std::out_of_range& e) {
00217
00218 std::cout << "ERROR: " << e.what() << "\n";
00219 retval = 1;
00220 }
00221 }
00222 return retval;
00223 }