• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.geometry;
18 
19 import com.google.common.base.Preconditions;
20 
21 /**
22  * This class contains various utility functions related to edges. It collects
23  * together common code that is needed to implement polygonal geometry such as
24  * polylines, loops, and general polygons.
25  *
26  */
27 public strictfp class S2EdgeUtil {
28   /**
29    * IEEE floating-point operations have a maximum error of 0.5 ULPS (units in
30    * the last place). For double-precision numbers, this works out to 2**-53
31    * (about 1.11e-16) times the magnitude of the result. It is possible to
32    * analyze the calculation done by getIntersection() and work out the
33    * worst-case rounding error. I have done a rough version of this, and my
34    * estimate is that the worst case distance from the intersection point X to
35    * the great circle through (a0, a1) is about 12 ULPS, or about 1.3e-15. This
36    * needs to be increased by a factor of (1/0.866) to account for the
37    * edgeSpliceFraction() in S2PolygonBuilder. Note that the maximum error
38    * measured by the unittest in 1,000,000 trials is less than 3e-16.
39    */
40   public static final S1Angle DEFAULT_INTERSECTION_TOLERANCE = S1Angle.radians(1.5e-15);
41 
42   /**
43    * This class allows a vertex chain v0, v1, v2, ... to be efficiently tested
44    * for intersection with a given fixed edge AB.
45    */
46   public static class EdgeCrosser {
47     // The fields below are all constant.
48 
49     private final S2Point a;
50     private final S2Point b;
51     private final S2Point aCrossB;
52 
53     // The fields below are updated for each vertex in the chain.
54 
55     // Previous vertex in the vertex chain.
56     private S2Point c;
57     // The orientation of the triangle ACB.
58     private int acb;
59 
60     /**
61      * AB is the given fixed edge, and C is the first vertex of the vertex
62      * chain. All parameters must point to fixed storage that persists for the
63      * lifetime of the EdgeCrosser object.
64      */
EdgeCrosser(S2Point a, S2Point b, S2Point c)65     public EdgeCrosser(S2Point a, S2Point b, S2Point c) {
66       this.a = a;
67       this.b = b;
68       this.aCrossB = S2Point.crossProd(a, b);
69       restartAt(c);
70     }
71 
72     /**
73      * Call this function when your chain 'jumps' to a new place.
74      */
restartAt(S2Point c)75     public void restartAt(S2Point c) {
76       this.c = c;
77       acb = -S2.robustCCW(a, b, c, aCrossB);
78     }
79 
80     /**
81      * This method is equivalent to calling the S2EdgeUtil.robustCrossing()
82      * function (defined below) on the edges AB and CD. It returns +1 if there
83      * is a crossing, -1 if there is no crossing, and 0 if two points from
84      * different edges are the same. Returns 0 or -1 if either edge is
85      * degenerate. As a side effect, it saves vertex D to be used as the next
86      * vertex C.
87      */
robustCrossing(S2Point d)88     public int robustCrossing(S2Point d) {
89       // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must
90       // all be oriented the same way (CW or CCW). We keep the orientation
91       // of ACB as part of our state. When each new point D arrives, we
92       // compute the orientation of BDA and check whether it matches ACB.
93       // This checks whether the points C and D are on opposite sides of the
94       // great circle through AB.
95 
96       // Recall that robustCCW is invariant with respect to rotating its
97       // arguments, i.e. ABC has the same orientation as BDA.
98       int bda = S2.robustCCW(a, b, d, aCrossB);
99       int result;
100 
101       if (bda == -acb && bda != 0) {
102         // Most common case -- triangles have opposite orientations.
103         result = -1;
104       } else if ((bda & acb) == 0) {
105         // At least one value is zero -- two vertices are identical.
106         result = 0;
107       } else {
108         // assert (bda == acb && bda != 0);
109         result = robustCrossingInternal(d); // Slow path.
110       }
111       // Now save the current vertex D as the next vertex C, and also save the
112       // orientation of the new triangle ACB (which is opposite to the current
113       // triangle BDA).
114       c = d;
115       acb = -bda;
116       return result;
117     }
118 
119     /**
120      * This method is equivalent to the S2EdgeUtil.edgeOrVertexCrossing() method
121      * defined below. It is similar to robustCrossing, but handles cases where
122      * two vertices are identical in a way that makes it easy to implement
123      * point-in-polygon containment tests.
124      */
edgeOrVertexCrossing(S2Point d)125     public boolean edgeOrVertexCrossing(S2Point d) {
126       // We need to copy c since it is clobbered by robustCrossing().
127       S2Point c2 = new S2Point(c.get(0), c.get(1), c.get(2));
128 
129       int crossing = robustCrossing(d);
130       if (crossing < 0) {
131         return false;
132       }
133       if (crossing > 0) {
134         return true;
135       }
136 
137       return vertexCrossing(a, b, c2, d);
138     }
139 
140     /**
141      * This function handles the "slow path" of robustCrossing().
142      */
robustCrossingInternal(S2Point d)143     private int robustCrossingInternal(S2Point d) {
144       // ACB and BDA have the appropriate orientations, so now we check the
145       // triangles CBD and DAC.
146       S2Point cCrossD = S2Point.crossProd(c, d);
147       int cbd = -S2.robustCCW(c, d, b, cCrossD);
148       if (cbd != acb) {
149         return -1;
150       }
151 
152       int dac = S2.robustCCW(c, d, a, cCrossD);
153       return (dac == acb) ? 1 : -1;
154     }
155   }
156 
157   /**
158    * This class computes a bounding rectangle that contains all edges defined by
159    * a vertex chain v0, v1, v2, ... All vertices must be unit length. Note that
160    * the bounding rectangle of an edge can be larger than the bounding rectangle
161    * of its endpoints, e.g. consider an edge that passes through the north pole.
162    */
163   public static class RectBounder {
164     // The previous vertex in the chain.
165     private S2Point a;
166 
167     // The corresponding latitude-longitude.
168     private S2LatLng aLatLng;
169 
170     // The current bounding rectangle.
171     private S2LatLngRect bound;
172 
RectBounder()173     public RectBounder() {
174       this.bound = S2LatLngRect.empty();
175     }
176 
177     /**
178      * This method is called to add each vertex to the chain. 'b' must point to
179      * fixed storage that persists for the lifetime of the RectBounder.
180      */
addPoint(S2Point b)181     public void addPoint(S2Point b) {
182       // assert (S2.isUnitLength(b));
183 
184       S2LatLng bLatLng = new S2LatLng(b);
185 
186       if (bound.isEmpty()) {
187         bound = bound.addPoint(bLatLng);
188       } else {
189         // We can't just call bound.addPoint(bLatLng) here, since we need to
190         // ensure that all the longitudes between "a" and "b" are included.
191         bound = bound.union(S2LatLngRect.fromPointPair(aLatLng, bLatLng));
192 
193         // Check whether the min/max latitude occurs in the edge interior.
194         // We find the normal to the plane containing AB, and then a vector
195         // "dir" in this plane that also passes through the equator. We use
196         // RobustCrossProd to ensure that the edge normal is accurate even
197         // when the two points are very close together.
198         S2Point aCrossB = S2.robustCrossProd(a, b);
199         S2Point dir = S2Point.crossProd(aCrossB, new S2Point(0, 0, 1));
200         double da = dir.dotProd(a);
201         double db = dir.dotProd(b);
202 
203         if (da * db < 0) {
204           // Minimum/maximum latitude occurs in the edge interior. This affects
205           // the latitude bounds but not the longitude bounds.
206           double absLat = Math.acos(Math.abs(aCrossB.get(2) / aCrossB.norm()));
207           R1Interval lat = bound.lat();
208           if (da < 0) {
209             // It's possible that absLat < lat.lo() due to numerical errors.
210             lat = new R1Interval(lat.lo(), Math.max(absLat, bound.lat().hi()));
211           } else {
212             lat = new R1Interval(Math.min(-absLat, bound.lat().lo()), lat.hi());
213           }
214           bound = new S2LatLngRect(lat, bound.lng());
215         }
216       }
217       a = b;
218       aLatLng = bLatLng;
219     }
220 
221     /**
222      * Return the bounding rectangle of the edge chain that connects the
223      * vertices defined so far.
224      */
getBound()225     public S2LatLngRect getBound() {
226       return bound;
227     }
228 
229   }
230 
231   /**
232    * The purpose of this class is to find edges that intersect a given XYZ
233    * bounding box. It can be used as an efficient rejection test when attempting to
234    * find edges that intersect a given region. It accepts a vertex chain v0, v1,
235    * v2, ... and returns a boolean value indicating whether each edge intersects
236    * the specified bounding box.
237    *
238    * We use XYZ intervals instead of something like longitude intervals because
239    * it is cheap to collect from S2Point lists and any slicing strategy should
240    * give essentially equivalent results.  See S2Loop for an example of use.
241    */
242   public static class XYZPruner {
243     private S2Point lastVertex;
244 
245     // The region to be tested against.
246     private boolean boundSet;
247     private double xmin;
248     private double ymin;
249     private double zmin;
250     private double xmax;
251     private double ymax;
252     private double zmax;
253     private double maxDeformation;
254 
XYZPruner()255     public XYZPruner() {
256       boundSet = false;
257     }
258 
259     /**
260      * Accumulate a bounding rectangle from provided edges.
261      *
262      * @param from start of edge
263      * @param to end of edge.
264      */
addEdgeToBounds(S2Point from, S2Point to)265     public void addEdgeToBounds(S2Point from, S2Point to) {
266       if (!boundSet) {
267         boundSet = true;
268         xmin = xmax = from.x;
269         ymin = ymax = from.y;
270         zmin = zmax = from.z;
271       }
272       xmin = Math.min(xmin, Math.min(to.x, from.x));
273       ymin = Math.min(ymin, Math.min(to.y, from.y));
274       zmin = Math.min(zmin, Math.min(to.z, from.z));
275       xmax = Math.max(xmax, Math.max(to.x, from.x));
276       ymax = Math.max(ymax, Math.max(to.y, from.y));
277       zmax = Math.max(zmax, Math.max(to.z, from.z));
278 
279       // Because our arcs are really geodesics on the surface of the earth
280       // an edge can have intermediate points outside the xyz bounds implicit
281       // in the end points.  Based on the length of the arc we compute a
282       // generous bound for the maximum amount of deformation.  For small edges
283       // it will be very small but for some large arcs (ie. from (1N,90W) to
284       // (1N,90E) the path can be wildly deformed.  I did a bunch of
285       // experiments with geodesics to get safe bounds for the deformation.
286       double approxArcLen =
287           Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z);
288       if (approxArcLen < 0.025) { // less than 2 degrees
289         maxDeformation = Math.max(maxDeformation, approxArcLen * 0.0025);
290       } else if (approxArcLen < 1.0) { // less than 90 degrees
291         maxDeformation = Math.max(maxDeformation, approxArcLen * 0.11);
292       } else {
293         maxDeformation = approxArcLen * 0.5;
294       }
295     }
296 
setFirstIntersectPoint(S2Point v0)297     public void setFirstIntersectPoint(S2Point v0) {
298       xmin = xmin - maxDeformation;
299       ymin = ymin - maxDeformation;
300       zmin = zmin - maxDeformation;
301       xmax = xmax + maxDeformation;
302       ymax = ymax + maxDeformation;
303       zmax = zmax + maxDeformation;
304       this.lastVertex = v0;
305     }
306 
307     /**
308      * Returns true if the edge going from the last point to this point passes
309      * through the pruner bounding box, otherwise returns false.  So the
310      * method returns false if we are certain there is no intersection, but it
311      * may return true when there turns out to be no intersection.
312      */
intersects(S2Point v1)313     public boolean intersects(S2Point v1) {
314       boolean result = true;
315 
316       if ((v1.x < xmin && lastVertex.x < xmin) || (v1.x > xmax && lastVertex.x > xmax)) {
317         result = false;
318       } else if ((v1.y < ymin && lastVertex.y < ymin) || (v1.y > ymax && lastVertex.y > ymax)) {
319         result = false;
320       } else if ((v1.z < zmin && lastVertex.z < zmin) || (v1.z > zmax && lastVertex.z > zmax)) {
321         result = false;
322       }
323 
324       lastVertex = v1;
325       return result;
326     }
327   }
328 
329   /**
330    * The purpose of this class is to find edges that intersect a given longitude
331    * interval. It can be used as an efficient rejection test when attempting to
332    * find edges that intersect a given region. It accepts a vertex chain v0, v1,
333    * v2, ... and returns a boolean value indicating whether each edge intersects
334    * the specified longitude interval.
335    *
336    * This class is not currently used as the XYZPruner is preferred for
337    * S2Loop, but this should be usable in similar circumstances.  Be wary
338    * of the cost of atan2() in conversions from S2Point to longitude!
339    */
340   public static class LongitudePruner {
341     // The interval to be tested against.
342     private S1Interval interval;
343 
344     // The longitude of the next v0.
345     private double lng0;
346 
347     /**
348      *'interval' is the longitude interval to be tested against, and 'v0' is
349      * the first vertex of edge chain.
350      */
LongitudePruner(S1Interval interval, S2Point v0)351     public LongitudePruner(S1Interval interval, S2Point v0) {
352       this.interval = interval;
353       this.lng0 = S2LatLng.longitude(v0).radians();
354     }
355 
356     /**
357      * Returns true if the edge (v0, v1) intersects the given longitude
358      * interval, and then saves 'v1' to be used as the next 'v0'.
359      */
intersects(S2Point v1)360     public boolean intersects(S2Point v1) {
361       double lng1 = S2LatLng.longitude(v1).radians();
362       boolean result = interval.intersects(S1Interval.fromPointPair(lng0, lng1));
363       lng0 = lng1;
364       return result;
365     }
366   }
367 
368   /**
369    * A wedge relation's test method accepts two edge chains A=(a0,a1,a2) and
370    * B=(b0,b1,b2) where a1==b1, and returns either -1, 0, or 1 to indicate the
371    * relationship between the region to the left of A and the region to the left
372    * of B. Wedge relations are used to determine the local relationship between
373    * two polygons that share a common vertex.
374    *
375    *  All wedge relations require that a0 != a2 and b0 != b2. Other degenerate
376    * cases (such as a0 == b2) are handled as expected. The parameter "ab1"
377    * denotes the common vertex a1 == b1.
378    */
379   public interface WedgeRelation {
test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)380     int test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2);
381   }
382 
383   public static class WedgeContains implements WedgeRelation {
384     /**
385      * Given two edge chains (see WedgeRelation above), this function returns +1
386      * if the region to the left of A contains the region to the left of B, and
387      * 0 otherwise.
388      */
389     @Override
test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)390     public int test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2) {
391       // For A to contain B (where each loop interior is defined to be its left
392       // side), the CCW edge order around ab1 must be a2 b2 b0 a0. We split
393       // this test into two parts that test three vertices each.
394       return S2.orderedCCW(a2, b2, b0, ab1) && S2.orderedCCW(b0, a0, a2, ab1) ? 1 : 0;
395     }
396   }
397 
398   public static class WedgeIntersects implements WedgeRelation {
399     /**
400      * Given two edge chains (see WedgeRelation above), this function returns -1
401      * if the region to the left of A intersects the region to the left of B,
402      * and 0 otherwise. Note that regions are defined such that points along a
403      * boundary are contained by one side or the other, not both. So for
404      * example, if A,B,C are distinct points ordered CCW around a vertex O, then
405      * the wedges BOA, AOC, and COB do not intersect.
406      */
407     @Override
test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)408     public int test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2) {
409       // For A not to intersect B (where each loop interior is defined to be
410       // its left side), the CCW edge order around ab1 must be a0 b2 b0 a2.
411       // Note that it's important to write these conditions as negatives
412       // (!OrderedCCW(a,b,c,o) rather than Ordered(c,b,a,o)) to get correct
413       // results when two vertices are the same.
414       return (S2.orderedCCW(a0, b2, b0, ab1) && S2.orderedCCW(b0, a2, a0, ab1) ? 0 : -1);
415     }
416   }
417 
418   public static class WedgeContainsOrIntersects implements WedgeRelation {
419     /**
420      * Given two edge chains (see WedgeRelation above), this function returns +1
421      * if A contains B, 0 if A and B are disjoint, and -1 if A intersects but
422      * does not contain B.
423      */
424     @Override
test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)425     public int test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2) {
426       // This is similar to WedgeContainsOrCrosses, except that we want to
427       // distinguish cases (1) [A contains B], (3) [A and B are disjoint],
428       // and (2,4,5,6) [A intersects but does not contain B].
429 
430       if (S2.orderedCCW(a0, a2, b2, ab1)) {
431         // We are in case 1, 5, or 6, or case 2 if a2 == b2.
432         return S2.orderedCCW(b2, b0, a0, ab1) ? 1 : -1; // Case 1 vs. 2,5,6.
433       }
434       // We are in cases 2, 3, or 4.
435       if (!S2.orderedCCW(a2, b0, b2, ab1)) {
436         return 0; // Case 3.
437       }
438 
439       // We are in case 2 or 4, or case 3 if a2 == b0.
440       return (a2.equals(b0)) ? 0 : -1; // Case 3 vs. 2,4.
441     }
442   }
443 
444   public static class WedgeContainsOrCrosses implements WedgeRelation {
445     /**
446      * Given two edge chains (see WedgeRelation above), this function returns +1
447      * if A contains B, 0 if B contains A or the two wedges do not intersect,
448      * and -1 if the edge chains A and B cross each other (i.e. if A intersects
449      * both the interior and exterior of the region to the left of B). In
450      * degenerate cases where more than one of these conditions is satisfied,
451      * the maximum possible result is returned. For example, if A == B then the
452      * result is +1.
453      */
454     @Override
test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)455     public int test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2) {
456       // There are 6 possible edge orderings at a shared vertex (all
457       // of these orderings are circular, i.e. abcd == bcda):
458       //
459       // (1) a2 b2 b0 a0: A contains B
460       // (2) a2 a0 b0 b2: B contains A
461       // (3) a2 a0 b2 b0: A and B are disjoint
462       // (4) a2 b0 a0 b2: A and B intersect in one wedge
463       // (5) a2 b2 a0 b0: A and B intersect in one wedge
464       // (6) a2 b0 b2 a0: A and B intersect in two wedges
465       //
466       // In cases (4-6), the boundaries of A and B cross (i.e. the boundary
467       // of A intersects the interior and exterior of B and vice versa).
468       // Thus we want to distinguish cases (1), (2-3), and (4-6).
469       //
470       // Note that the vertices may satisfy more than one of the edge
471       // orderings above if two or more vertices are the same. The tests
472       // below are written so that we take the most favorable
473       // interpretation, i.e. preferring (1) over (2-3) over (4-6). In
474       // particular note that if orderedCCW(a,b,c,o) returns true, it may be
475       // possible that orderedCCW(c,b,a,o) is also true (if a == b or b == c).
476 
477       if (S2.orderedCCW(a0, a2, b2, ab1)) {
478         // The cases with this vertex ordering are 1, 5, and 6,
479         // although case 2 is also possible if a2 == b2.
480         if (S2.orderedCCW(b2, b0, a0, ab1)) {
481           return 1; // Case 1 (A contains B)
482         }
483 
484         // We are in case 5 or 6, or case 2 if a2 == b2.
485         return (a2.equals(b2)) ? 0 : -1; // Case 2 vs. 5,6.
486       }
487       // We are in case 2, 3, or 4.
488       return S2.orderedCCW(a0, b0, a2, ab1) ? 0 : -1; // Case 2,3 vs. 4.
489     }
490   }
491 
492   /**
493    * Return true if edge AB crosses CD at a point that is interior to both
494    * edges. Properties:
495    *
496    *  (1) simpleCrossing(b,a,c,d) == simpleCrossing(a,b,c,d) (2)
497    * simpleCrossing(c,d,a,b) == simpleCrossing(a,b,c,d)
498    */
simpleCrossing(S2Point a, S2Point b, S2Point c, S2Point d)499   public static boolean simpleCrossing(S2Point a, S2Point b, S2Point c, S2Point d) {
500     // We compute simpleCCW() for triangles ACB, CBD, BDA, and DAC. All
501     // of these triangles need to have the same orientation (CW or CCW)
502     // for an intersection to exist. Note that this is slightly more
503     // restrictive than the corresponding definition for planar edges,
504     // since we need to exclude pairs of line segments that would
505     // otherwise "intersect" by crossing two antipodal points.
506 
507     S2Point ab = S2Point.crossProd(a, b);
508     double acb = -(ab.dotProd(c));
509     double bda = ab.dotProd(d);
510     if (acb * bda <= 0) {
511       return false;
512     }
513 
514     S2Point cd = S2Point.crossProd(c, d);
515     double cbd = -(cd.dotProd(b));
516     double dac = cd.dotProd(a);
517     return (acb * cbd > 0) && (acb * dac > 0);
518   }
519 
520   /**
521    * Like SimpleCrossing, except that points that lie exactly on a line are
522    * arbitrarily classified as being on one side or the other (according to the
523    * rules of S2.robustCCW). It returns +1 if there is a crossing, -1 if there
524    * is no crossing, and 0 if any two vertices from different edges are the
525    * same. Returns 0 or -1 if either edge is degenerate. Properties of
526    * robustCrossing:
527    *
528    *  (1) robustCrossing(b,a,c,d) == robustCrossing(a,b,c,d) (2)
529    * robustCrossing(c,d,a,b) == robustCrossing(a,b,c,d) (3)
530    * robustCrossing(a,b,c,d) == 0 if a==c, a==d, b==c, b==d (3)
531    * robustCrossing(a,b,c,d) <= 0 if a==b or c==d
532    *
533    *  Note that if you want to check an edge against a *chain* of other edges,
534    * it is much more efficient to use an EdgeCrosser (above).
535    */
robustCrossing(S2Point a, S2Point b, S2Point c, S2Point d)536   public static int robustCrossing(S2Point a, S2Point b, S2Point c, S2Point d) {
537     // For there to be a crossing, the triangles ACB, CBD, BDA, DAC must
538     // all have the same orientation (clockwise or counterclockwise).
539     //
540     // First we compute the orientation of ACB and BDA. We permute the
541     // arguments to robustCCW so that we can reuse the cross-product of A and B.
542     // Recall that when the arguments to robustCCW are permuted, the sign of the
543     // result changes according to the sign of the permutation. Thus ACB and
544     // ABC are oppositely oriented, while BDA and ABD are the same.
545     S2Point aCrossB = S2Point.crossProd(a, b);
546     int acb = -S2.robustCCW(a, b, c, aCrossB);
547     int bda = S2.robustCCW(a, b, d, aCrossB);
548 
549     // If any two vertices are the same, the result is degenerate.
550     if ((bda & acb) == 0) {
551       return 0;
552     }
553 
554     // If ABC and BDA have opposite orientations (the most common case),
555     // there is no crossing.
556     if (bda != acb) {
557       return -1;
558     }
559 
560     // Otherwise we compute the orientations of CBD and DAC, and check whether
561     // their orientations are compatible with the other two triangles.
562     S2Point cCrossD = S2Point.crossProd(c, d);
563     int cbd = -S2.robustCCW(c, d, b, cCrossD);
564     if (cbd != acb) {
565       return -1;
566     }
567 
568     int dac = S2.robustCCW(c, d, a, cCrossD);
569     return (dac == acb) ? 1 : -1;
570   }
571 
572   /**
573    * Given two edges AB and CD where at least two vertices are identical (i.e.
574    * robustCrossing(a,b,c,d) == 0), this function defines whether the two edges
575    * "cross" in a such a way that point-in-polygon containment tests can be
576    * implemented by counting the number of edge crossings. The basic rule is
577    * that a "crossing" occurs if AB is encountered after CD during a CCW sweep
578    * around the shared vertex starting from a fixed reference point.
579    *
580    *  Note that according to this rule, if AB crosses CD then in general CD does
581    * not cross AB. However, this leads to the correct result when counting
582    * polygon edge crossings. For example, suppose that A,B,C are three
583    * consecutive vertices of a CCW polygon. If we now consider the edge
584    * crossings of a segment BP as P sweeps around B, the crossing number changes
585    * parity exactly when BP crosses BA or BC.
586    *
587    *  Useful properties of VertexCrossing (VC):
588    *
589    *  (1) VC(a,a,c,d) == VC(a,b,c,c) == false (2) VC(a,b,a,b) == VC(a,b,b,a) ==
590    * true (3) VC(a,b,c,d) == VC(a,b,d,c) == VC(b,a,c,d) == VC(b,a,d,c) (3) If
591    * exactly one of a,b equals one of c,d, then exactly one of VC(a,b,c,d) and
592    * VC(c,d,a,b) is true
593    *
594    * It is an error to call this method with 4 distinct vertices.
595    */
vertexCrossing(S2Point a, S2Point b, S2Point c, S2Point d)596   public static boolean vertexCrossing(S2Point a, S2Point b, S2Point c, S2Point d) {
597     // If A == B or C == D there is no intersection. We need to check this
598     // case first in case 3 or more input points are identical.
599     if (a.equals(b) || c.equals(d)) {
600       return false;
601     }
602 
603     // If any other pair of vertices is equal, there is a crossing if and only
604     // if orderedCCW() indicates that the edge AB is further CCW around the
605     // shared vertex than the edge CD.
606     if (a.equals(d)) {
607       return S2.orderedCCW(S2.ortho(a), c, b, a);
608     }
609     if (b.equals(c)) {
610       return S2.orderedCCW(S2.ortho(b), d, a, b);
611     }
612     if (a.equals(c)) {
613       return S2.orderedCCW(S2.ortho(a), d, b, a);
614     }
615     if (b.equals(d)) {
616       return S2.orderedCCW(S2.ortho(b), c, a, b);
617     }
618 
619     // assert (false);
620     return false;
621   }
622 
623   /**
624    * A convenience function that calls robustCrossing() to handle cases where
625    * all four vertices are distinct, and VertexCrossing() to handle cases where
626    * two or more vertices are the same. This defines a crossing function such
627    * that point-in-polygon containment tests can be implemented by simply
628    * counting edge crossings.
629    */
edgeOrVertexCrossing(S2Point a, S2Point b, S2Point c, S2Point d)630   public static boolean edgeOrVertexCrossing(S2Point a, S2Point b, S2Point c, S2Point d) {
631     int crossing = robustCrossing(a, b, c, d);
632     if (crossing < 0) {
633       return false;
634     }
635     if (crossing > 0) {
636       return true;
637     }
638     return vertexCrossing(a, b, c, d);
639   }
640 
641   static class CloserResult {
642     private double dmin2;
643     private S2Point vmin;
644 
getDmin2()645     public double getDmin2() {
646       return dmin2;
647     }
648 
getVmin()649     public S2Point getVmin() {
650       return vmin;
651     }
652 
CloserResult(double dmin2, S2Point vmin)653     public CloserResult(double dmin2, S2Point vmin) {
654       this.dmin2 = dmin2;
655       this.vmin = vmin;
656     }
657 
replaceIfCloser(S2Point x, S2Point y)658     public void replaceIfCloser(S2Point x, S2Point y) {
659       // If the squared distance from x to y is less than dmin2, then replace
660       // vmin by y and update dmin2 accordingly.
661       double d2 = S2Point.minus(x, y).norm2();
662       if (d2 < dmin2 || (d2 == dmin2 && y.lessThan(vmin))) {
663         dmin2 = d2;
664         vmin = y;
665       }
666     }
667   }
668 
669   /*
670    * Given two edges AB and CD such that robustCrossing() is true, return their
671    * intersection point. Useful properties of getIntersection (GI):
672    *
673    * (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d) (2) GI(c,d,a,b) ==
674    * GI(a,b,c,d)
675    *
676    * The returned intersection point X is guaranteed to be close to the edges AB
677    * and CD, but if the edges intersect at a very small angle then X may not be
678    * close to the true mathematical intersection point P. See the description of
679    * "DEFAULT_INTERSECTION_TOLERANCE" below for details.
680    */
getIntersection(S2Point a0, S2Point a1, S2Point b0, S2Point b1)681   public static S2Point getIntersection(S2Point a0, S2Point a1, S2Point b0, S2Point b1) {
682     Preconditions.checkArgument(robustCrossing(a0, a1, b0, b1) > 0,
683         "Input edges a0a1 and b0b1 muct have a true robustCrossing.");
684 
685     // We use robustCrossProd() to get accurate results even when two endpoints
686     // are close together, or when the two line segments are nearly parallel.
687     S2Point aNorm = S2Point.normalize(S2.robustCrossProd(a0, a1));
688     S2Point bNorm = S2Point.normalize(S2.robustCrossProd(b0, b1));
689     S2Point x = S2Point.normalize(S2.robustCrossProd(aNorm, bNorm));
690 
691     // Make sure the intersection point is on the correct side of the sphere.
692     // Since all vertices are unit length, and edges are less than 180 degrees,
693     // (a0 + a1) and (b0 + b1) both have positive dot product with the
694     // intersection point. We use the sum of all vertices to make sure that the
695     // result is unchanged when the edges are reversed or exchanged.
696     if (x.dotProd(S2Point.add(S2Point.add(a0, a1), S2Point.add(b0, b1))) < 0) {
697       x = S2Point.neg(x);
698     }
699 
700     // The calculation above is sufficient to ensure that "x" is within
701     // DEFAULT_INTERSECTION_TOLERANCE of the great circles through (a0,a1) and
702     // (b0,b1).
703     // However, if these two great circles are very close to parallel, it is
704     // possible that "x" does not lie between the endpoints of the given line
705     // segments. In other words, "x" might be on the great circle through
706     // (a0,a1) but outside the range covered by (a0,a1). In this case we do
707     // additional clipping to ensure that it does.
708 
709     if (S2.orderedCCW(a0, x, a1, aNorm) && S2.orderedCCW(b0, x, b1, bNorm)) {
710       return x;
711     }
712 
713     // Find the acceptable endpoint closest to x and return it. An endpoint is
714     // acceptable if it lies between the endpoints of the other line segment.
715     CloserResult r = new CloserResult(10, x);
716     if (S2.orderedCCW(b0, a0, b1, bNorm)) {
717       r.replaceIfCloser(x, a0);
718     }
719     if (S2.orderedCCW(b0, a1, b1, bNorm)) {
720       r.replaceIfCloser(x, a1);
721     }
722     if (S2.orderedCCW(a0, b0, a1, aNorm)) {
723       r.replaceIfCloser(x, b0);
724     }
725     if (S2.orderedCCW(a0, b1, a1, aNorm)) {
726       r.replaceIfCloser(x, b1);
727     }
728     return r.getVmin();
729   }
730 
731   /**
732    * Given a point X and an edge AB, return the distance ratio AX / (AX + BX).
733    * If X happens to be on the line segment AB, this is the fraction "t" such
734    * that X == Interpolate(A, B, t). Requires that A and B are distinct.
735    */
getDistanceFraction(S2Point x, S2Point a0, S2Point a1)736   public static double getDistanceFraction(S2Point x, S2Point a0, S2Point a1) {
737     Preconditions.checkArgument(!a0.equals(a1));
738     double d0 = x.angle(a0);
739     double d1 = x.angle(a1);
740     return d0 / (d0 + d1);
741   }
742 
743   /**
744    * Return the minimum distance from X to any point on the edge AB. The result
745    * is very accurate for small distances but may have some numerical error if
746    * the distance is large (approximately Pi/2 or greater). The case A == B is
747    * handled correctly. Note: x, a and b must be of unit length. Throws
748    * IllegalArgumentException if this is not the case.
749    */
getDistance(S2Point x, S2Point a, S2Point b)750   public static S1Angle getDistance(S2Point x, S2Point a, S2Point b) {
751     return getDistance(x, a, b, S2.robustCrossProd(a, b));
752   }
753 
754   /**
755    * A slightly more efficient version of getDistance() where the cross product
756    * of the two endpoints has been precomputed. The cross product does not need
757    * to be normalized, but should be computed using S2.robustCrossProd() for the
758    * most accurate results.
759    */
getDistance(S2Point x, S2Point a, S2Point b, S2Point aCrossB)760   public static S1Angle getDistance(S2Point x, S2Point a, S2Point b, S2Point aCrossB) {
761     Preconditions.checkArgument(S2.isUnitLength(x));
762     Preconditions.checkArgument(S2.isUnitLength(a));
763     Preconditions.checkArgument(S2.isUnitLength(b));
764 
765     // There are three cases. If X is located in the spherical wedge defined by
766     // A, B, and the axis A x B, then the closest point is on the segment AB.
767     // Otherwise the closest point is either A or B; the dividing line between
768     // these two cases is the great circle passing through (A x B) and the
769     // midpoint of AB.
770 
771     if (S2.simpleCCW(aCrossB, a, x) && S2.simpleCCW(x, b, aCrossB)) {
772       // The closest point to X lies on the segment AB. We compute the distance
773       // to the corresponding great circle. The result is accurate for small
774       // distances but not necessarily for large distances (approaching Pi/2).
775 
776       double sinDist = Math.abs(x.dotProd(aCrossB)) / aCrossB.norm();
777       return S1Angle.radians(Math.asin(Math.min(1.0, sinDist)));
778     }
779 
780     // Otherwise, the closest point is either A or B. The cheapest method is
781     // just to compute the minimum of the two linear (as opposed to spherical)
782     // distances and convert the result to an angle. Again, this method is
783     // accurate for small but not large distances (approaching Pi).
784 
785     double linearDist2 = Math.min(S2Point.minus(x, a).norm2(), S2Point.minus(x, b).norm2());
786     return S1Angle.radians(2 * Math.asin(Math.min(1.0, 0.5 * Math.sqrt(linearDist2))));
787   }
788 
789   /**
790    * Returns the point on edge AB closest to X. x, a and b must be of unit
791    * length. Throws IllegalArgumentException if this is not the case.
792    *
793    */
getClosestPoint(S2Point x, S2Point a, S2Point b)794   public static S2Point getClosestPoint(S2Point x, S2Point a, S2Point b) {
795     Preconditions.checkArgument(S2.isUnitLength(x));
796     Preconditions.checkArgument(S2.isUnitLength(a));
797     Preconditions.checkArgument(S2.isUnitLength(b));
798 
799     S2Point crossProd = S2.robustCrossProd(a, b);
800     // Find the closest point to X along the great circle through AB.
801     S2Point p = S2Point.minus(x, S2Point.mul(crossProd, x.dotProd(crossProd) / crossProd.norm2()));
802 
803     // If p is on the edge AB, then it's the closest point.
804     if (S2.simpleCCW(crossProd, a, p) && S2.simpleCCW(p, b, crossProd)) {
805       return S2Point.normalize(p);
806     }
807     // Otherwise, the closest point is either A or B.
808     return S2Point.minus(x, a).norm2() <= S2Point.minus(x, b).norm2() ? a : b;
809   }
810 
811   /** Constructor is private so that this class is never instantiated. */
S2EdgeUtil()812   private S2EdgeUtil() {
813   }
814 }
815