GeographicLib 2.5
IntersectTool.cpp
Go to the documentation of this file.
1/**
2 * \file IntersectTool.cpp
3 * \brief Command line utility for geodesic intersections
4 *
5 * Copyright (c) Charles Karney (2023) <karney@alum.mit.edu> and licensed under
6 * the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 *
9 * See the <a href="IntersectTool.1.html">man page</a> for usage information.
10 **********************************************************************/
11
12#include <iostream>
13#include <string>
14#include <sstream>
15#include <fstream>
16#include <vector>
18#include <GeographicLib/DMS.hpp>
21
22#include "IntersectTool.usage"
23using namespace GeographicLib;
25
26int main(int argc, const char* const argv[]) {
27 try {
28 enum { CLOSE = 0, OFFSET, NEXT, SEGMENT };
30 real
33 maxdist = -1;
34 bool exact = false, check = false, longfirst = false;
35 int prec = 3, mode = CLOSE;
36 std::string istring, ifile, ofile, cdelim;
37 char lsep = ';';
38
39 for (int m = 1; m < argc; ++m) {
40 std::string arg(argv[m]);
41 if (arg == "-e") {
42 if (m + 2 >= argc) return usage(1, true);
43 try {
44 a = Utility::val<real>(std::string(argv[m + 1]));
45 f = Utility::fract<real>(std::string(argv[m + 2]));
46 }
47 catch (const std::exception& e) {
48 std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
49 return 1;
50 }
51 m += 2;
52 } else if (arg == "-E")
53 exact = true;
54 else if (arg == "-p") {
55 if (++m == argc) return usage(1, true);
56 try {
57 prec = Utility::val<int>(std::string(argv[m]));
58 }
59 catch (const std::exception&) {
60 std::cerr << "Precision " << argv[m] << " is not a number\n";
61 return 1;
62 }
63 } else if (arg == "-R") {
64 if (++m == argc) return usage(1, true);
65 try {
66 maxdist = Utility::val<real>(std::string(argv[m]));
67 }
68 catch (const std::exception&) {
69 std::cerr << "Maxdist " << argv[m] << " is not a number\n";
70 return 1;
71 }
72 if (!(maxdist >= 0)) {
73 std::cerr << "Maxdist must be nonnegative\n";
74 return 1;
75 }
76 } else if (arg == "-c")
77 mode = CLOSE;
78 else if (arg == "-o")
79 mode = OFFSET;
80 else if (arg == "-n")
81 mode = NEXT;
82 else if (arg == "-i")
83 mode = SEGMENT;
84 else if (arg == "-C")
85 check = true;
86 else if (arg == "-w")
87 longfirst = true;
88 else if (arg == "--input-string") {
89 if (++m == argc) return usage(1, true);
90 istring = argv[m];
91 } else if (arg == "--input-file") {
92 if (++m == argc) return usage(1, true);
93 ifile = argv[m];
94 } else if (arg == "--output-file") {
95 if (++m == argc) return usage(1, true);
96 ofile = argv[m];
97 } else if (arg == "--line-separator") {
98 if (++m == argc) return usage(1, true);
99 if (std::string(argv[m]).size() != 1) {
100 std::cerr << "Line separator must be a single character\n";
101 return 1;
102 }
103 lsep = argv[m][0];
104 } else if (arg == "--comment-delimiter") {
105 if (++m == argc) return usage(1, true);
106 cdelim = argv[m];
107 } else if (arg == "--version") {
108 std::cout << argv[0] << ": GeographicLib version "
109 << GEOGRAPHICLIB_VERSION_STRING << "\n";
110 return 0;
111 } else
112 return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
113 }
114
115 if (!ifile.empty() && !istring.empty()) {
116 std::cerr << "Cannot specify --input-string and --input-file together\n";
117 return 1;
118 }
119 if (ifile == "-") ifile.clear();
120 std::ifstream infile;
121 std::istringstream instring;
122 if (!ifile.empty()) {
123 infile.open(ifile.c_str());
124 if (!infile.is_open()) {
125 std::cerr << "Cannot open " << ifile << " for reading\n";
126 return 1;
127 }
128 } else if (!istring.empty()) {
129 std::string::size_type m = 0;
130 while (true) {
131 m = istring.find(lsep, m);
132 if (m == std::string::npos)
133 break;
134 istring[m] = '\n';
135 }
136 instring.str(istring);
137 }
138 std::istream* input = !ifile.empty() ? &infile :
139 (!istring.empty() ? &instring : &std::cin);
140
141 std::ofstream outfile;
142 if (ofile == "-") ofile.clear();
143 if (!ofile.empty()) {
144 outfile.open(ofile.c_str());
145 if (!outfile.is_open()) {
146 std::cerr << "Cannot open " << ofile << " for writing\n";
147 return 1;
148 }
149 }
150 std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
151
152 Geodesic geod(a, f, exact);
153 Intersect intersect(geod);
154 real latX1, lonX1, aziX, latY1, lonY1, aziY, latX2, lonX2, latY2, lonY2,
155 x0 = 0, y0 = 0, x, y;
156 std::string inp[8], s, sc, eol;
157 std::istringstream str;
158 int retval = 0,
159 ninp = mode == CLOSE ? 6 : (mode == NEXT ? 4 :
160 8); // mode == OFFSET || mode == SEGMENT
161 GeodesicLine lineX, lineY;
162 unsigned caps = Intersect::LineCaps;
163 while (std::getline(*input, s)) {
164 try {
165 eol = "\n";
166 if (!cdelim.empty()) {
167 std::string::size_type m = s.find(cdelim);
168 if (m != std::string::npos) {
169 eol = " " + s.substr(m) + "\n";
170 s = s.substr(0, m);
171 }
172 }
173 str.clear(); str.str(s);
174 for (int i = 0; i < ninp; ++i) {
175 if (!(str >> inp[i]))
176 throw GeographicErr("Incomplete input: " + s);
177 }
178 if (str >> sc)
179 throw GeographicErr("Extraneous input: " + sc);
180 if (mode == CLOSE || mode == OFFSET) {
181 DMS::DecodeLatLon(inp[0], inp[1], latX1, lonX1, longfirst);
182 aziX = DMS::DecodeAzimuth(inp[2]);
183 DMS::DecodeLatLon(inp[3], inp[4], latY1, lonY1, longfirst);
184 aziY = DMS::DecodeAzimuth(inp[5]);
185 if (mode == OFFSET) {
186 x0 = Utility::val<real>(inp[6]);
187 y0 = Utility::val<real>(inp[7]);
188 } else
189 x0 = y0 = 0;
190 lineX = geod.Line(latX1, lonX1, aziX, caps);
191 lineY = geod.Line(latY1, lonY1, aziY, caps);
192 } else if (mode == NEXT) {
193 DMS::DecodeLatLon(inp[0], inp[1], latX1, lonX1, longfirst);
194 aziX = DMS::DecodeAzimuth(inp[2]);
195 aziY = DMS::DecodeAzimuth(inp[3]);
196 lineX = geod.Line(latX1, lonX1, aziX, caps);
197 lineY = geod.Line(latX1, lonX1, aziY, caps);
198 } else { // mode == SEGMENT
199 DMS::DecodeLatLon(inp[0], inp[1], latX1, lonX1, longfirst);
200 DMS::DecodeLatLon(inp[2], inp[3], latX2, lonX2, longfirst);
201 DMS::DecodeLatLon(inp[4], inp[5], latY1, lonY1, longfirst);
202 DMS::DecodeLatLon(inp[6], inp[7], latY2, lonY2, longfirst);
203 lineX = geod.InverseLine(latX1, lonX1, latX2, lonX2,
205 lineY = geod.InverseLine(latY1, lonY1, latY2, lonY2,
207 x0 = lineX.Distance()/2;
208 y0 = lineY.Distance()/2;
209 }
210 std::pair<real, real> p0(x0, y0);
211 if (maxdist < 0) {
212 int segmode = 0, c;
213 auto p = mode == CLOSE || mode == OFFSET ?
214 intersect.Closest(lineX, lineY, p0, &c) :
215 mode == NEXT ? intersect.Next(lineX, lineY, &c) :
216 intersect.Segment(lineX, lineY, segmode, &c);
217 x = p.first; y = p.second;
218 *output << Utility::str(x, prec) << " "
219 << Utility::str(y, prec) << " " << c;
220 if (mode == SEGMENT)
221 *output << " " << segmode;
222 *output << eol;
223 if (check) {
224 lineX.Position(x, latX2, lonX2);
225 lineY.Position(y, latY2, lonY2);
226 real sXY;
227 geod.Inverse(latX2, lonX2, latY2, lonY2, sXY);
228 std::cerr << Utility::str(longfirst ? lonX2 : latX2, prec+5) << " "
229 << Utility::str(longfirst ? latX2 : lonX2, prec+5) << " "
230 << Utility::str(longfirst ? lonY2 : latY2, prec+5) << " "
231 << Utility::str(longfirst ? latY2 : lonY2, prec+5) << " "
232 << Utility::str(sXY, prec) << eol;
233 }
234 } else {
235 std::vector<int> c;
236 auto v = intersect.All(lineX, lineY, maxdist, c, p0);
237 unsigned n = unsigned(v.size());
238 for (unsigned i = 0; i < n; ++i) {
239 x = v[i].first; y = v[i].second;
240 *output << Utility::str(x, prec) << " " << Utility::str(y, prec)
241 << " " << c[i] << " "
242 << Utility::str(Intersect::Dist(v[i], p0), prec)
243 << eol;
244 if (check) {
245 lineX.Position(x, latX2, lonX2);
246 lineY.Position(y, latY2, lonY2);
247 real sXY;
248 geod.Inverse(latX2, lonX2, latY2, lonY2, sXY);
249 std::cerr << Utility::str(longfirst ? lonX2 : latX2, prec+5) << " "
250 << Utility::str(longfirst ? latX2 : lonX2, prec+5) << " "
251 << Utility::str(longfirst ? lonY2 : latY2, prec+5) << " "
252 << Utility::str(longfirst ? latY2 : lonY2, prec+5) << " "
253 << Utility::str(sXY, prec) << eol;
254 }
255 }
256 *output << "nan nan 0 nan" << eol;
257 if (check)
258 std::cerr << "nan nan nan nan nan" << eol;
259 }
260 }
261 catch (const std::exception& e) {
262 // Write error message cout so output lines match input lines
263 *output << "ERROR: " << e.what() << "\n";
264 retval = 1;
265 }
266 }
267 return retval;
268 }
269 catch (const std::exception& e) {
270 std::cerr << "Caught exception: " << e.what() << "\n";
271 return 1;
272 }
273 catch (...) {
274 std::cerr << "Caught unknown exception\n";
275 return 1;
276 }
277}
Header for GeographicLib::DMS class.
GeographicLib::Math::real real
Definition GeodSolve.cpp:28
Header for GeographicLib::Geodesic class.
Math::real real
int main(int argc, const char *const argv[])
Header for GeographicLib::Intersect class.
Header for GeographicLib::Utility class.
static Math::real DecodeAzimuth(const std::string &azistr)
Definition DMS.cpp:402
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool longfirst=false)
Definition DMS.cpp:363
Math::real Distance() const
Math::real Position(real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Geodesic calculations
Definition Geodesic.hpp:175
GeodesicLine InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps=ALL) const
Definition Geodesic.cpp:532
GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Definition Geodesic.cpp:123
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:689
Exception handling for GeographicLib.
Geodesic intersections
Definition Intersect.hpp:71
Point Segment(Math::real latX1, Math::real lonX1, Math::real latX2, Math::real lonX2, Math::real latY1, Math::real lonY1, Math::real latY2, Math::real lonY2, int &segmode, int *c=nullptr) const
Definition Intersect.cpp:72
static const unsigned LineCaps
Definition Intersect.hpp:84
static Math::real Dist(const Point &p, const Point &p0=Point(0, 0))
Point Closest(Math::real latX, Math::real lonX, Math::real aziX, Math::real latY, Math::real lonY, Math::real aziY, const Point &p0=Point(0, 0), int *c=nullptr) const
Definition Intersect.cpp:55
std::vector< Point > All(Math::real latX, Math::real lonX, Math::real aziX, Math::real latY, Math::real lonY, Math::real aziY, Math::real maxdist, std::vector< int > &c, const Point &p0=Point(0, 0)) const
Point Next(Math::real latX, Math::real lonX, Math::real aziX, Math::real aziY, int *c=nullptr) const
Definition Intersect.cpp:91
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 GeographicLib.