GeographicLib 2.3

Intersect.cpp
Go to the documentation of this file.
1/**
2 * \file Intersect.cpp
3 * \brief Implementation for GeographicLib::Intersect class
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
10#include <GeographicLib/Intersect.hpp>
11#include <limits>
12#include <utility>
13#include <algorithm>
14#include <set>
15
16 using namespace std;
17
18 namespace GeographicLib {
19
20 Intersect::Intersect(const Geodesic& geod)
21 : _geod(geod)
22 , _a(_geod.EquatorialRadius())
23 , _f(_geod.Flattening())
24 , _R(sqrt(_geod.EllipsoidArea() / (4 * Math::pi())))
25 , _d(_R * Math::pi()) // Used to normalize intersection points
26 , _eps(3 * numeric_limits<real>::epsilon())
27 , _tol(_d * pow(numeric_limits<real>::epsilon(), 3/real(4)))
28 , _delta(_d * pow(numeric_limits<real>::epsilon(), 1/real(5)))
29 , _comp(_delta)
30 , _cnt0(0)
31 , _cnt1(0)
32 , _cnt2(0)
33 , _cnt3(0)
34 , _cnt4(0)
35 {
36 _t1 = _t4 = _a * (1 - _f) * Math::pi();
37 _t2 = 2 * distpolar(90);
38 _geod.Inverse(0, 0, 90, 0, _t5); _t5 *= 2;
39 if (_f > 0) {
40 _t3 = distoblique();
41 _t4 = _t1;
42 } else {
43 _t3 = _t5;
44 _t4 = polarb();
45 swap(_t1, _t2);
46 }
47 _d1 = _t2 / 2;
48 _d2 = 2 * _t3 / 3;
49 _d3 = _t4 - _delta;
50 if (! (_d1 < _d3 && _d2 < _d3 && _d2 < 2 * _t1) )
51 throw GeographicErr("Ellipsoid too eccentric for Closest");
52 }
53
54 Intersect::Point
55 Intersect::Closest(Math::real latX, Math::real lonX, Math::real aziX,
56 Math::real latY, Math::real lonY, Math::real aziY,
57 const Intersect::Point& p0, int* c) const {
58 return Closest(_geod.Line(latX, lonX, aziX, LineCaps),
59 _geod.Line(latY, lonY, aziY, LineCaps),
60 p0, c);
61 }
62
63 Intersect::Point
64 Intersect::Closest(const GeodesicLine& lineX, const GeodesicLine& lineY,
65 const Intersect::Point& p0, int* c) const {
66 XPoint p = ClosestInt(lineX, lineY, XPoint(p0));
67 if (c) *c = p.c;
68 return p.data();
69 }
70
71 Intersect::Point
72 Intersect::Segment(Math::real latX1, Math::real lonX1,
73 Math::real latX2, Math::real lonX2,
74 Math::real latY1, Math::real lonY1,
75 Math::real latY2, Math::real lonY2,
76 int& segmode, int* c) const {
77 return Segment(_geod.InverseLine(latX1, lonX1, latX2, lonX2, LineCaps),
78 _geod.InverseLine(latY1, lonY1, latY2, lonY2, LineCaps),
79 segmode, c);
80 }
81
82 Intersect::Point
83 Intersect::Segment(const GeodesicLine& lineX,
84 const GeodesicLine& lineY, int& segmode, int* c) const {
85 XPoint p = SegmentInt(lineX, lineY, segmode);
86 if (c) *c = p.c;
87 return p.data();
88 }
89
90 Intersect::Point
91 Intersect::Next(Math::real latX, Math::real lonX,
92 Math::real aziX, Math::real aziY, int* c) const {
93 return Next(_geod.Line(latX, lonX, aziX, LineCaps),
94 _geod.Line(latX, lonX, aziY, LineCaps), c);
95 }
96
97 Intersect::Point
98 Intersect::Next(const GeodesicLine& lineX, const GeodesicLine& lineY,
99 int* c) const {
100 XPoint p = NextInt(lineX, lineY);
101 if (c) *c = p.c;
102 return p.data();
103 }
104
105 std::vector<Intersect::Point>
106 Intersect::All(Math::real latX, Math::real lonX, Math::real aziX,
107 Math::real latY, Math::real lonY, Math::real aziY,
108 Math::real maxdist, const Point& p0) const {
109 return All(_geod.Line(latX, lonX, aziX, LineCaps),
110 _geod.Line(latY, lonY, aziY, LineCaps),
111 maxdist, p0);
112 }
113
114 std::vector<Intersect::Point>
115 Intersect::All(Math::real latX, Math::real lonX, Math::real aziX,
116 Math::real latY, Math::real lonY, Math::real aziY,
117 Math::real maxdist, std::vector<int>& c, const Point& p0)
118 const {
119 return All(_geod.Line(latX, lonX, aziX, LineCaps),
120 _geod.Line(latY, lonY, aziY, LineCaps),
121 maxdist, c, p0);
122 }
123
124 std::vector<Intersect::Point>
125 Intersect::All(const GeodesicLine& lineX, const GeodesicLine& lineY,
126 Math::real maxdist, const Point& p0) const {
127 vector<int> c;
128 return AllInternal(lineX, lineY, maxdist, p0, c, false);
129 }
130
131 std::vector<Intersect::Point>
132 Intersect::All(const GeodesicLine& lineX, const GeodesicLine& lineY,
133 Math::real maxdist, std::vector<int>& c, const Point& p0)
134 const {
135 return AllInternal(lineX, lineY, maxdist, p0, c, true);
136 }
137
138 Intersect::XPoint
139 Intersect::Spherical(const GeodesicLine& lineX, const GeodesicLine& lineY,
140 const Intersect::XPoint& p) const {
141 // threshold for coincident geodesics and intersections; this corresponds
142 // to about 4.3 nm on WGS84.
143 real latX, lonX, aziX, latY, lonY, aziY;
144 lineX.Position(p.x , latX, lonX, aziX);
145 lineY.Position(p.y, latY, lonY, aziY);
146 real z, aziXa, aziYa;
147 _geod.Inverse(latX, lonX, latY, lonY, z, aziXa, aziYa);
148 real sinz = sin(z/_R), cosz = cos(z/_R);
149 // X = interior angle at X, Y = exterior angle at Y
150 real dX, dY, dXY,
151 X = Math::AngDiff(aziX, aziXa, dX), Y = Math::AngDiff(aziY, aziYa, dY),
152 XY = Math::AngDiff(X, Y, dXY);
153 real s = copysign(real(1), XY + (dXY + dY - dX)); // inverted triangle
154 // For z small, sinz -> z, cosz -> 1
155 // ( sinY*cosX*cosz - cosY*sinX) =
156 // (-sinX*cosY*cosz + cosX*sinY) -> sin(Y-X)
157 // for z = pi, sinz -> 0, cosz -> -1
158 // ( sinY*cosX*cosz - cosY*sinX) -> -sin(Y+X)
159 // (-sinX*cosY*cosz + cosX*sinY) -> sin(Y+X)
160 real sinX, cosX; Math::sincosde(s*X, s*dX, sinX, cosX);
161 real sinY, cosY; Math::sincosde(s*Y, s*dY, sinY, cosY);
162 real sX, sY;
163 int c;
164 if (z <= _eps * _R) {
165 sX = sY = 0; // Already at intersection
166 // Determine whether lineX and lineY are parallel or antiparallel
167 if (fabs(sinX - sinY) <= _eps && fabs(cosX - cosY) <= _eps)
168 c = 1;
169 else if (fabs(sinX + sinY) <= _eps && fabs(cosX + cosY) <= _eps)
170 c = -1;
171 else
172 c = 0;
173 } else if (fabs(sinX) <= _eps && fabs(sinY) <= _eps) {
174 c = cosX * cosY > 0 ? 1 : -1;
175 // Coincident geodesics, place intersection at midpoint
176 sX = cosX * z/2; sY = -cosY * z/2;
177 // alt1: sX = cosX * z; sY = 0;
178 // alt2: sY = -cosY * z; sX = 0;
179 } else {
180 // General case. [SKIP: Divide args by |sinz| to avoid possible
181 // underflow in {sinX,sinY}*sinz; this is probably not necessary].
182 // Definitely need to treat sinz < 0 (z > pi*R) correctly. Without
183 // this we have some convergence failures in Basic.
184 sX = _R * atan2(sinY * sinz, sinY * cosX * cosz - cosY * sinX);
185 sY = _R * atan2(sinX * sinz, -sinX * cosY * cosz + cosX * sinY);
186 c = 0;
187 }
188 return XPoint(sX, sY, c);
189 }
190
191 Intersect::XPoint
192 Intersect::Basic(const GeodesicLine& lineX, const GeodesicLine& lineY,
193 const Intersect::XPoint& p0) const {
194 ++_cnt1;
195 XPoint q = p0;
196 for (int n = 0; n < numit_ || GEOGRAPHICLIB_PANIC; ++n) {
197 ++_cnt0;
198 XPoint dq = Spherical(lineX, lineY, q);
199 q += dq;
200 if (q.c || !(dq.Dist() > _tol)) break; // break if nan
201 }
202 return q;
203 }
204
205 Intersect::XPoint
206 Intersect::ClosestInt(const GeodesicLine& lineX, const GeodesicLine& lineY,
207 const Intersect::XPoint& p0) const {
208 const int num = 5;
209 const int ix[num] = { 0, 1, -1, 0, 0 };
210 const int iy[num] = { 0, 0, 0, 1, -1 };
211 bool skip[num] = { 0, 0, 0, 0, 0 };
212 XPoint q; // Best intersection so far
213 for (int n = 0; n < num; ++n) {
214 if (skip[n]) continue;
215 XPoint qx = Basic(lineX, lineY, p0 + XPoint(ix[n] * _d1, iy[n] * _d1));
216 qx = fixcoincident(p0, qx);
217 if (_comp.eq(q, qx)) continue;
218 if (qx.Dist(p0) < _t1) { q = qx; ++_cnt2; break; }
219 if (n == 0 || qx.Dist(p0) < q.Dist(p0)) { q = qx; ++_cnt2; }
220 for (int m = n + 1; m < num; ++m)
221 skip[m] = skip[m] ||
222 qx.Dist(p0 + XPoint(ix[m]*_d1, iy[m]*_d1)) < 2*_t1 - _d1 - _delta;
223 }
224 return q;
225 }
226
227 Intersect::XPoint
228 Intersect::NextInt(const GeodesicLine& lineX, const GeodesicLine& lineY)
229 const {
230 const int num = 8;
231 const int ix[num] = { -1, -1, 1, 1, -2, 0, 2, 0 };
232 const int iy[num] = { -1, 1, -1, 1, 0, 2, 0, -2 };
233 bool skip[num] = { 0, 0, 0, 0, 0, 0, 0, 0 };
234 XPoint z(0,0), // for excluding the origin
235 q(Math::infinity(), 0); // Best intersection so far
236 for (int n = 0; n < num; ++n) {
237 if (skip[n]) continue;
238 XPoint qx = Basic(lineX, lineY, XPoint(ix[n] * _d2, iy[n] * _d2));
239 qx = fixcoincident(z, qx);
240 bool zerop = _comp.eq(z, qx);
241 if (qx.c == 0 && zerop) continue;
242 if (qx.c && zerop) {
243 for (int sgn = -1; sgn <= 1; sgn+=2) {
244 real s = ConjugateDist(lineX, sgn * _d, false);
245 XPoint qa(s, qx.c*s, qx.c);
246 if (qa.Dist() < q.Dist()) { q = qa; ++_cnt2; }
247 }
248 } else {
249 if (qx.Dist() < q.Dist()) { q = qx; ++_cnt2; }
250 }
251 for (int sgn = -1; sgn <= 1; ++sgn) {
252 // if qx.c == 0 only process sgn == 0
253 // if zerop skip sgn == 0
254 if ((qx.c == 0 && sgn != 0) || (zerop && sgn == 0)) continue;
255 XPoint qy = qx.c ? qx + Point(sgn * _d2, qx.c * sgn *_d2) : qx;
256 for (int m = n + 1; m < num; ++m)
257 skip[m] = skip[m] ||
258 qy.Dist(XPoint(ix[m]*_d2, iy[m]*_d2)) < 2*_t1 - _d2 - _delta;
259 }
260 }
261 return q;
262 }
263
264 Intersect::XPoint
265 Intersect::SegmentInt(const GeodesicLine& lineX, const GeodesicLine& lineY,
266 int& segmode) const {
267 // The conjecture is that whenever two geodesic segments intersect, the
268 // intersection is the one that is closest to the midpoints of segments.
269 // If this is proven, set conjectureproved to true.
270 const bool conjectureproved = false;
271 real sx = lineX.Distance(), sy = lineY.Distance();
272 // p0 is center of [sx,sy] rectangle, q is intersection closest to p0
273 XPoint p0 = XPoint(sx/2, sy/2), q = ClosestInt(lineX, lineY, p0);
274 q = fixsegment(sx, sy, q);
275 segmode = segmentmode(sx, sy, q);
276 // Are corners of [sx,sy] rectangle further from p0 than q?
277 if (!conjectureproved && segmode != 0 && p0.Dist() >= p0.Dist(q)) {
278 int segmodex = 1;
279 XPoint qx;
280 // Cycle through 4 corners of [sx,sy] rectangle
281 for (int ix = 0; ix < 2 && segmodex != 0; ++ix) {
282 for (int iy = 0; iy < 2 && segmodex != 0; ++iy) {
283 XPoint t(ix * sx, iy * sy); // corner point
284 // Is corner outside next intersection exclusion circle?
285 if (q.Dist(t) >= 2 * _t1) {
286 ++_cnt3;
287 qx = Basic(lineX, lineY, t);
288 // fixsegment is not needed because the coincidence line must just
289 // slice off a corner of the sx x sy rectangle.
290 qx = fixcoincident(t, qx);
291 // No need to check if equal to q, because result is only accepted
292 // if segmode != 0 && segmodex == 0.
293 segmodex = segmentmode(sx, sy, qx);
294 }
295 }
296 }
297 if (segmodex == 0) { ++_cnt4; segmode = 0; q = qx; }
298 }
299 return q;
300 }
301
302 std::vector<Intersect::XPoint>
303 Intersect::AllInt0(const GeodesicLine& lineX,
304 const GeodesicLine& lineY,
305 Math::real maxdist, const XPoint& p0) const {
306 real maxdistx = maxdist + _delta;
307 const int m = int(ceil(maxdistx / _d3)), // process m x m set of tiles
308 m2 = m*m + (m - 1) % 2, // add center tile if m is even
309 n = m - 1; // Range of i, j = [-n:2:n]
310 real d3 = maxdistx/m; // d3 <= _d3
311 vector<XPoint> start(m2);
312 vector<bool> skip(m2, false);
313 int h = 0, c0 = 0;
314 start[h++] = p0;
315 for (int i = -n; i <= n; i += 2)
316 for (int j = -n; j <= n; j += 2) {
317 if (!(i == 0 && j == 0))
318 start[h++] = p0 + XPoint( d3 * (i + j) / 2, d3 * (i - j) / 2);
319 }
320 // assert(h == m2);
321 set<XPoint, SetComp> r(_comp); // Intersections found
322 set<XPoint, SetComp> c(_comp); // Closest coincident intersections
323 vector<XPoint> added;
324 for (int k = 0; k < m2; ++k) {
325 if (skip[k]) continue;
326 XPoint q = Basic(lineX, lineY, start[k]);
327 if (r.find(q) != r.end() // intersection already found
328 // or it's on a line of coincident intersections already processed
329 || (c0 != 0 && c.find(fixcoincident(p0, q)) != c.end()))
330 continue;
331 added.clear();
332 if (q.c != 0) {
333 // This value of q.c must be constitent with c0
334 // assert(c0 == 0 || c0 == q.c);
335 c0 = q.c;
336 // Process coincident intersections
337 q = fixcoincident(p0, q);
338 c.insert(q);
339 // Elimate all existing intersections on this line (which
340 // didn't set c0).
341 for (auto qp = r.begin(); qp != r.end(); ) {
342 if (_comp.eq(fixcoincident(p0, *qp, c0), q)) {
343 qp = r.erase(qp);
344 }
345 else
346 ++qp;
347 }
348 real s0 = q.x;
349 XPoint qc;
350 real t, m12, M12, M21;
351 lineX.GenPosition(false, s0,
352 GeodesicLine::REDUCEDLENGTH |
353 GeodesicLine::GEODESICSCALE,
354 t, t, t, t, m12, M12, M21, t);
355 // Compute line of conjugate points
356 for (int sgn = -1; sgn <= 1; sgn += 2) {
357 real sa = 0;
358 do {
359 sa = ConjugateDist(lineX, s0 + sa + sgn*_d, false, m12, M12, M21)
360 - s0;
361 qc = q + XPoint(sa, c0*sa);
362 added.push_back(qc);
363 r.insert(qc);
364 } while (qc.Dist(p0) <= maxdistx);
365 }
366 }
367 added.push_back(q);
368 r.insert(q);
369 for (auto qp = added.cbegin(); qp != added.cend(); ++qp) {
370 for (int l = k + 1; l < m2; ++l)
371 skip[l] = skip[l] || qp->Dist(start[l]) < 2*_t1 - d3 - _delta;
372 }
373 }
374 // Trim intersections to maxdist
375 for (auto qp = r.begin(); qp != r.end(); ) {
376 if (!(qp->Dist(p0) <= maxdist))
377 qp = r.erase(qp);
378 else
379 ++qp;
380 }
381 vector<XPoint> v(r.size());
382 int i = 0;
383 for (auto p = r.cbegin(); p != r.cend(); ++p)
384 v[i++] = *p;
385 sort(v.begin(), v.end(), RankPoint(p0));
386 return v;
387 }
388
389 std::vector<Intersect::Point>
390 Intersect::AllInternal(const GeodesicLine& lineX, const GeodesicLine& lineY,
391 Math::real maxdist, const Point& p0,
392 std::vector<int>& c, bool cp) const {
393 const vector<XPoint>
394 v = AllInt0(lineX, lineY, fmax(real(0), maxdist), XPoint(p0));
395 int i = int(v.size());
396 vector<Point> u(i);
397 if (cp) c.resize(i);
398 for (int j = 0; j < i; ++j) {
399 u[j] = v[j].data();
400 if (cp) c[j] = v[j].c;
401 }
402 return u;
403 }
404
405 Math::real Intersect::distpolar(Math::real lat1, Math::real* lat2)
406 const {
407 GeodesicLine line = _geod.Line(lat1, 0, 0,
408 GeodesicLine::REDUCEDLENGTH |
409 GeodesicLine::GEODESICSCALE |
410 GeodesicLine::DISTANCE_IN);
411 real s = ConjugateDist(line, (1 + _f/2) * _a * Math::pi() / 2, true);
412 if (lat2) {
413 real t;
414 line.GenPosition(false, s, GeodesicLine::LATITUDE,
415 *lat2, t, t, t, t, t, t, t);
416 }
417 return s;
418 }
419
420 Math::real Intersect::polarb(Math::real* lata, Math::real* latb) const {
421 if (_f == 0) {
422 if (lata) *lata = 64;
423 if (latb) *latb = 90-64;
424 return _d;
425 }
426 real
427 lat0 = 63, s0 = distpolar(lat0),
428 lat1 = 65, s1 = distpolar(lat1),
429 lat2 = 64, s2 = distpolar(lat2),
430 latx = lat2, sx = s2;
431 // Solve for ds(lat)/dlat = 0 with a quadratic fit
432 for (int i = 0; i < 10; ++i) {
433 real den = (lat1-lat0)*s2 + (lat0-lat2)*s1 + (lat2-lat1)*s0;
434 if (!(den < 0 || den > 0)) break; // Break if nan
435 real latn = ((lat1-lat0)*(lat1+lat0)*s2 + (lat0-lat2)*(lat0+lat2)*s1 +
436 (lat2-lat1)*(lat2+lat1)*s0) / (2*den);
437 lat0 = lat1; s0 = s1;
438 lat1 = lat2; s1 = s2;
439 lat2 = latn; s2 = distpolar(lat2);
440 if (_f < 0 ? (s2 < sx) : (s2 > sx)) {
441 sx = s2;
442 latx = lat2;
443 }
444 }
445 if (lata) *lata = latx;
446 if (latb) distpolar(latx, latb);
447 return 2 * sx;
448 }
449
450 // Find {semi-,}conjugate point relative to s0 which is close to s1.
451 Math::real Intersect::ConjugateDist(const GeodesicLine& line, Math::real s3,
452 bool semi, Math::real m12,
453 Math::real M12, Math::real M21) const {
454 // semi = false: solve for m23 = 0 using dm23/ds3 = M32
455 // semi = true : solve for M23 = 0 using dM23/ds3 = - (1 - M23*M32)/m23
456 // Here 2 is point with given m12, M12, M21 and default values s.t. point 2
457 // = point 1.
458 real s = s3;
459 for (int i = 0; i < 100; ++i) {
460 real t, m13, M13, M31;
461 line.GenPosition(false, s,
462 GeodesicLine::REDUCEDLENGTH |
463 GeodesicLine::GEODESICSCALE,
464 t, t, t, t, m13, M13, M31, t);
465 real
466 // See "Algorithms for geodesics", eqs. 31, 32, 33.
467 m23 = m13 * M12 - m12 * M13,
468 // when m12 -> eps, (1 - M12 * M21) -> eps^2, I suppose.
469 M23 = M13 * M21 + (m12 == 0 ? 0 : (1 - M12 * M21) * m13/m12),
470 M32 = M31 * M12 + (m13 == 0 ? 0 : (1 - M13 * M31) * m12/m13);
471 real ds = semi ? m23 * M23 / (1 - M23*M32) : -m23 / M32;
472 s = s + ds;
473 if (!(fabs(ds) > _tol)) break;
474 }
475 return s;
476 }
477
478 Math::real Intersect::conjdist(Math::real azi,
479 Math::real* ds,
480 Math::real* sp, Math::real* sm) const {
481 GeodesicLine line = _geod.Line(0, 0, azi, LineCaps);
482 real s = ConjugateDist(line, _d, false);
483 if (ds) {
484 XPoint p = Basic(line, line, XPoint(s/2, -3*s/2));
485 if (sp) *sp = p.x;
486 if (sm) *sm = p.y;
487 *ds = p.Dist() - 2*s;
488 }
489 return s;
490 }
491
492 Math::real Intersect::distoblique(Math::real* azi,
493 Math::real* sp,
494 Math::real* sm) const {
495 if (_f == 0) {
496 if (azi) *azi = 45;
497 if (sp) *sp = 0.5;
498 if (sm) *sm = -1.5;
499 return _d;
500 }
501 real sa, sb,
502 azi0 = 46, ds0, s0 = conjdist(azi0, &ds0, &sa, &sb),
503 azi1 = 44, ds1, s1 = conjdist(azi1, &ds1, &sa, &sb),
504 azix = azi1, dsx = fabs(ds1), sx = s1, sax = sa, sbx = sb;
505 // find ds(azi) = 0 by secant method
506 (void) s0;
507 for (int i = 0; i < 10 && ds1 != ds0; ++i) {
508 real azin = (azi0*ds1-azi1*ds0)/(ds1-ds0);
509 azi0 = azi1; s0 = s1; ds0 = ds1;
510 azi1 = azin; s1 = conjdist(azi1, &ds1, &sa, &sb);
511 if (fabs(ds1) < dsx) {
512 azix = azi1, sx = s1, dsx = fabs(ds1);
513 sax = sa; sbx = sb;
514 if (ds1 == 0) break;
515 }
516 }
517 if (azi) *azi = azix;
518 if (sp) *sp = sax;
519 if (sm) *sm = sbx;
520 return sx;
521 }
522
523 Intersect::XPoint
524 Intersect::fixcoincident(const Intersect::XPoint& p0,
525 const Intersect::XPoint& p) {
526 return fixcoincident(p0, p, p.c);
527 }
528
529 Intersect::XPoint
530 Intersect::fixcoincident(const Intersect::XPoint& p0,
531 const Intersect::XPoint& p, int c) {
532 if (c == 0) return p;
533 // eqs : [p0x-p1x = -c*(p0y-p1y), p1x = px+s, p1y = py+c*s]$
534 // sol : solve(eqs,[s,p1x,p1y]);
535 // =>
536 // sol:[ s = ((p0x+c*p0y) - (px+c*py))/2,
537 // p1x = px + ((p0x+c*p0y) - (px+c*py))/2,
538 // p1y = py + c * ((p0x+c*p0y) - (px+c*py))/2
539 // ];
540 real s = ((p0.x + c * p0.y) - (p.x + c * p.y))/2;
541 return p + XPoint(s, c*s);
542 }
543
544 Intersect::XPoint
545 Intersect::fixsegment(Math::real sx, Math::real sy,
546 const Intersect::XPoint& p) {
547 if (p.c == 0) return p;
548 // eq0: [p1x = px+s, p1y = py+f*s]$
549 // solx0:linsolve(cons(p1x=0 ,eq0),[s,p1x,p1y]);
550 // solx1:linsolve(cons(p1x=sx,eq0),[s,p1x,p1y]);
551 // soly0:linsolve(cons(p1y=0 ,eq0),[s,p1x,p1y]);
552 // soly1:linsolve(cons(p1y=sy,eq0),[s,p1x,p1y]);
553 // solx0:[s = -px ,p1x = 0 ,p1y = py-f*px ];
554 // solx1:[s = sx-px ,p1x = sx,p1y = py-f*(px-sx)];
555 // soly0:[s = -f*py ,p1x = px-f*py ,p1y = 0 ];
556 // soly1:[s = f*(sy-py),p1x = px-f*(py-sy),p1y = sy];
557 real
558 pya = p.y - p.c * p.x, sa = -p.x, // pxa = 0
559 pyb = p.y - p.c * (p.x-sx), sb = sx - p.x, // pxb = sx
560 pxc = p.x - p.c * p.y, sc = p.c * -p.y, // pyc = 0
561 pxd = p.x - p.c * (p.y-sy), sd = p.c * (sy - p.y); // pyd = sy
562 bool
563 ga = 0 <= pya && pya <= sy,
564 gb = 0 <= pyb && pyb <= sy,
565 gc = 0 <= pxc && pxc <= sx,
566 gd = 0 <= pxd && pxd <= sx;
567 real s;
568 // Test opposite sides of the rectangle first
569 if (ga && gb) s = (sa + sb) / 2;
570 else if (gc && gd) s = (sc + sd) / 2;
571 else if (ga && gc) s = (sa + sc) / 2;
572 else if (ga && gd) s = (sa + sd) / 2;
573 else if (gb && gc) s = (sb + sc) / 2;
574 else if (gb && gd) s = (sb + sd) / 2;
575 else {
576 // Intersection not within segments; place intersection in smallest gap.
577 if (p.c > 0) {
578 // distance from p to corner p0 is abs( (px - py) - (p0x - p0y) )
579 // consider corners p0 = [0, sy] and p0 = [sx, 0]
580 if (fabs((p.x - p.y) + sy) < fabs((p.x - p.y) - sx))
581 s = (sy - (p.x + p.y))/2;
582 else
583 s = (sx - (p.x + p.y))/2;
584 } else {
585 // distance from p to corner p0 is abs( (px + p.y) - (p0x + p0y) )
586 // consider corners p0 = [0, 0] and p0 = [sx, sy]
587 if (fabs(p.x + p.y) < fabs((p.x + p.y) - (sx + sy)))
588 s = (0 - (p.x - p.y))/2;
589 else
590 s = ((sx - sy) - (p.x - p.y))/2;
591 }
592 }
593 return p + XPoint(s, p.c*s);
594 }
595
596}
real
GeographicLib::Math::real real
Definition: GeodSolve.cpp:29
Intersect.hpp
Header for GeographicLib::Intersect class.
GEOGRAPHICLIB_PANIC
#define GEOGRAPHICLIB_PANIC
Definition: Math.hpp:62
GeographicLib::GeodesicLine
A geodesic line.
Definition: GeodesicLine.hpp:74
GeographicLib::GeodesicLine::Position
Math::real Position(real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Definition: GeodesicLine.hpp:298
GeographicLib::GeodesicLine::LATITUDE
@ LATITUDE
Definition: GeodesicLine.hpp:138
GeographicLib::GeodesicLine::GEODESICSCALE
@ GEODESICSCALE
Definition: GeodesicLine.hpp:177
GeographicLib::GeodesicLine::DISTANCE_IN
@ DISTANCE_IN
Definition: GeodesicLine.hpp:167
GeographicLib::GeodesicLine::REDUCEDLENGTH
@ REDUCEDLENGTH
Definition: GeodesicLine.hpp:172
GeographicLib::Geodesic
Geodesic calculations
Definition: Geodesic.hpp:175
GeographicLib::Geodesic::InverseLine
GeodesicLine InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps=ALL) const
Definition: Geodesic.cpp:533
GeographicLib::Geodesic::Line
GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Definition: Geodesic.cpp:124
GeographicLib::Geodesic::Inverse
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:691
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition: Constants.hpp:316
GeographicLib::Intersect::Segment
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
GeographicLib::Intersect::LineCaps
static const unsigned LineCaps
Definition: Intersect.hpp:83
GeographicLib::Intersect::Closest
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
GeographicLib::Intersect::Point
std::pair< Math::real, Math::real > Point
Definition: Intersect.hpp:78
GeographicLib::Intersect::All
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
Definition: Intersect.cpp:115
GeographicLib::Intersect::Next
Point Next(Math::real latX, Math::real lonX, Math::real aziX, Math::real aziY, int *c=nullptr) const
Definition: Intersect.cpp:91
GeographicLib::Intersect::Intersect
Intersect(const Geodesic &geod)
Definition: Intersect.cpp:20
GeographicLib::Math
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:77
GeographicLib::Math::infinity
static T infinity()
Definition: Math.cpp:262
GeographicLib::Math::sincosde
static void sincosde(T x, T t, T &sinx, T &cosx)
Definition: Math.cpp:126
GeographicLib::Math::pi
static T pi()
Definition: Math.hpp:183
GeographicLib::Math::AngDiff
static T AngDiff(T x, T y, T &e)
Definition: Math.cpp:82
GeographicLib::Math::real
double real
Definition: Math.hpp:100
GeographicLib
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
std
Definition: NearestNeighbor.hpp:812
std::swap
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
Definition: NearestNeighbor.hpp:825