GeographicLib  1.50.1
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-2019) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  *
9  * See the <a href="GeodSolve.1.html">man page</a> for usage information.
10  **********************************************************************/
11 
12 #include <iostream>
13 #include <string>
14 #include <sstream>
15 #include <fstream>
20 #include <GeographicLib/DMS.hpp>
22 
23 #if defined(_MSC_VER)
24 // Squelch warnings about constant conditional expressions and potentially
25 // uninitialized local variables
26 # pragma warning (disable: 4127 4701)
27 #endif
28 
29 #include "GeodSolve.usage"
30 
32 
33 std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep,
34  bool longfirst) {
35  using namespace GeographicLib;
36  std::string
37  latstr = dms ? DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) :
38  DMS::Encode(lat, prec + 5, DMS::NUMBER),
39  lonstr = dms ? DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
40  DMS::Encode(lon, prec + 5, DMS::NUMBER);
41  return
42  (longfirst ? lonstr : latstr) + " " + (longfirst ? latstr : lonstr);
43 }
44 
45 std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
46  using namespace GeographicLib;
47  return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
48  DMS::Encode(azi, prec + 5, DMS::NUMBER);
49 }
50 
51 std::string DistanceStrings(real s12, real a12,
52  bool full, bool arcmode, int prec, bool dms) {
53  using namespace GeographicLib;
54  std::string s;
55  if (full || !arcmode)
56  s += Utility::str(s12, prec);
57  if (full)
58  s += " ";
59  if (full || arcmode)
60  s += DMS::Encode(a12, prec + 5, dms ? DMS::NONE : DMS::NUMBER);
61  return s;
62 }
63 
64 real ReadDistance(const std::string& s, bool arcmode, bool fraction = false) {
65  using namespace GeographicLib;
66  return fraction ? Utility::fract<real>(s) :
67  (arcmode ? DMS::DecodeAngle(s) : Utility::val<real>(s));
68 }
69 
70 int main(int argc, const char* const argv[]) {
71  try {
72  using namespace GeographicLib;
73  enum { NONE = 0, LINE, DIRECT, INVERSE };
75  bool inverse = false, arcmode = false,
76  dms = false, full = false, exact = false, unroll = false,
77  longfirst = false, azi2back = false, fraction = false,
78  arcmodeline = false;
79  real
80  a = Constants::WGS84_a(),
81  f = Constants::WGS84_f();
82  real lat1, lon1, azi1, lat2, lon2, azi2, s12, m12, a12, M12, M21, S12,
83  mult = 1;
84  int linecalc = NONE, prec = 3;
85  std::string istring, ifile, ofile, cdelim;
86  char lsep = ';', dmssep = char(0);
87 
88  for (int m = 1; m < argc; ++m) {
89  std::string arg(argv[m]);
90  if (arg == "-i") {
91  inverse = true;
92  linecalc = NONE;
93  } else if (arg == "-a")
94  arcmode = !arcmode;
95  else if (arg == "-F")
96  fraction = true;
97  else if (arg == "-L" || arg == "-l") { // -l is DEPRECATED
98  inverse = false;
99  linecalc = LINE;
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, longfirst);
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 == "-D") {
112  inverse = false;
113  linecalc = DIRECT;
114  if (m + 4 >= argc) return usage(1, true);
115  try {
116  DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
117  lat1, lon1, longfirst);
118  azi1 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
119  s12 = ReadDistance(std::string(argv[m + 4]), arcmode);
120  arcmodeline = arcmode;
121  }
122  catch (const std::exception& e) {
123  std::cerr << "Error decoding arguments of -D: " << e.what() << "\n";
124  return 1;
125  }
126  m += 4;
127  } else if (arg == "-I") {
128  inverse = false;
129  linecalc = INVERSE;
130  if (m + 4 >= argc) return usage(1, true);
131  try {
132  DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
133  lat1, lon1, longfirst);
134  DMS::DecodeLatLon(std::string(argv[m + 3]), std::string(argv[m + 4]),
135  lat2, lon2, longfirst);
136  }
137  catch (const std::exception& e) {
138  std::cerr << "Error decoding arguments of -I: " << e.what() << "\n";
139  return 1;
140  }
141  m += 4;
142  } else if (arg == "-e") {
143  if (m + 2 >= argc) return usage(1, true);
144  try {
145  a = Utility::val<real>(std::string(argv[m + 1]));
146  f = Utility::fract<real>(std::string(argv[m + 2]));
147  }
148  catch (const std::exception& e) {
149  std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
150  return 1;
151  }
152  m += 2;
153  } else if (arg == "-u")
154  unroll = true;
155  else if (arg == "-d") {
156  dms = true;
157  dmssep = '\0';
158  } else if (arg == "-:") {
159  dms = true;
160  dmssep = ':';
161  } else if (arg == "-w")
162  longfirst = !longfirst;
163  else if (arg == "-b")
164  azi2back = true;
165  else if (arg == "-f")
166  full = true;
167  else if (arg == "-p") {
168  if (++m == argc) return usage(1, true);
169  try {
170  prec = Utility::val<int>(std::string(argv[m]));
171  }
172  catch (const std::exception&) {
173  std::cerr << "Precision " << argv[m] << " is not a number\n";
174  return 1;
175  }
176  } else if (arg == "-E")
177  exact = true;
178  else if (arg == "--input-string") {
179  if (++m == argc) return usage(1, true);
180  istring = argv[m];
181  } else if (arg == "--input-file") {
182  if (++m == argc) return usage(1, true);
183  ifile = argv[m];
184  } else if (arg == "--output-file") {
185  if (++m == argc) return usage(1, true);
186  ofile = argv[m];
187  } else if (arg == "--line-separator") {
188  if (++m == argc) return usage(1, true);
189  if (std::string(argv[m]).size() != 1) {
190  std::cerr << "Line separator must be a single character\n";
191  return 1;
192  }
193  lsep = argv[m][0];
194  } else if (arg == "--comment-delimiter") {
195  if (++m == argc) return usage(1, true);
196  cdelim = argv[m];
197  } else if (arg == "--version") {
198  std::cout << argv[0] << ": GeographicLib version "
199  << GEOGRAPHICLIB_VERSION_STRING << "\n";
200  return 0;
201  } else
202  return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
203  }
204 
205  if (!ifile.empty() && !istring.empty()) {
206  std::cerr << "Cannot specify --input-string and --input-file together\n";
207  return 1;
208  }
209  if (ifile == "-") ifile.clear();
210  std::ifstream infile;
211  std::istringstream instring;
212  if (!ifile.empty()) {
213  infile.open(ifile.c_str());
214  if (!infile.is_open()) {
215  std::cerr << "Cannot open " << ifile << " for reading\n";
216  return 1;
217  }
218  } else if (!istring.empty()) {
219  std::string::size_type m = 0;
220  while (true) {
221  m = istring.find(lsep, m);
222  if (m == std::string::npos)
223  break;
224  istring[m] = '\n';
225  }
226  instring.str(istring);
227  }
228  std::istream* input = !ifile.empty() ? &infile :
229  (!istring.empty() ? &instring : &std::cin);
230 
231  std::ofstream outfile;
232  if (ofile == "-") ofile.clear();
233  if (!ofile.empty()) {
234  outfile.open(ofile.c_str());
235  if (!outfile.is_open()) {
236  std::cerr << "Cannot open " << ofile << " for writing\n";
237  return 1;
238  }
239  }
240  std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
241 
242  // GeodesicExact mask values are the same as Geodesic
243  unsigned outmask = Geodesic::LATITUDE | Geodesic::LONGITUDE |
244  Geodesic::AZIMUTH; // basic output quantities
245  outmask |= inverse ? Geodesic::DISTANCE : // distance-related flags
247  // longitude unrolling
248  outmask |= unroll ? Geodesic::LONG_UNROLL : Geodesic::NONE;
249  // full output -- don't use Geodesic::ALL since this includes DISTANCE_IN
250  outmask |= full ? (Geodesic::DISTANCE | Geodesic::REDUCEDLENGTH |
253 
254  const Geodesic geods(a, f);
255  const GeodesicExact geode(a, f);
256  GeodesicLine ls;
258  if (linecalc) {
259  if (linecalc == LINE) fraction = false;
260  if (exact) {
261  le = linecalc == DIRECT ?
262  geode.GenDirectLine(lat1, lon1, azi1, arcmodeline, s12, outmask) :
263  linecalc == INVERSE ?
264  geode.InverseLine(lat1, lon1, lat2, lon2, outmask) :
265  // linecalc == LINE
266  geode.Line(lat1, lon1, azi1, outmask);
267  mult = fraction ? le.GenDistance(arcmode) : 1;
268  if (linecalc == INVERSE) azi1 = le.Azimuth();
269  } else {
270  ls = linecalc == DIRECT ?
271  geods.GenDirectLine(lat1, lon1, azi1, arcmodeline, s12, outmask) :
272  linecalc == INVERSE ?
273  geods.InverseLine(lat1, lon1, lat2, lon2, outmask) :
274  // linecalc == LINE
275  geods.Line(lat1, lon1, azi1, outmask);
276  mult = fraction ? ls.GenDistance(arcmode) : 1;
277  if (linecalc == INVERSE) azi1 = ls.Azimuth();
278  }
279  }
280 
281  // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
282  // 10^-11 sec (= 0.3 nm).
283  prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
284  std::string s, eol, slat1, slon1, slat2, slon2, sazi1, ss12, strc;
285  std::istringstream str;
286  int retval = 0;
287  while (std::getline(*input, s)) {
288  try {
289  eol = "\n";
290  if (!cdelim.empty()) {
291  std::string::size_type m = s.find(cdelim);
292  if (m != std::string::npos) {
293  eol = " " + s.substr(m) + "\n";
294  s = s.substr(0, m);
295  }
296  }
297  str.clear(); str.str(s);
298  if (inverse) {
299  if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
300  throw GeographicErr("Incomplete input: " + s);
301  if (str >> strc)
302  throw GeographicErr("Extraneous input: " + strc);
303  DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
304  DMS::DecodeLatLon(slat2, slon2, lat2, lon2, longfirst);
305  a12 = exact ?
306  geode.GenInverse(lat1, lon1, lat2, lon2, outmask,
307  s12, azi1, azi2, m12, M12, M21, S12) :
308  geods.GenInverse(lat1, lon1, lat2, lon2, outmask,
309  s12, azi1, azi2, m12, M12, M21, S12);
310  if (full) {
311  if (unroll) {
312  real e;
313  lon2 = lon1 + Math::AngDiff(lon1, lon2, e);
314  lon2 += e;
315  } else {
316  lon1 = Math::AngNormalize(lon1);
317  lon2 = Math::AngNormalize(lon2);
318  }
319  *output << LatLonString(lat1, lon1, prec, dms, dmssep, longfirst)
320  << " ";
321  }
322  *output << AzimuthString(azi1, prec, dms, dmssep) << " ";
323  if (full)
324  *output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
325  << " ";
326  if (azi2back)
327  azi2 += azi2 >= 0 ? -180 : 180;
328  *output << AzimuthString(azi2, prec, dms, dmssep) << " "
329  << DistanceStrings(s12, a12, full, arcmode, prec, dms);
330  if (full)
331  *output << " " << Utility::str(m12, prec)
332  << " " << Utility::str(M12, prec+7)
333  << " " << Utility::str(M21, prec+7)
334  << " " << Utility::str(S12, std::max(prec-7, 0));
335  *output << eol;
336  } else {
337  if (linecalc) {
338  if (!(str >> ss12))
339  throw GeographicErr("Incomplete input: " + s);
340  if (str >> strc)
341  throw GeographicErr("Extraneous input: " + strc);
342  // In fraction mode input is read as a distance
343  s12 = ReadDistance(ss12, !fraction && arcmode, fraction) * mult;
344  a12 = exact ?
345  le.GenPosition(arcmode, s12, outmask,
346  lat2, lon2, azi2, s12, m12, M12, M21, S12) :
347  ls.GenPosition(arcmode, s12, outmask,
348  lat2, lon2, azi2, s12, m12, M12, M21, S12);
349  } else {
350  if (!(str >> slat1 >> slon1 >> sazi1 >> ss12))
351  throw GeographicErr("Incomplete input: " + s);
352  if (str >> strc)
353  throw GeographicErr("Extraneous input: " + strc);
354  DMS::DecodeLatLon(slat1, slon1, lat1, lon1, longfirst);
355  azi1 = DMS::DecodeAzimuth(sazi1);
356  s12 = ReadDistance(ss12, arcmode);
357  a12 = exact ?
358  geode.GenDirect(lat1, lon1, azi1, arcmode, s12, outmask,
359  lat2, lon2, azi2, s12, m12, M12, M21, S12) :
360  geods.GenDirect(lat1, lon1, azi1, arcmode, s12, outmask,
361  lat2, lon2, azi2, s12, m12, M12, M21, S12);
362  }
363  if (full)
364  *output
365  << LatLonString(lat1, unroll ? lon1 : Math::AngNormalize(lon1),
366  prec, dms, dmssep, longfirst)
367  << " " << AzimuthString(azi1, prec, dms, dmssep) << " ";
368  if (azi2back)
369  azi2 += azi2 >= 0 ? -180 : 180;
370  *output << LatLonString(lat2, lon2, prec, dms, dmssep, longfirst)
371  << " " << AzimuthString(azi2, prec, dms, dmssep);
372  if (full)
373  *output << " "
374  << DistanceStrings(s12, a12, full, arcmode, prec, dms)
375  << " " << Utility::str(m12, prec)
376  << " " << Utility::str(M12, prec+7)
377  << " " << Utility::str(M21, prec+7)
378  << " " << Utility::str(S12, std::max(prec-7, 0));
379  *output << eol;
380  }
381  }
382  catch (const std::exception& e) {
383  // Write error message cout so output lines match input lines
384  *output << "ERROR: " << e.what() << "\n";
385  retval = 1;
386  }
387  }
388  return retval;
389  }
390  catch (const std::exception& e) {
391  std::cerr << "Caught exception: " << e.what() << "\n";
392  return 1;
393  }
394  catch (...) {
395  std::cerr << "Caught unknown exception\n";
396  return 1;
397  }
398 }
real
GeographicLib::Math::real real
Definition: GeodSolve.cpp:31
GeographicLib::Math::AngNormalize
static T AngNormalize(T x)
Definition: Math.hpp:383
GeographicLib::Geodesic::LATITUDE
Definition: Geodesic.hpp:274
GeographicLib::GeodesicExact
Exact geodesic calculations.
Definition: GeodesicExact.hpp:80
GeographicLib::Utility::str
static std::string str(T x, int p=-1)
Definition: Utility.hpp:276
GeographicLib
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
GeographicLib::Geodesic::AZIMUTH
Definition: Geodesic.hpp:286
GeographicLib::GeodesicLine
A geodesic line.
Definition: GeodesicLine.hpp:71
AzimuthString
std::string AzimuthString(real azi, int prec, bool dms, char dmssep)
Definition: GeodSolve.cpp:45
GeographicLib::DMS::DecodeLatLon
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool longfirst=false)
Definition: DMS.cpp:256
GeographicLib::DMS::DecodeAngle
static Math::real DecodeAngle(const std::string &angstr)
Definition: DMS.cpp:285
GeographicLib::GeodesicLineExact::GenPosition
Math::real GenPosition(bool arcmode, real s12_a12, unsigned outmask, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Definition: GeodesicLineExact.cpp:137
GeographicLib::GeodesicExact::GenDirectLine
GeodesicLineExact GenDirectLine(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned caps=ALL) const
Definition: GeodesicExact.cpp:139
GeographicLib::Geodesic::LONG_UNROLL
Definition: Geodesic.hpp:317
main
int main(int argc, const char *const argv[])
Definition: GeodSolve.cpp:70
GeographicLib::Geodesic::GEODESICSCALE
Definition: Geodesic.hpp:307
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition: Constants.hpp:390
GeographicLib::DMS::NONE
Definition: DMS.hpp:46
GeographicLib::Geodesic::LONGITUDE
Definition: Geodesic.hpp:279
GeographicLib::Math::real
double real
Definition: Math.hpp:121
LatLonString
std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep, bool longfirst)
Definition: GeodSolve.cpp:33
GeodesicExact.hpp
Header for GeographicLib::GeodesicExact class.
GeodesicLineExact.hpp
Header for GeographicLib::GeodesicLineExact class.
GeographicLib::DMS::NUMBER
Definition: DMS.hpp:67
GeographicLib::Math::extra_digits
static int extra_digits()
Definition: Math.cpp:52
GeographicLib::GeodesicLine::GenDistance
Math::real GenDistance(bool arcmode) const
Definition: GeodesicLine.hpp:684
DistanceStrings
std::string DistanceStrings(real s12, real a12, bool full, bool arcmode, int prec, bool dms)
Definition: GeodSolve.cpp:51
GeographicLib::DMS::Encode
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
Definition: DMS.cpp:303
GeographicLib::GeodesicLine::Azimuth
Math::real Azimuth() const
Definition: GeodesicLine.hpp:606
GeodesicLine.hpp
Header for GeographicLib::GeodesicLine class.
GeographicLib::Math::AngDiff
static T AngDiff(T x, T y, T &e)
Definition: Math.hpp:414
GeographicLib::GeodesicLineExact::GenDistance
Math::real GenDistance(bool arcmode) const
Definition: GeodesicLineExact.hpp:649
GeographicLib::Geodesic::DISTANCE
Definition: Geodesic.hpp:291
GeographicLib::GeodesicLineExact::Azimuth
Math::real Azimuth() const
Definition: GeodesicLineExact.hpp:569
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::Geodesic::NONE
Definition: Geodesic.hpp:268
GeographicLib::DMS::LONGITUDE
Definition: DMS.hpp:56
GeographicLib::GeodesicExact::InverseLine
GeodesicLineExact InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps=ALL) const
Definition: GeodesicExact.cpp:538
GeographicLib::DMS::LATITUDE
Definition: DMS.hpp:51
GeographicLib::Constants::WGS84_a
static T WGS84_a()
Definition: Constants.hpp:160
GeographicLib::GeodesicLineExact
An exact geodesic line.
Definition: GeodesicLineExact.hpp:35
GeographicLib::GeodesicLine::GenPosition
Math::real GenPosition(bool arcmode, real s12_a12, unsigned outmask, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Definition: GeodesicLine.cpp:136
GeographicLib::Geodesic::AREA
Definition: Geodesic.hpp:312
GeographicLib::Geodesic::REDUCEDLENGTH
Definition: Geodesic.hpp:302
GeographicLib::Constants::WGS84_f
static T WGS84_f()
Definition: Constants.hpp:170
GeographicLib::GeodesicExact::GenDirect
Math::real GenDirect(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned outmask, real &lat2, real &lon2, real &azi2, real &s12, real &m12, real &M12, real &M21, real &S12) const
Definition: GeodesicExact.cpp:124
GeographicLib::DMS::AZIMUTH
Definition: DMS.hpp:62
GeographicLib::DMS::DecodeAzimuth
static Math::real DecodeAzimuth(const std::string &azistr)
Definition: DMS.cpp:294
GeographicLib::GeodesicExact::Line
GeodesicLineExact Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Definition: GeodesicExact.cpp:119
GeographicLib::Utility::set_digits
static int set_digits(int ndigits=0)
Definition: Utility.cpp:48
DMS.hpp
Header for GeographicLib::DMS class.
GeographicLib::Geodesic
Geodesic calculations
Definition: Geodesic.hpp:172
ReadDistance
real ReadDistance(const std::string &s, bool arcmode, bool fraction=false)
Definition: GeodSolve.cpp:64
Geodesic.hpp
Header for GeographicLib::Geodesic class.
GeographicLib::Geodesic::DISTANCE_IN
Definition: Geodesic.hpp:297