GeographicLib  1.43
RhumbSolve.cpp
Go to the documentation of this file.
1 /**
2  * \file RhumbSolve.cpp
3  * \brief Command line utility for rhumb line calculations
4  *
5  * Copyright (c) Charles Karney (2014) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * http://geographiclib.sourceforge.net/
8  *
9  * See the <a href="RhumbSolve.1.html">man page</a> for usage information.
10  **********************************************************************/
11 
12 #include <iostream>
13 #include <sstream>
14 #include <string>
15 #include <sstream>
16 #include <fstream>
17 #include <cmath>
18 #include <limits>
19 #include <GeographicLib/Rhumb.hpp>
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 "RhumbSolve.usage"
30 
31 using namespace GeographicLib;
32 typedef Math::real real;
33 
34 std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep) {
35  return dms ?
36  DMS::Encode(lat, prec + 5, DMS::LATITUDE, dmssep) + " " +
37  DMS::Encode(lon, prec + 5, DMS::LONGITUDE, dmssep) :
38  DMS::Encode(lat, prec + 5, DMS::NUMBER) + " " +
39  DMS::Encode(lon, prec + 5, DMS::NUMBER);
40 }
41 
42 std::string AzimuthString(real azi, int prec, bool dms, char dmssep) {
43  return dms ? DMS::Encode(azi, prec + 5, DMS::AZIMUTH, dmssep) :
44  DMS::Encode(azi >= 180 ? azi - 360 : azi, prec + 5, DMS::NUMBER);
45 }
46 
47 int main(int argc, char* argv[]) {
48  try {
50  bool linecalc = false, inverse = false, dms = false, exact = true;
51  real
52  a = Constants::WGS84_a(),
53  f = Constants::WGS84_f();
54  real lat1, lon1, azi12 = Math::NaN(), lat2, lon2, s12, S12;
55  int prec = 3;
56  std::string istring, ifile, ofile, cdelim;
57  char lsep = ';', dmssep = char(0);
58 
59  for (int m = 1; m < argc; ++m) {
60  std::string arg(argv[m]);
61  if (arg == "-i") {
62  inverse = true;
63  linecalc = false;
64  } else if (arg == "-l") {
65  inverse = false;
66  linecalc = true;
67  if (m + 3 >= argc) return usage(1, true);
68  try {
69  DMS::DecodeLatLon(std::string(argv[m + 1]), std::string(argv[m + 2]),
70  lat1, lon1);
71  azi12 = DMS::DecodeAzimuth(std::string(argv[m + 3]));
72  }
73  catch (const std::exception& e) {
74  std::cerr << "Error decoding arguments of -l: " << e.what() << "\n";
75  return 1;
76  }
77  m += 3;
78  } else if (arg == "-e") {
79  if (m + 2 >= argc) return usage(1, true);
80  try {
81  a = Utility::num<real>(std::string(argv[m + 1]));
82  f = Utility::fract<real>(std::string(argv[m + 2]));
83  }
84  catch (const std::exception& e) {
85  std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
86  return 1;
87  }
88  m += 2;
89  }
90  else if (arg == "-d") {
91  dms = true;
92  dmssep = '\0';
93  } else if (arg == "-:") {
94  dms = true;
95  dmssep = ':';
96  } else if (arg == "-p") {
97  if (++m == argc) return usage(1, true);
98  try {
99  prec = Utility::num<int>(std::string(argv[m]));
100  }
101  catch (const std::exception&) {
102  std::cerr << "Precision " << argv[m] << " is not a number\n";
103  return 1;
104  }
105  } else if (arg == "-s")
106  exact = false;
107  else if (arg == "--input-string") {
108  if (++m == argc) return usage(1, true);
109  istring = argv[m];
110  } else if (arg == "--input-file") {
111  if (++m == argc) return usage(1, true);
112  ifile = argv[m];
113  } else if (arg == "--output-file") {
114  if (++m == argc) return usage(1, true);
115  ofile = argv[m];
116  } else if (arg == "--line-separator") {
117  if (++m == argc) return usage(1, true);
118  if (std::string(argv[m]).size() != 1) {
119  std::cerr << "Line separator must be a single character\n";
120  return 1;
121  }
122  lsep = argv[m][0];
123  } else if (arg == "--comment-delimiter") {
124  if (++m == argc) return usage(1, true);
125  cdelim = argv[m];
126  } else if (arg == "--version") {
127  std::cout << argv[0] << ": GeographicLib version "
128  << GEOGRAPHICLIB_VERSION_STRING << "\n";
129  return 0;
130  } else
131  return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
132  }
133 
134  if (!ifile.empty() && !istring.empty()) {
135  std::cerr << "Cannot specify --input-string and --input-file together\n";
136  return 1;
137  }
138  if (ifile == "-") ifile.clear();
139  std::ifstream infile;
140  std::istringstream instring;
141  if (!ifile.empty()) {
142  infile.open(ifile.c_str());
143  if (!infile.is_open()) {
144  std::cerr << "Cannot open " << ifile << " for reading\n";
145  return 1;
146  }
147  } else if (!istring.empty()) {
148  std::string::size_type m = 0;
149  while (true) {
150  m = istring.find(lsep, m);
151  if (m == std::string::npos)
152  break;
153  istring[m] = '\n';
154  }
155  instring.str(istring);
156  }
157  std::istream* input = !ifile.empty() ? &infile :
158  (!istring.empty() ? &instring : &std::cin);
159 
160  std::ofstream outfile;
161  if (ofile == "-") ofile.clear();
162  if (!ofile.empty()) {
163  outfile.open(ofile.c_str());
164  if (!outfile.is_open()) {
165  std::cerr << "Cannot open " << ofile << " for writing\n";
166  return 1;
167  }
168  }
169  std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
170 
171  const Rhumb rh(a, f, exact);
172  const RhumbLine rhl(linecalc ? rh.Line(lat1, lon1, azi12) :
173  rh.Line(0, 0, 90));
174  // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
175  // 10^-11 sec (= 0.3 nm).
176  prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
177  int retval = 0;
178  std::string s;
179  while (std::getline(*input, s)) {
180  try {
181  std::string eol("\n");
182  if (!cdelim.empty()) {
183  std::string::size_type m = s.find(cdelim);
184  if (m != std::string::npos) {
185  eol = " " + s.substr(m) + "\n";
186  s = s.substr(0, m);
187  }
188  }
189  std::istringstream str(s);
190  if (linecalc) {
191  if (!(str >> s12))
192  throw GeographicErr("Incomplete input: " + s);
193  std::string strc;
194  if (str >> strc)
195  throw GeographicErr("Extraneous input: " + strc);
196  rhl.Position(s12, lat2, lon2, S12);
197  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
198  << Utility::str(S12, std::max(prec-7, 0)) << eol;
199  } else if (inverse) {
200  std::string slat1, slon1, slat2, slon2;
201  if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
202  throw GeographicErr("Incomplete input: " + s);
203  std::string strc;
204  if (str >> strc)
205  throw GeographicErr("Extraneous input: " + strc);
206  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
207  DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
208  rh.Inverse(lat1, lon1, lat2, lon2, s12, azi12, S12);
209  *output << AzimuthString(azi12, prec, dms, dmssep) << " "
210  << Utility::str(s12, prec) << " "
211  << Utility::str(S12, std::max(prec-7, 0)) << eol;
212  } else { // direct
213  std::string slat1, slon1, sazi;
214  if (!(str >> slat1 >> slon1 >> sazi >> s12))
215  throw GeographicErr("Incomplete input: " + s);
216  std::string strc;
217  if (str >> strc)
218  throw GeographicErr("Extraneous input: " + strc);
219  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
220  azi12 = DMS::DecodeAzimuth(sazi);
221  rh.Direct(lat1, lon1, azi12, s12, lat2, lon2, S12);
222  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
223  << Utility::str(S12, std::max(prec-7, 0)) << eol;
224  }
225  }
226  catch (const std::exception& e) {
227  // Write error message cout so output lines match input lines
228  *output << "ERROR: " << e.what() << "\n";
229  retval = 1;
230  }
231  }
232  return retval;
233  }
234  catch (const std::exception& e) {
235  std::cerr << "Caught exception: " << e.what() << "\n";
236  return 1;
237  }
238  catch (...) {
239  std::cerr << "Caught unknown exception\n";
240  return 1;
241  }
242 }
static T NaN()
Definition: Math.hpp:629
void Inverse(real lat1, real lon1, real lat2, real lon2, real &s12, real &azi12, real &S12) const
Definition: Rhumb.hpp:347
int main(int argc, char *argv[])
Definition: RhumbSolve.cpp:47
GeographicLib::Math::real real
Definition: GeodSolve.cpp:32
Header for GeographicLib::Utility class.
Header for GeographicLib::Rhumb and GeographicLib::RhumbLine classes.
Math::real real
Definition: RhumbSolve.cpp:32
static int extra_digits()
Definition: Math.hpp:185
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
Definition: DMS.cpp:298
static Math::real DecodeAzimuth(const std::string &azistr)
Definition: DMS.cpp:287
RhumbLine Line(real lat1, real lon1, real azi12) const
Definition: Rhumb.cpp:167
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool swaplatlong=false)
Definition: DMS.cpp:246
std::string LatLonString(real lat, real lon, int prec, bool dms, char dmssep)
Definition: RhumbSolve.cpp:34
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static std::string str(T x, int p=-1)
Definition: Utility.hpp:276
static int set_digits(int ndigits=0)
Definition: Utility.cpp:48
Exception handling for GeographicLib.
Definition: Constants.hpp:382
std::string AzimuthString(real azi, int prec, bool dms, char dmssep)
Definition: RhumbSolve.cpp:42
Solve of the direct and inverse rhumb problems.
Definition: Rhumb.hpp:66
Find a sequence of points on a single rhumb line.
Definition: Rhumb.hpp:447
void Direct(real lat1, real lon1, real azi12, real s12, real &lat2, real &lon2, real &S12) const
Definition: Rhumb.hpp:276
Header for GeographicLib::DMS class.