GeographicLib  2.6
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 
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  , _rR(sqrt(_geod.EllipsoidArea() / (4 * Math::pi())))
25  , _d(_rR * 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 
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 
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 
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 
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 
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 
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>
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>
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/_rR), cosz = cos(z/_rR);
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 * _rR) {
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 = _rR * atan2(sinY * sinz, sinY * cosX * cosz - cosY * sinX);
185  sY = _rR * 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;
197  n < numit_ ||
198  GEOGRAPHICLIB_PANIC("Convergence failure in Intersect");
199  ++n) {
200  ++_cnt0;
201  XPoint dq = Spherical(lineX, lineY, q);
202  q += dq;
203  if (q.c || !(dq.Dist() > _tol)) break; // break if nan
204  }
205  return q;
206  }
207 
208  Intersect::XPoint
209  Intersect::ClosestInt(const GeodesicLine& lineX, const GeodesicLine& lineY,
210  const Intersect::XPoint& p0) const {
211  const int num = 5;
212  const int ix[num] = { 0, 1, -1, 0, 0 };
213  const int iy[num] = { 0, 0, 0, 1, -1 };
214  bool skip[num] = { 0, 0, 0, 0, 0 };
215  XPoint q; // Best intersection so far
216  for (int n = 0; n < num; ++n) {
217  if (skip[n]) continue;
218  XPoint qx = Basic(lineX, lineY, p0 + XPoint(ix[n] * _d1, iy[n] * _d1));
219  qx = fixcoincident(p0, qx);
220  if (_comp.eq(q, qx)) continue;
221  if (qx.Dist(p0) < _t1) { q = qx; ++_cnt2; break; }
222  if (n == 0 || qx.Dist(p0) < q.Dist(p0)) { q = qx; ++_cnt2; }
223  for (int m = n + 1; m < num; ++m)
224  skip[m] = skip[m] ||
225  qx.Dist(p0 + XPoint(ix[m]*_d1, iy[m]*_d1)) < 2*_t1 - _d1 - _delta;
226  }
227  return q;
228  }
229 
230  Intersect::XPoint
231  Intersect::NextInt(const GeodesicLine& lineX, const GeodesicLine& lineY)
232  const {
233  const int num = 8;
234  const int ix[num] = { -1, -1, 1, 1, -2, 0, 2, 0 };
235  const int iy[num] = { -1, 1, -1, 1, 0, 2, 0, -2 };
236  bool skip[num] = { 0, 0, 0, 0, 0, 0, 0, 0 };
237  XPoint z(0,0), // for excluding the origin
238  q(Math::infinity(), 0); // Best intersection so far
239  for (int n = 0; n < num; ++n) {
240  if (skip[n]) continue;
241  XPoint qx = Basic(lineX, lineY, XPoint(ix[n] * _d2, iy[n] * _d2));
242  qx = fixcoincident(z, qx);
243  bool zerop = _comp.eq(z, qx);
244  if (qx.c == 0 && zerop) continue;
245  if (qx.c && zerop) {
246  for (int sgn = -1; sgn <= 1; sgn+=2) {
247  real s = ConjugateDist(lineX, sgn * _d, false);
248  XPoint qa(s, qx.c*s, qx.c);
249  if (qa.Dist() < q.Dist()) { q = qa; ++_cnt2; }
250  }
251  } else {
252  if (qx.Dist() < q.Dist()) { q = qx; ++_cnt2; }
253  }
254  for (int sgn = -1; sgn <= 1; ++sgn) {
255  // if qx.c == 0 only process sgn == 0
256  // if zerop skip sgn == 0
257  if ((qx.c == 0 && sgn != 0) || (zerop && sgn == 0)) continue;
258  XPoint qy = qx.c ? qx + Point(sgn * _d2, qx.c * sgn *_d2) : qx;
259  for (int m = n + 1; m < num; ++m)
260  skip[m] = skip[m] ||
261  qy.Dist(XPoint(ix[m]*_d2, iy[m]*_d2)) < 2*_t1 - _d2 - _delta;
262  }
263  }
264  return q;
265  }
266 
267  Intersect::XPoint
268  Intersect::SegmentInt(const GeodesicLine& lineX, const GeodesicLine& lineY,
269  int& segmode) const {
270  // The conjecture is that whenever two geodesic segments intersect, the
271  // intersection is the one that is closest to the midpoints of segments.
272  // If this is proven, set conjectureproved to true.
273  const bool conjectureproved = false;
274  real sx = lineX.Distance(), sy = lineY.Distance();
275  // p0 is center of [sx,sy] rectangle, q is intersection closest to p0
276  XPoint p0 = XPoint(sx/2, sy/2), q = ClosestInt(lineX, lineY, p0);
277  q = fixsegment(sx, sy, q);
278  segmode = segmentmode(sx, sy, q);
279  // Are corners of [sx,sy] rectangle further from p0 than q?
280  if (!conjectureproved && segmode != 0 && p0.Dist() >= p0.Dist(q)) {
281  int segmodex = 1;
282  XPoint qx;
283  // Cycle through 4 corners of [sx,sy] rectangle
284  for (int ix = 0; ix < 2 && segmodex != 0; ++ix) {
285  for (int iy = 0; iy < 2 && segmodex != 0; ++iy) {
286  XPoint t(ix * sx, iy * sy); // corner point
287  // Is corner outside next intersection exclusion circle?
288  if (q.Dist(t) >= 2 * _t1) {
289  ++_cnt3;
290  qx = Basic(lineX, lineY, t);
291  // fixsegment is not needed because the coincidence line must just
292  // slice off a corner of the sx x sy rectangle.
293  qx = fixcoincident(t, qx);
294  // No need to check if equal to q, because result is only accepted
295  // if segmode != 0 && segmodex == 0.
296  segmodex = segmentmode(sx, sy, qx);
297  }
298  }
299  }
300  if (segmodex == 0) { ++_cnt4; segmode = 0; q = qx; }
301  }
302  return q;
303  }
304 
305  std::vector<Intersect::XPoint>
306  Intersect::AllInt0(const GeodesicLine& lineX,
307  const GeodesicLine& lineY,
308  Math::real maxdist, const XPoint& p0) const {
309  real maxdistx = maxdist + _delta;
310  const int m = int(ceil(maxdistx / _d3)), // process m x m set of tiles
311  m2 = m*m + (m - 1) % 2, // add center tile if m is even
312  n = m - 1; // Range of i, j = [-n:2:n]
313  real d3 = maxdistx/m; // d3 <= _d3
314  vector<XPoint> start(m2);
315  vector<bool> skip(m2, false);
316  int h = 0, c0 = 0;
317  start[h++] = p0;
318  for (int i = -n; i <= n; i += 2)
319  for (int j = -n; j <= n; j += 2) {
320  if (!(i == 0 && j == 0))
321  start[h++] = p0 + XPoint( d3 * (i + j) / 2, d3 * (i - j) / 2);
322  }
323  // assert(h == m2);
324  set<XPoint, SetComp> r(_comp); // Intersections found
325  set<XPoint, SetComp> c(_comp); // Closest coincident intersections
326  vector<XPoint> added;
327  for (int k = 0; k < m2; ++k) {
328  if (skip[k]) continue;
329  XPoint q = Basic(lineX, lineY, start[k]);
330  if (r.find(q) != r.end() // intersection already found
331  // or it's on a line of coincident intersections already processed
332  || (c0 != 0 && c.find(fixcoincident(p0, q)) != c.end()))
333  continue;
334  added.clear();
335  if (q.c != 0) {
336  // This value of q.c must be constitent with c0
337  // assert(c0 == 0 || c0 == q.c);
338  c0 = q.c;
339  // Process coincident intersections
340  q = fixcoincident(p0, q);
341  c.insert(q);
342  // Elimate all existing intersections on this line (which
343  // didn't set c0).
344  for (auto qp = r.begin(); qp != r.end(); ) {
345  if (_comp.eq(fixcoincident(p0, *qp, c0), q)) {
346  qp = r.erase(qp);
347  }
348  else
349  ++qp;
350  }
351  real s0 = q.x;
352  XPoint qc;
353  real t, m12, M12, M21;
354  lineX.GenPosition(false, s0,
357  t, t, t, t, m12, M12, M21, t);
358  // Compute line of conjugate points
359  for (int sgn = -1; sgn <= 1; sgn += 2) {
360  real sa = 0;
361  do {
362  sa = ConjugateDist(lineX, s0 + sa + sgn*_d, false, m12, M12, M21)
363  - s0;
364  qc = q + XPoint(sa, c0*sa);
365  added.push_back(qc);
366  r.insert(qc);
367  } while (qc.Dist(p0) <= maxdistx);
368  }
369  }
370  added.push_back(q);
371  r.insert(q);
372  for (auto qp = added.cbegin(); qp != added.cend(); ++qp) {
373  for (int l = k + 1; l < m2; ++l)
374  skip[l] = skip[l] || qp->Dist(start[l]) < 2*_t1 - d3 - _delta;
375  }
376  }
377  // Trim intersections to maxdist
378  for (auto qp = r.begin(); qp != r.end(); ) {
379  if (!(qp->Dist(p0) <= maxdist))
380  qp = r.erase(qp);
381  else
382  ++qp;
383  }
384  vector<XPoint> v(r.size());
385  int i = 0;
386  for (auto p = r.cbegin(); p != r.cend(); ++p)
387  v[i++] = *p;
388  sort(v.begin(), v.end(), RankPoint(p0));
389  return v;
390  }
391 
392  std::vector<Intersect::Point>
393  Intersect::AllInternal(const GeodesicLine& lineX, const GeodesicLine& lineY,
394  Math::real maxdist, const Point& p0,
395  std::vector<int>& c, bool cp) const {
396  const vector<XPoint>
397  v = AllInt0(lineX, lineY, fmax(real(0), maxdist), XPoint(p0));
398  int i = int(v.size());
399  vector<Point> u(i);
400  if (cp) c.resize(i);
401  for (int j = 0; j < i; ++j) {
402  u[j] = v[j].data();
403  if (cp) c[j] = v[j].c;
404  }
405  return u;
406  }
407 
408  Math::real Intersect::distpolar(Math::real lat1, Math::real* lat2)
409  const {
410  GeodesicLine line = _geod.Line(lat1, 0, 0,
414  real s = ConjugateDist(line, (1 + _f/2) * _a * Math::pi() / 2, true);
415  if (lat2) {
416  real t;
417  line.GenPosition(false, s, GeodesicLine::LATITUDE,
418  *lat2, t, t, t, t, t, t, t);
419  }
420  return s;
421  }
422 
423  Math::real Intersect::polarb(Math::real* lata, Math::real* latb) const {
424  if (_f == 0) {
425  if (lata) *lata = 64;
426  if (latb) *latb = 90-64;
427  return _d;
428  }
429  real
430  lat0 = 63, s0 = distpolar(lat0),
431  lat1 = 65, s1 = distpolar(lat1),
432  lat2 = 64, s2 = distpolar(lat2),
433  latx = lat2, sx = s2;
434  // Solve for ds(lat)/dlat = 0 with a quadratic fit
435  for (int i = 0; i < 10; ++i) {
436  real den = (lat1-lat0)*s2 + (lat0-lat2)*s1 + (lat2-lat1)*s0;
437  if (!(den < 0 || den > 0)) break; // Break if nan
438  real latn = ((lat1-lat0)*(lat1+lat0)*s2 + (lat0-lat2)*(lat0+lat2)*s1 +
439  (lat2-lat1)*(lat2+lat1)*s0) / (2*den);
440  lat0 = lat1; s0 = s1;
441  lat1 = lat2; s1 = s2;
442  lat2 = latn; s2 = distpolar(lat2);
443  if (_f < 0 ? (s2 < sx) : (s2 > sx)) {
444  sx = s2;
445  latx = lat2;
446  }
447  }
448  if (lata) *lata = latx;
449  if (latb) distpolar(latx, latb);
450  return 2 * sx;
451  }
452 
453  // Find {semi-,}conjugate point relative to s0 which is close to s1.
454  Math::real Intersect::ConjugateDist(const GeodesicLine& line, Math::real s3,
455  bool semi, Math::real m12,
456  Math::real M12, Math::real M21) const {
457  // semi = false: solve for m23 = 0 using dm23/ds3 = M32
458  // semi = true : solve for M23 = 0 using dM23/ds3 = - (1 - M23*M32)/m23
459  // Here 2 is point with given m12, M12, M21 and default values s.t. point 2
460  // = point 1.
461  real s = s3;
462  for (int i = 0; i < 100; ++i) {
463  real t, m13, M13, M31;
464  line.GenPosition(false, s,
467  t, t, t, t, m13, M13, M31, t);
468  real
469  // See "Algorithms for geodesics", eqs. 31, 32, 33.
470  m23 = m13 * M12 - m12 * M13,
471  // when m12 -> eps, (1 - M12 * M21) -> eps^2, I suppose.
472  M23 = M13 * M21 + (m12 == 0 ? 0 : (1 - M12 * M21) * m13/m12),
473  M32 = M31 * M12 + (m13 == 0 ? 0 : (1 - M13 * M31) * m12/m13);
474  real ds = semi ? m23 * M23 / (1 - M23*M32) : -m23 / M32;
475  s = s + ds;
476  if (!(fabs(ds) > _tol)) break;
477  }
478  return s;
479  }
480 
481  Math::real Intersect::conjdist(Math::real azi,
482  Math::real* ds,
483  Math::real* sp, Math::real* sm) const {
484  GeodesicLine line = _geod.Line(0, 0, azi, LineCaps);
485  real s = ConjugateDist(line, _d, false);
486  if (ds) {
487  XPoint p = Basic(line, line, XPoint(s/2, -3*s/2));
488  if (sp) *sp = p.x;
489  if (sm) *sm = p.y;
490  *ds = p.Dist() - 2*s;
491  }
492  return s;
493  }
494 
495  Math::real Intersect::distoblique(Math::real* azi,
496  Math::real* sp,
497  Math::real* sm) const {
498  if (_f == 0) {
499  if (azi) *azi = 45;
500  if (sp) *sp = 0.5;
501  if (sm) *sm = -1.5;
502  return _d;
503  }
504  real sa, sb,
505  azi0 = 46, ds0, s0 = conjdist(azi0, &ds0, &sa, &sb),
506  azi1 = 44, ds1, s1 = conjdist(azi1, &ds1, &sa, &sb),
507  azix = azi1, dsx = fabs(ds1), sx = s1, sax = sa, sbx = sb;
508  // find ds(azi) = 0 by secant method
509  (void) s0;
510  for (int i = 0; i < 10 && ds1 != ds0; ++i) {
511  real azin = (azi0*ds1-azi1*ds0)/(ds1-ds0);
512  azi0 = azi1; s0 = s1; ds0 = ds1;
513  azi1 = azin; s1 = conjdist(azi1, &ds1, &sa, &sb);
514  if (fabs(ds1) < dsx) {
515  azix = azi1, sx = s1, dsx = fabs(ds1);
516  sax = sa; sbx = sb;
517  if (ds1 == 0) break;
518  }
519  }
520  if (azi) *azi = azix;
521  if (sp) *sp = sax;
522  if (sm) *sm = sbx;
523  return sx;
524  }
525 
526  Intersect::XPoint
527  Intersect::fixcoincident(const Intersect::XPoint& p0,
528  const Intersect::XPoint& p) {
529  return fixcoincident(p0, p, p.c);
530  }
531 
532  Intersect::XPoint
533  Intersect::fixcoincident(const Intersect::XPoint& p0,
534  const Intersect::XPoint& p, int c) {
535  if (c == 0) return p;
536  // eqs : [p0x-p1x = -c*(p0y-p1y), p1x = px+s, p1y = py+c*s]$
537  // sol : solve(eqs,[s,p1x,p1y]);
538  // =>
539  // sol:[ s = ((p0x+c*p0y) - (px+c*py))/2,
540  // p1x = px + ((p0x+c*p0y) - (px+c*py))/2,
541  // p1y = py + c * ((p0x+c*p0y) - (px+c*py))/2
542  // ];
543  real s = ((p0.x + c * p0.y) - (p.x + c * p.y))/2;
544  return p + XPoint(s, c*s);
545  }
546 
547  Intersect::XPoint
548  Intersect::fixsegment(Math::real sx, Math::real sy,
549  const Intersect::XPoint& p) {
550  if (p.c == 0) return p;
551  // eq0: [p1x = px+s, p1y = py+f*s]$
552  // solx0:linsolve(cons(p1x=0 ,eq0),[s,p1x,p1y]);
553  // solx1:linsolve(cons(p1x=sx,eq0),[s,p1x,p1y]);
554  // soly0:linsolve(cons(p1y=0 ,eq0),[s,p1x,p1y]);
555  // soly1:linsolve(cons(p1y=sy,eq0),[s,p1x,p1y]);
556  // solx0:[s = -px ,p1x = 0 ,p1y = py-f*px ];
557  // solx1:[s = sx-px ,p1x = sx,p1y = py-f*(px-sx)];
558  // soly0:[s = -f*py ,p1x = px-f*py ,p1y = 0 ];
559  // soly1:[s = f*(sy-py),p1x = px-f*(py-sy),p1y = sy];
560  real
561  pya = p.y - p.c * p.x, sa = -p.x, // pxa = 0
562  pyb = p.y - p.c * (p.x-sx), sb = sx - p.x, // pxb = sx
563  pxc = p.x - p.c * p.y, sc = p.c * -p.y, // pyc = 0
564  pxd = p.x - p.c * (p.y-sy), sd = p.c * (sy - p.y); // pyd = sy
565  bool
566  ga = 0 <= pya && pya <= sy,
567  gb = 0 <= pyb && pyb <= sy,
568  gc = 0 <= pxc && pxc <= sx,
569  gd = 0 <= pxd && pxd <= sx;
570  real s;
571  // Test opposite sides of the rectangle first
572  if (ga && gb) s = (sa + sb) / 2;
573  else if (gc && gd) s = (sc + sd) / 2;
574  else if (ga && gc) s = (sa + sc) / 2;
575  else if (ga && gd) s = (sa + sd) / 2;
576  else if (gb && gc) s = (sb + sc) / 2;
577  else if (gb && gd) s = (sb + sd) / 2;
578  else {
579  // Intersection not within segments; place intersection in smallest gap.
580  if (p.c > 0) {
581  // distance from p to corner p0 is abs( (px - py) - (p0x - p0y) )
582  // consider corners p0 = [0, sy] and p0 = [sx, 0]
583  if (fabs((p.x - p.y) + sy) < fabs((p.x - p.y) - sx))
584  s = (sy - (p.x + p.y))/2;
585  else
586  s = (sx - (p.x + p.y))/2;
587  } else {
588  // distance from p to corner p0 is abs( (px + p.y) - (p0x + p0y) )
589  // consider corners p0 = [0, 0] and p0 = [sx, sy]
590  if (fabs(p.x + p.y) < fabs((p.x + p.y) - (sx + sy)))
591  s = (0 - (p.x - p.y))/2;
592  else
593  s = ((sx - sy) - (p.x - p.y))/2;
594  }
595  }
596  return p + XPoint(s, p.c*s);
597  }
598 
599 }
static T pi()
Definition: Math.hpp:187
static const unsigned LineCaps
Definition: Intersect.hpp:84
std::pair< Math::real, Math::real > Point
Definition: Intersect.hpp:79
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
GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps=ALL) const
Definition: Geodesic.cpp:123
static T infinity()
Definition: Math.cpp:308
Math::real Position(real s12, real &lat2, real &lon2, real &azi2, real &m12, real &M12, real &M21, real &S12) const
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:82
GeodesicLine InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps=ALL) const
Definition: Geodesic.cpp:523
static void sincosde(T x, T t, T &sinx, T &cosx)
Definition: Math.cpp:131
Point Next(Math::real latX, Math::real lonX, Math::real aziX, Math::real aziY, int *c=nullptr) const
Definition: Intersect.cpp:91
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
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
Header for GeographicLib::Intersect class.
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static T AngDiff(T x, T y, T &e)
Definition: Math.cpp:80
GeographicLib::Math::real real
Definition: Geod3Solve.cpp:25
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
#define GEOGRAPHICLIB_PANIC(msg)
Definition: Math.hpp:67
Exception handling for GeographicLib.
Definition: Constants.hpp:344
Geodesic calculations
Definition: Geodesic.hpp:175
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