GeographicLib  1.37
GeodSolve.cpp
Go to the documentation of this file.
1 /**
2  * \file GeodSolve.cpp
3  * \brief Command line utility for geodesic calculations
4  *
5  * Copyright (c) Charles Karney (2009-2012) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * http://geographiclib.sourceforge.net/
8  *
9  * Compile and link with
10  * g++ -g -O3 -I../include -I../man -o GeodSolve \
11  * GeodSolve.cpp \
12  * ../src/DMS.cpp \
13  * ../src/Geodesic.cpp \
14  * ../src/GeodesicLine.cpp
15  *
16  * See the <a href="GeodSolve.1.html">man page</a> for usage
17  * information.
18  **********************************************************************/
19 
20 #include <iostream>
21 #include <sstream>
22 #include <string>
23 #include <sstream>
24 #include <fstream>
29 #include <GeographicLib/DMS.hpp>
31 
32 #if defined(_MSC_VER)
33 // Squelch warnings about constant conditional expressions and potentially
34 // uninitialized local variables
35 # pragma warning (disable: 4127 4701)
36 #endif
37 
38 #include "GeodSolve.usage"
39 
41 
42 std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep) {
43  using namespace GeographicLib;
44  return dms ?
45  DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) + " " +
46  DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
47  DMS::Encode(lat, prec + 5, DMS::NUMBER) + " " +
48  DMS::Encode(lon, prec + 5, DMS::NUMBER);
49 }
50 
51 std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
52  using namespace GeographicLib;
53  return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
54  DMS::Encode(azi >= 180 ? azi - 360 : azi, prec + 5, DMS::NUMBER);
55 }
56 
57 std::string DistanceStrings(real s12, real a12,
58  bool full, bool arcmode, int prec, bool dms) {
59  using namespace GeographicLib;
60  std::string s;
61  if (full || !arcmode)
62  s += Utility::str(s12, prec);
63  if (full)
64  s += " ";
65  if (full || arcmode)
66  s += DMS::Encode(a12, prec + 5, dms ? DMS::NONE : DMS::NUMBER);
67  return s;
68 }
69 
70 real ReadDistance(const std::string& s, bool arcmode) {
71  using namespace GeographicLib;
72  return arcmode ? DMS::DecodeAngle(s) : Utility::num<real>(s);
73 }
74 
75 int main(int argc, char* argv[]) {
76  try {
77  using namespace GeographicLib;
79  bool linecalc = false, inverse = false, arcmode = false,
80  dms = false, full = false, exact = false;
81  real
82  a = Constants::WGS84_a(),
83  f = Constants::WGS84_f();
84  real lat1, lon1, azi1, lat2, lon2, azi2, s12, m12, a12, M12, M21, S12;
85  real azi2sense = 0;
86  int prec = 3;
87  std::string istring, ifile, ofile, cdelim;
88  char lsep = ';', dmssep = char(0);
89 
90  for (int m = 1; m < argc; ++m) {
91  std::string arg(argv[m]);
92  if (arg == "-i") {
93  inverse = true;
94  linecalc = false;
95  } else if (arg == "-a")
96  arcmode = true;
97  else if (arg == "-l") {
98  inverse = false;
99  linecalc = true;
100  if (m + 3 >= argc) return usage(1, true);
101  try {
102  DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
103  lat1, lon1);
104  azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
105  }
106  catch (const std::exception& e) {
107  std::cerr << "Error decoding arguments of -l: " << e.what() << "\n";
108  return 1;
109  }
110  m += 3;
111  } else if (arg == "-e") {
112  if (m + 2 >= argc) return usage(1, true);
113  try {
114  a = Utility::num<real>(std::string(argv[m + 1]));
115  f = Utility::fract<real>(std::string(argv[m + 2]));
116  }
117  catch (const std::exception& e) {
118  std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
119  return 1;
120  }
121  m += 2;
122  }
123  else if (arg == "-d") {
124  dms = true;
125  dmssep = '\0';
126  } else if (arg == "-:") {
127  dms = true;
128  dmssep = ':';
129  } else if (arg == "-b")
130  azi2sense = 180;
131  else if (arg == "-f")
132  full = true;
133  else if (arg == "-p") {
134  if (++m == argc) return usage(1, true);
135  try {
136  prec = Utility::num<int>(std::string(argv[m]));
137  }
138  catch (const std::exception&) {
139  std::cerr << "Precision " << argv[m] << " is not a number\n";
140  return 1;
141  }
142  } else if (arg == "-E")
143  exact = true;
144  else if (arg == "--input-string") {
145  if (++m == argc) return usage(1, true);
146  istring = argv[m];
147  } else if (arg == "--input-file") {
148  if (++m == argc) return usage(1, true);
149  ifile = argv[m];
150  } else if (arg == "--output-file") {
151  if (++m == argc) return usage(1, true);
152  ofile = argv[m];
153  } else if (arg == "--line-separator") {
154  if (++m == argc) return usage(1, true);
155  if (std::string(argv[m]).size() != 1) {
156  std::cerr << "Line separator must be a single character\n";
157  return 1;
158  }
159  lsep = argv[m][0];
160  } else if (arg == "--comment-delimiter") {
161  if (++m == argc) return usage(1, true);
162  cdelim = argv[m];
163  } else if (arg == "--version") {
164  std::cout
165  << argv[0] << ": GeographicLib version "
166  << GEOGRAPHICLIB_VERSION_STRING << "\n";
167  return 0;
168  } else
169  return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
170  }
171 
172  if (!ifile.empty() && !istring.empty()) {
173  std::cerr << "Cannot specify --input-string and --input-file together\n";
174  return 1;
175  }
176  if (ifile == "-") ifile.clear();
177  std::ifstream infile;
178  std::istringstream instring;
179  if (!ifile.empty()) {
180  infile.open(ifile.c_str());
181  if (!infile.is_open()) {
182  std::cerr << "Cannot open " << ifile << " for reading\n";
183  return 1;
184  }
185  } else if (!istring.empty()) {
186  std::string::size_type m = 0;
187  while (true) {
188  m = istring.find(lsep, m);
189  if (m == std::string::npos)
190  break;
191  istring[m] = '\n';
192  }
193  instring.str(istring);
194  }
195  std::istream* input = !ifile.empty() ? &infile :
196  (!istring.empty() ? &instring : &std::cin);
197 
198  std::ofstream outfile;
199  if (ofile == "-") ofile.clear();
200  if (!ofile.empty()) {
201  outfile.open(ofile.c_str());
202  if (!outfile.is_open()) {
203  std::cerr << "Cannot open " << ofile << " for writing\n";
204  return 1;
205  }
206  }
207  std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
208 
209  const Geodesic geod(a, f);
210  const GeodesicExact geode(a, f);
211  GeodesicLine l;
213  if (linecalc) {
214  if (exact)
215  le = geode.Line(lat1, lon1, azi1);
216  else
217  l = geod.Line(lat1, lon1, azi1);
218  }
219 
220  // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
221  // 10^-11 sec (= 0.3 nm).
222  prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
223  std::string s;
224  int retval = 0;
225  while (std::getline(*input, s)) {
226  try {
227  std::string eol("\n");
228  if (!cdelim.empty()) {
229  std::string::size_type m = s.find(cdelim);
230  if (m != std::string::npos) {
231  eol = " " + s.substr(m) + "\n";
232  s = s.substr(0, m);
233  }
234  }
235  std::istringstream str(s);
236  if (inverse) {
237  std::string slat1, slon1, slat2, slon2;
238  if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
239  throw GeographicErr("Incomplete input: " + s);
240  std::string strc;
241  if (str >> strc)
242  throw GeographicErr("Extraneous input: " + strc);
243  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
244  DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
245  a12 = exact ?
246  geode.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2,
247  m12, M12, M21, S12) :
248  geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2,
249  m12, M12, M21, S12);
250  if (full)
251  *output << LatLonString(lat1, lon1, prec, dms, dmssep) << " ";
252  *output << AzimuthString(azi1, prec, dms, dmssep) << " ";
253  if (full)
254  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " ";
255  *output << AzimuthString(azi2 + azi2sense, prec, dms, dmssep) << " "
256  << DistanceStrings(s12, a12, full, arcmode, prec, dms);
257  if (full)
258  *output << " " << Utility::str(m12, prec)
259  << " " << Utility::str(M12, prec+7)
260  << " " << Utility::str(M21, prec+7)
261  << " " << Utility::str(S12, std::max(prec-7, 0));
262  *output << eol;
263  } else {
264  if (linecalc) {
265  std::string ss12;
266  if (!(str >> ss12))
267  throw GeographicErr("Incomplete input: " + s);
268  std::string strc;
269  if (str >> strc)
270  throw GeographicErr("Extraneous input: " + strc);
271  s12 = ReadDistance(ss12, arcmode);
272  if (arcmode)
273  exact ?
274  le.ArcPosition(s12, lat2, lon2, azi2, a12, m12, M12, M21, S12) :
275  l.ArcPosition(s12, lat2, lon2, azi2, a12, m12, M12, M21, S12);
276  else
277  a12 = exact ?
278  le.Position(s12, lat2, lon2, azi2, m12, M12, M21, S12) :
279  l.Position(s12, lat2, lon2, azi2, m12, M12, M21, S12);
280  } else {
281  std::string slat1, slon1, sazi1, ss12;
282  if (!(str >> slat1 >> slon1 >> sazi1 >> ss12))
283  throw GeographicErr("Incomplete input: " + s);
284  std::string strc;
285  if (str >> strc)
286  throw GeographicErr("Extraneous input: " + strc);
287  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
288  azi1 = DMS::DecodeAzimuth(sazi1);
289  s12 = ReadDistance(ss12, arcmode);
290  if (arcmode)
291  exact ?
292  geode.ArcDirect(lat1, lon1, azi1, s12, lat2, lon2, azi2, a12,
293  m12, M12, M21, S12) :
294  geod.ArcDirect(lat1, lon1, azi1, s12, lat2, lon2, azi2, a12,
295  m12, M12, M21, S12);
296  else
297  a12 = exact ?
298  geode.Direct(lat1, lon1, azi1, s12, lat2, lon2, azi2,
299  m12, M12, M21, S12) :
300  geod.Direct(lat1, lon1, azi1, s12, lat2, lon2, azi2,
301  m12, M12, M21, S12);
302  }
303  if (arcmode)
304  std::swap(s12, a12);
305  if (full)
306  *output << LatLonString(lat1, lon1, prec, dms, dmssep) << " "
307  << AzimuthString(azi1, prec, dms, dmssep) << " ";
308  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
309  << AzimuthString(azi2 + azi2sense, prec, dms, dmssep);
310  if (full)
311  *output << " "
312  << DistanceStrings(s12, a12, full, arcmode, prec, dms)
313  << " " << Utility::str(m12, prec)
314  << " " << Utility::str(M12, prec+7)
315  << " " << Utility::str(M21, prec+7)
316  << " " << Utility::str(S12, std::max(prec-7, 0));
317  *output << eol;
318  }
319  }
320  catch (const std::exception& e) {
321  // Write error message cout so output lines match input lines
322  *output << "ERROR: " << e.what() << "\n";
323  retval = 1;
324  }
325  }
326  return retval;
327  }
328  catch (const std::exception& e) {
329  std::cerr << "Caught exception: " << e.what() << "\n";
330  return 1;
331  }
332  catch (...) {
333  std::cerr << "Caught unknown exception\n";
334  return 1;
335  }
336 }
void ArcDirect(real lat1, real lon1, real azi1, real a12, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Header for GeographicLib::GeodesicLine class.
static Math::real DecodeAngle(const std::string &angstr)
Definition: DMS.cpp:245
Math::real Position(real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Math::real Direct(real lat1, real lon1, real azi1, real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Definition: Geodesic.hpp:386
GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Definition: Geodesic.cpp:119
GeographicLib::Math::real real
Definition: GeodSolve.cpp:40
Header for GeographicLib::Utility class.
Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real &s12, real &azi1, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Definition: Geodesic.hpp:677
Math::real Position(real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Math::real Direct(real lat1, real lon1, real azi1, real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
real ReadDistance(const std::string &s, bool arcmode)
Definition: GeodSolve.cpp:70
static int extra_digits()
Definition: Math.hpp:184
Header for GeographicLib::Geodesic class.
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
Definition: DMS.cpp:265
static Math::real DecodeAzimuth(const std::string &azistr)
Definition: DMS.cpp:254
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool swaplatlong=false)
Definition: DMS.cpp:213
GeodesicLineExact Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Header for GeographicLib::GeodesicLineExact class.
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static std::string str(T x, int p=-1)
Definition: Utility.hpp:266
std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep)
Definition: GeodSolve.cpp:42
static int set_digits(int ndigits=0)
Definition: Utility.cpp:48
Exact geodesic calculations.
Header for GeographicLib::GeodesicExact class.
void ArcDirect(real lat1, real lon1, real azi1, real a12, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Definition: Geodesic.hpp:499
Exception handling for GeographicLib.
Definition: Constants.hpp:362
std::string AzimuthString(real azi, int prec, bool dms, char dmssep)
Definition: GeodSolve.cpp:51
int main(int argc, char *argv[])
Definition: GeodSolve.cpp:75
void ArcPosition(real a12, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real &s12, real &azi1, real &azi2, real &m12, real &M12, real &M21, real &S12) const
std::string DistanceStrings(real s12, real a12, bool full, bool arcmode, int prec, bool dms)
Definition: GeodSolve.cpp:57
void ArcPosition(real a12, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Geodesic calculations
Definition: Geodesic.hpp:172
Header for GeographicLib::DMS class.