GeographicLib 2.6
Loading...
Searching...
No Matches
Conformal3Proj.cpp
Go to the documentation of this file.
1/**
2 * \file Conformal3Proj.cpp
3 * \brief Command line utility for computing geodesics on a triaxial ellipsoid
4 *
5 * Copyright (c) Charles Karney (2024-2025) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 *
9 * See the <a href="Conformal3Proj.1.html">man page</a> for usage information.
10 **********************************************************************/
11
12// Usual flags
13// -r reverse
14// -e (supplement with -t)
15// -w longfirst
16// -p prec
17// -h help
18// -d dms
19// -: colon
20// --help
21// --version
22// --comment-delimiter
23// + other I/O related flags
24
25// New flags
26// -ex -tx
27
28#include <iostream>
29#include <iomanip>
30#include <string>
31#include <sstream>
32#include <fstream>
33#include <GeographicLib/DMS.hpp>
37
38#include "Conformal3Proj.usage"
39
40int main(int argc, const char* const argv[]) {
41 try {
42 using namespace GeographicLib;
43 using namespace Triaxial;
44 using real = Math::real;
45 using ang = Angle;
47 bool reverse = false, dms = false,
48 longfirst = false, altell = false;
49 real
53 e2 = -1, k2 = 0, kp2 = 0,
54 ax = -1, bx = 0, cx = 0, e2x = -1, k2x = 0, kp2x = 0;
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 == "-r")
62 reverse = true;
63 else if (arg == "-t") {
64 if (m + 3 >= argc) return usage(1, true);
65 try {
66 a = Utility::val<real>(std::string(argv[m + 1]));
67 b = Utility::val<real>(std::string(argv[m + 2]));
68 c = Utility::val<real>(std::string(argv[m + 3]));
69 }
70 catch (const std::exception& e) {
71 std::cerr << "Error decoding arguments of -t: " << e.what() << "\n";
72 return 1;
73 }
74 e2 = -1;
75 m += 3;
76 } else if (arg == "-e") {
77 // Cayley ellipsoid sqrt([2,1,1/2]) is
78 // -e 1 3/2 1/3 2/3
79 if (m + 4 >= argc) return usage(1, true);
80 try {
81 b = Utility::val<real>(std::string(argv[m + 1]));
82 e2 = Utility::fract<real>(std::string(argv[m + 2]));
83 k2 = Utility::fract<real>(std::string(argv[m + 3]));
84 kp2 = Utility::fract<real>(std::string(argv[m + 4]));
85 }
86 catch (const std::exception& e) {
87 std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
88 return 1;
89 }
90 a = -1;
91 m += 4;
92 } else if (arg == "-tx") {
93 if (m + 3 >= argc) return usage(1, true);
94 try {
95 ax = Utility::val<real>(std::string(argv[m + 1]));
96 bx = Utility::val<real>(std::string(argv[m + 2]));
97 cx = Utility::val<real>(std::string(argv[m + 3]));
98 }
99 catch (const std::exception& e) {
100 std::cerr << "Error decoding arguments of -t: " << e.what() << "\n";
101 return 1;
102 }
103 e2x = -1;
104 m += 3;
105 } else if (arg == "-ex") {
106 // Cayley ellipsoid sqrt([2,1,1/2]) is
107 // -e 1 3/2 1/3 2/3
108 if (m + 4 >= argc) return usage(1, true);
109 try {
110 bx = Utility::val<real>(std::string(argv[m + 1]));
111 e2x = Utility::fract<real>(std::string(argv[m + 2]));
112 k2x = Utility::fract<real>(std::string(argv[m + 3]));
113 kp2x = Utility::fract<real>(std::string(argv[m + 4]));
114 }
115 catch (const std::exception& e) {
116 std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
117 return 1;
118 }
119 ax = -1;
120 m += 4;
121 } else if (arg == "-d") {
122 dms = true;
123 dmssep = '\0';
124 } else if (arg == "-:") {
125 dms = true;
126 dmssep = ':';
127 } else if (arg == "-w")
128 longfirst = !longfirst;
129 else if (arg == "-p") {
130 if (++m == argc) return usage(1, true);
131 try {
132 prec = Utility::val<int>(std::string(argv[m]));
133 }
134 catch (const std::exception&) {
135 std::cerr << "Precision " << argv[m] << " is not a number\n";
136 return 1;
137 }
138 } else if (arg == "--input-string") {
139 if (++m == argc) return usage(1, true);
140 istring = argv[m];
141 } else if (arg == "--input-file") {
142 if (++m == argc) return usage(1, true);
143 ifile = argv[m];
144 } else if (arg == "--output-file") {
145 if (++m == argc) return usage(1, true);
146 ofile = argv[m];
147 } else if (arg == "--line-separator") {
148 if (++m == argc) return usage(1, true);
149 if (std::string(argv[m]).size() != 1) {
150 std::cerr << "Line separator must be a single character\n";
151 return 1;
152 }
153 lsep = argv[m][0];
154 } else if (arg == "--comment-delimiter") {
155 if (++m == argc) return usage(1, true);
156 cdelim = argv[m];
157 } else if (arg == "--version") {
158 std::cout << argv[0] << ": GeographicLib version "
159 << GEOGRAPHICLIB_VERSION_STRING << "\n";
160 return 0;
161 } else
162 return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
163 }
164
165 Conformal3 tc(e2 >= 0 ? Ellipsoid3(b, e2, k2, kp2) : Ellipsoid3(a, b, c));
166 altell = e2x >= 0 || ax > 0;
167 Conformal3 tcx(e2x >= 0 ? Ellipsoid3(bx, e2x, k2x, kp2x) :
168 ax > 0 ? Ellipsoid3(ax, bx, cx) : Ellipsoid3());
169
170 if (!ifile.empty() && !istring.empty()) {
171 std::cerr << "Cannot specify --input-string and --input-file together\n";
172 return 1;
173 }
174 if (ifile == "-") ifile.clear();
175 std::ifstream infile;
176 std::istringstream instring;
177 if (!ifile.empty()) {
178 infile.open(ifile.c_str());
179 if (!infile.is_open()) {
180 std::cerr << "Cannot open " << ifile << " for reading\n";
181 return 1;
182 }
183 } else if (!istring.empty()) {
184 std::string::size_type m = 0;
185 while (true) {
186 m = istring.find(lsep, m);
187 if (m == std::string::npos)
188 break;
189 istring[m] = '\n';
190 }
191 instring.str(istring);
192 }
193 std::istream* input = !ifile.empty() ? &infile :
194 (!istring.empty() ? &instring : &std::cin);
195
196 std::ofstream outfile;
197 if (ofile == "-") ofile.clear();
198 if (!ofile.empty()) {
199 outfile.open(ofile.c_str());
200 if (!outfile.is_open()) {
201 std::cerr << "Cannot open " << ofile << " for writing\n";
202 return 1;
203 }
204 }
205 std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
206
207 // Max precision = 10: 0.1 nm in distance, 10^-15 deg (= 0.11 nm),
208 // 10^-11 sec (= 0.3 nm).
209 prec = std::min(10 + Math::extra_digits(), std::max(0, prec));
210 using std::round, std::log10, std::ceil, std::signbit;
211 int disprec = std::max(0, prec + int(round(log10(6400000/b)))),
212 angprec = prec + 5, scalprec = prec + 7;
213 if (altell) {
214 scalprec += int(round(log10(b/bx)));
215 scalprec = std::max(0, scalprec);
216 }
217 std::string s, eol, stra, strb, strc;
218 std::istringstream str;
219 int retval = 0;
220 while (std::getline(*input, s)) {
221 try {
222 eol = "\n";
223 if (!cdelim.empty()) {
224 std::string::size_type m = s.find(cdelim);
225 if (m != std::string::npos) {
226 eol = " " + s.substr(m) + "\n";
227 s = s.substr(0, m);
228 }
229 }
230 // READ
231 str.clear(); str.str(s);
232 if (!(str >> stra >> strb))
233 throw GeographicErr("Incomplete input: " + s);
234 if (str >> strc)
235 throw GeographicErr("Extraneous input: " + strc);
236 ang gam{}; real k = 1;
237 if (reverse) {
238 ang bet, omg;
239 if (altell) {
240 ang betx, omgx;
241 ang::DecodeLatLon(stra, strb, betx, omgx, longfirst);
242 tc.ReverseOther(tcx, betx, omgx, bet, omg, gam, k);
243 } else {
244 real x = Utility::val<real>(stra), y = Utility::val<real>(strb);
245 tc.Reverse(x, y, bet, omg, k);
246 }
247 *output << ang::LatLonString(bet, omg,
248 angprec, dms, dmssep, longfirst);
249 } else {
250 ang bet, omg;
251 ang::DecodeLatLon(stra, strb, bet, omg, longfirst);
252 if (altell) {
253 ang betx, omgx;
254 tc.ForwardOther(tcx, bet, omg, betx, omgx, gam, k);
255 *output << ang::LatLonString(betx, omgx,
256 angprec, dms, dmssep, longfirst);
257 } else {
258 real x, y;
259 tc.Forward(bet, omg, x, y, k);
260 *output << Utility::str(x, disprec) << " "
261 << Utility::str(y, disprec);
262 }
263 }
264 if (altell)
265 *output << " " << ang::AzimuthString(gam, angprec, dms, dmssep);
266 *output << " " << Utility::str(k, scalprec) << eol;
267 }
268 catch (const std::exception& e) {
269 // Write error message cout so output lines match input lines
270 *output << "ERROR: " << e.what() << "\n";
271 retval = 1;
272 }
273 }
274 return retval;
275 }
276 catch (const std::exception& e) {
277 std::cerr << "Caught exception: " << e.what() << "\n";
278 return 1;
279 }
280 catch (...) {
281 std::cerr << "Caught unknown exception\n";
282 return 1;
283 }
284}
Header for the GeographicLib::AngleT class.
int main(int argc, const char *const argv[])
Header for GeographicLib::Triaxial::Conformal3 class.
Header for GeographicLib::DMS class.
int usage(int retval, bool)
Definition Geod3ODE.cpp:41
GeographicLib::Angle ang
GeographicLib::Math::real real
Header for GeographicLib::Utility class.
static void DecodeLatLon(const std::string &stra, const std::string &strb, AngleT &lat, AngleT &lon, bool longfirst=false)
static std::string LatLonString(AngleT lat, AngleT lon, int prec, bool dms=false, char dmssep='\0', bool longfirst=false)
static std::string AzimuthString(AngleT azi, int prec, bool dms=false, char dmssep='\0')
Exception handling for GeographicLib.
static int extra_digits()
Definition Math.cpp:49
static T fract(const std::string &s)
Definition Utility.hpp:298
static T val(const std::string &s)
Definition Utility.hpp:225
static int set_digits(int ndigits=0)
Definition Utility.cpp:184
static std::string str(T x, int p=-1)
Definition Utility.hpp:161
Namespace for operations on triaxial ellipsoids.
Namespace for GeographicLib.
AngleT< Math::real > Angle
Definition Angle.hpp:760