GeographicLib  1.40
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
128  << argv[0] << ": GeographicLib version "
129  << GEOGRAPHICLIB_VERSION_STRING << "\n";
130  return 0;
131  } else
132  return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
133  }
134 
135  if (!ifile.empty() && !istring.empty()) {
136  std::cerr << "Cannot specify --input-string and --input-file together\n";
137  return 1;
138  }
139  if (ifile == "-") ifile.clear();
140  std::ifstream infile;
141  std::istringstream instring;
142  if (!ifile.empty()) {
143  infile.open(ifile.c_str());
144  if (!infile.is_open()) {
145  std::cerr << "Cannot open " << ifile << " for reading\n";
146  return 1;
147  }
148  } else if (!istring.empty()) {
149  std::string::size_type m = 0;
150  while (true) {
151  m = istring.find(lsep, m);
152  if (m == std::string::npos)
153  break;
154  istring[m] = '\n';
155  }
156  instring.str(istring);
157  }
158  std::istream* input = !ifile.empty() ? &infile :
159  (!istring.empty() ? &instring : &std::cin);
160 
161  std::ofstream outfile;
162  if (ofile == "-") ofile.clear();
163  if (!ofile.empty()) {
164  outfile.open(ofile.c_str());
165  if (!outfile.is_open()) {
166  std::cerr << "Cannot open " << ofile << " for writing\n";
167  return 1;
168  }
169  }
170  std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
171 
172  const Rhumb rh(a, f, exact);
173  const RhumbLine rhl(linecalc ? rh.Line(lat1, lon1, azi12) :
174  rh.Line(0, 0, 90));
175  // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
176  // 10^-11 sec (= 0.3 nm).
177  prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
178  int retval = 0;
179  std::string s;
180  while (std::getline(*input, s)) {
181  try {
182  std::string eol("\n");
183  if (!cdelim.empty()) {
184  std::string::size_type m = s.find(cdelim);
185  if (m != std::string::npos) {
186  eol = " " + s.substr(m) + "\n";
187  s = s.substr(0, m);
188  }
189  }
190  std::istringstream str(s);
191  if (linecalc) {
192  if (!(str >> s12))
193  throw GeographicErr("Incomplete input: " + s);
194  std::string strc;
195  if (str >> strc)
196  throw GeographicErr("Extraneous input: " + strc);
197  rhl.Position(s12, lat2, lon2, S12);
198  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
199  << Utility::str(S12, std::max(prec-7, 0)) << eol;
200  } else if (inverse) {
201  std::string slat1, slon1, slat2, slon2;
202  if (!(str >> slat1 >> slon1 >> slat2 >> slon2))
203  throw GeographicErr("Incomplete input: " + s);
204  std::string strc;
205  if (str >> strc)
206  throw GeographicErr("Extraneous input: " + strc);
207  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
208  DMS::DecodeLatLon(slat2, slon2, lat2, lon2);
209  rh.Inverse(lat1, lon1, lat2, lon2, s12, azi12, S12);
210  *output << AzimuthString(azi12, prec, dms, dmssep) << " "
211  << Utility::str(s12, prec) << " "
212  << Utility::str(S12, std::max(prec-7, 0)) << eol;
213  } else { // direct
214  std::string slat1, slon1, sazi;
215  if (!(str >> slat1 >> slon1 >> sazi >> s12))
216  throw GeographicErr("Incomplete input: " + s);
217  std::string strc;
218  if (str >> strc)
219  throw GeographicErr("Extraneous input: " + strc);
220  DMS::DecodeLatLon(slat1, slon1, lat1, lon1);
221  azi12 = DMS::DecodeAzimuth(sazi);
222  rh.Direct(lat1, lon1, azi12, s12, lat2, lon2, S12);
223  *output << LatLonString(lat2, lon2, prec, dms, dmssep) << " "
224  << Utility::str(S12, std::max(prec-7, 0)) << eol;
225  }
226  }
227  catch (const std::exception& e) {
228  // Write error message cout so output lines match input lines
229  *output << "ERROR: " << e.what() << "\n";
230  retval = 1;
231  }
232  }
233  return retval;
234  }
235  catch (const std::exception& e) {
236  std::cerr << "Caught exception: " << e.what() << "\n";
237  return 1;
238  }
239  catch (...) {
240  std::cerr << "Caught unknown exception\n";
241  return 1;
242  }
243 }
static T NaN()
Definition: Math.hpp:461
void Inverse(real lat1, real lon1, real lat2, real lon2, real &s12, real &azi12, real &S12) const
Definition: Rhumb.hpp:358
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:266
static Math::real DecodeAzimuth(const std::string &azistr)
Definition: DMS.cpp:255
RhumbLine Line(real lat1, real lon1, real azi12) const
Definition: Rhumb.cpp:134
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool swaplatlong=false)
Definition: DMS.cpp:214
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:361
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:458
void Direct(real lat1, real lon1, real azi12, real s12, real &lat2, real &lon2, real &S12) const
Definition: Rhumb.hpp:288
Header for GeographicLib::DMS class.