1 /**
2    An S2Loop represents a simple spherical polygon.
3 
4    Copyright: 2005 Google Inc. All Rights Reserved.
5 
6    License:
7    Licensed under the Apache License, Version 2.0 (the "License");
8    you may not use this file except in compliance with the License.
9    You may obtain a copy of the License at
10 
11    $(LINK http://www.apache.org/licenses/LICENSE-2.0)
12 
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS-IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18 
19    Authors: ericv@google.com (Eric Veach), madric@gmail.com (Vijay Nayar)
20 */
21 module s2.s2loop;
22 
23 import s2.logger;
24 import s2.mutable_s2shape_index;
25 import s2.r1interval;
26 import s2.r2point;
27 import s2.r2rect;
28 import s2.s1angle;
29 import s2.s1chord_angle;
30 import s2.s1interval;
31 import s2.s2cap;
32 import s2.s2cell;
33 import s2.s2cell_id;
34 import s2.s2centroids : trueCentroid;
35 import s2.s2closest_edge_query;
36 import s2.s2coords : XYZtoFaceSiTi;
37 import s2.s2crossing_edge_query;
38 import s2.s2debug;
39 import s2.s2edge_crosser;
40 import s2.s2edge_distances : getDistance;
41 import s2.s2error;
42 import s2.s2latlng_rect;
43 import s2.s2latlng_rect_bounder;
44 import s2.s2measures : signedArea, turnAngle;
45 import s2.s2padded_cell;
46 import s2.s2point;
47 import s2.s2point_compression : S2XYZFaceSiTi;
48 import s2.s2pointutil : approxEquals, fromFrame, getFrame, origin, robustCrossProd;
49 import s2.s2predicates : orderedCCW;
50 import s2.s2region;
51 import s2.s2shape;
52 import s2.s2shape_index;
53 import s2.s2wedge_relations : wedgeContains, wedgeIntersects;
54 import s2.shapeutil.visit_crossing_edge_pairs : findSelfIntersection;
55 import s2.util.coding.coder;
56 import s2.util.math.matrix3x3;
57 import s2.util.math.vector;
58 
59 import std.algorithm : copy, min, max, reverse, swap;
60 import std.array : appender;
61 import std.conv : to;
62 import std.exception;
63 import std.math;
64 import std.range : empty, back, isInputRange, popBack;
65 import core.atomic;
66 
67 // Build the S2ShapeIndex only when it is first needed.  This can save
68 // significant amounts of memory and time when geometry is constructed but
69 // never queried, for example when loops are passed directly to S2Polygon,
70 // or when geometry is being converted from one format to another.
71 enum bool LAZY_INDEXING = true;
72 
73 /**
74  * An S2Loop represents a simple spherical polygon.  It consists of a single
75  * chain of vertices where the first vertex is implicitly connected to the
76  * last. All loops are defined to have a CCW orientation, i.e. the interior of
77  * the loop is on the left side of the edges.  This implies that a clockwise
78  * loop enclosing a small area is interpreted to be a CCW loop enclosing a
79  * very large area.
80  *
81  * Loops are not allowed to have any duplicate vertices (whether adjacent or
82  * not).  Non-adjacent edges are not allowed to intersect, and furthermore edges
83  * of length 180 degrees are not allowed (i.e., adjacent vertices cannot be
84  * antipodal).  Loops must have at least 3 vertices (except for the "empty" and
85  * "full" loops discussed below).  Although these restrictions are not enforced
86  * in optimized code, you may get unexpected results if they are violated.
87  *
88  * There are two special loops: the "empty" loop contains no points, while the
89  * "full" loop contains all points.  These loops do not have any edges, but to
90  * preserve the invariant that every loop can be represented as a vertex
91  * chain, they are defined as having exactly one vertex each (see kEmpty and
92  * kFull).
93  *
94  * Point containment of loops is defined such that if the sphere is subdivided
95  * into faces (loops), every point is contained by exactly one face.  This
96  * implies that loops do not necessarily contain their vertices.
97  *
98  * Note: The reason that duplicate vertices and intersecting edges are not
99  * allowed is that they make it harder to define and implement loop
100  * relationships, e.g. whether one loop contains another.  If your data does
101  * not satisfy these restrictions, you can use S2Builder to normalize it.
102  *
103  * TODO: Convert logic to use a ForwardRange rather than making a copy of its vertices.
104  */
105 class S2Loop : S2Region {
106 public:
107   /// Default constructor.  The loop must be initialized by calling Init() or
108   /// Decode() before it is used.
109   this() {
110     _bound = new S2LatLngRect();
111     _subregionBound = new S2LatLngRect();
112     _index = new MutableS2ShapeIndex();
113   }
114 
115   this(in S2Point[] vertices) {
116     this(vertices, S2Debug.ALLOW);
117   }
118 
119   /// Convenience constructor that calls Init() with the given vertices.
120   this(in S2Point[] vertices, S2Debug s2DebugOverride) {
121     this();
122     _s2DebugOverride = s2DebugOverride;
123     initialize(vertices);
124   }
125 
126   /**
127      Initialize a loop with given vertices.  The last vertex is implicitly
128      connected to the first.  All points should be unit length.  Loops must
129      have at least 3 vertices (except for the "empty" and "full" loops, see
130      kEmpty and kFull).  This method may be called multiple times.
131   */
132   void initialize(RangeT)(RangeT vertexRange)
133   if (isInputRange!RangeT /*&& is(ElementType!RangeT == Vector!(double, 3))*/) {
134     clearIndex();
135     _vertices.length = 0;
136     _vertices ~= vertexRange;
137     //copy(vertexRange, appender(_vertices));
138     initOriginAndBound();
139   }
140 
141   /**
142      A special vertex chain of length 1 that creates an empty loop (i.e., a
143      loop with no edges that contains no points).  Example usage:
144 
145         S2Loop emptyLoop = new S2Loop(S2Loop.empty());
146 
147      The loop may be safely encoded lossily (e.g. by snapping it to an S2Cell
148      center) as long as its position does not move by 90 degrees or more.
149   */
150   static S2Point[] empty() {
151     return [S2Loop.emptyVertex()];
152   }
153 
154   /// A special vertex chain of length 1 that creates a full loop (i.e., a loop
155   /// with no edges that contains all points).  See kEmpty() for details.
156   static S2Point[] full() {
157     return [S2Loop.fullVertex()];
158   }
159 
160   /**
161      Construct a loop corresponding to the given cell.
162 
163      Note that the loop and cell *do not* contain exactly the same set of
164      points, because S2Loop and S2Cell have slightly different definitions of
165      point containment.  For example, an S2Cell vertex is contained by all
166      four neighboring S2Cells, but it is contained by exactly one of four
167      S2Loops constructed from those cells.  As another example, the S2Cell
168      coverings of "cell" and "S2Loop(cell)" will be different, because the
169      loop contains points on its boundary that actually belong to other cells
170      (i.e., the covering will include a layer of neighboring cells).
171   */
172   this(in S2Cell cell) {
173     this();
174     _depth = 0;
175     _vertices.length = 4;
176     _s2DebugOverride = S2Debug.ALLOW;
177     _unindexedContainsCalls = 0;
178     foreach (i; 0 .. 4) {
179       _vertices[i] = cell.getVertex(i);
180     }
181     // We recompute the bounding rectangle ourselves, since S2Cell uses a
182     // different method and we need all the bounds to be consistent.
183     initOriginAndBound();
184   }
185 
186   /**
187      Allows overriding the automatic validity checks controlled by the
188      --s2debug flag.  If this flag is true, then loops are automatically
189      checked for validity as they are initialized.  The main reason to disable
190      this flag is if you intend to call IsValid() explicitly, like this:
191      ---
192        S2Loop loop;
193        loop.set_s2debug_override(S2Debug::DISABLE);
194        loop.Init(...);
195        if (!loop.IsValid()) { ... }
196      ---
197      Without the call to set_s2debug_override(), invalid data would cause a
198      fatal error in Init() whenever the --s2debug flag is enabled.
199 
200      This setting is preserved across calls to Init() and Decode().
201   */
202   @property
203   void s2DebugOverride(S2Debug s2DebugOverride) {
204     _s2DebugOverride = s2DebugOverride;
205   }
206 
207   @property
208   S2Debug s2DebugOverride() const {
209     return _s2DebugOverride;
210   }
211 
212   /**
213      Returns true if this is a valid loop.  Note that validity is checked
214      automatically during initialization when --s2debug is enabled (true by
215      default in debug binaries).
216   */
217   bool isValid() {
218     S2Error error;
219     if (findValidationError(error)) {
220       if (_s2DebugOverride == S2Debug.ALLOW) logger.logError(error);
221       return false;
222     }
223     return true;
224   }
225 
226   /**
227      Returns true if this is *not* a valid loop and sets "error"
228      appropriately.  Otherwise returns false and leaves "error" unchanged.
229   */
230   bool findValidationError(ref S2Error error) {
231     return (findValidationErrorNoIndex(error) || findSelfIntersection(_index, error));
232   }
233 
234   /**
235      Like FindValidationError(), but skips any checks that would require
236      building the S2ShapeIndex (i.e., self-intersection tests).  This is used
237      by the S2Polygon implementation, which uses its own index to check for
238      loop self-intersections.
239   */
240   bool findValidationErrorNoIndex(ref S2Error error) const
241   in {
242     // subregion_bound_ must be at least as large as bound_.  (This is an
243     // internal consistency check rather than a test of client data.)
244     assert(_subregionBound.contains(_bound));
245   } do {
246     import s2.s2pointutil : isUnitLength;
247     // All vertices must be unit length.  (Unfortunately this check happens too
248     // late in debug mode, because S2Loop construction calls s2pred::Sign which
249     // expects vertices to be unit length.  But it is still a useful check in
250     // optimized builds.)
251     for (int i = 0; i < numVertices(); ++i) {
252       if (!isUnitLength(vertex(i))) {
253         error.initialize(S2Error.Code.NOT_UNIT_LENGTH, "Vertex %d is not unit length", i);
254         return true;
255       }
256     }
257     // Loops must have at least 3 vertices (except for "empty" and "full").
258     if (numVertices() < 3) {
259       if (isEmptyOrFull()) {
260         return false;  // Skip remaining tests.
261       }
262       error.initialize(S2Error.Code.LOOP_NOT_ENOUGH_VERTICES,
263           "Non-empty, non-full loops must have at least 3 vertices");
264       return true;
265     }
266     // Loops are not allowed to have any duplicate vertices or edge crossings.
267     // We split this check into two parts.  First we check that no edge is
268     // degenerate (identical endpoints).  Then we check that there are no
269     // intersections between non-adjacent edges (including at vertices).  The
270     // second part needs the S2ShapeIndex, so it does not fall within the scope
271     // of this method.
272     for (int i = 0; i < numVertices(); ++i) {
273       if (vertex(i) == vertex(i+1)) {
274         error.initialize(
275             S2Error.Code.DUPLICATE_VERTICES, "Edge %d is degenerate (duplicate vertex)", i);
276         return true;
277       }
278       if (vertex(i) == -vertex(i + 1)) {
279         error.initialize(S2Error.Code.ANTIPODAL_VERTICES,
280             "Vertices %d and %d are antipodal", i, (i + 1) % numVertices());
281         return true;
282       }
283     }
284     return false;
285   }
286 
287   int numVertices() const {
288     return cast(int) _vertices.length;
289   }
290 
291   /**
292      For convenience, we make two entire copies of the vertex list available:
293      vertex(n..2*n-1) is mapped to vertex(0..n-1), where n == num_vertices().
294 
295      REQUIRES: 0 <= i < 2 * num_vertices()
296   */
297   S2Point vertex(int i) const
298   in {
299     assert(i >= 0);
300     assert(i < 2 * numVertices());
301   } do {
302     int j = i - numVertices();
303     return _vertices[j < 0 ? i : j];
304   }
305 
306   const(S2Point[]) vertices() const {
307     return _vertices;
308   }
309 
310   /**
311      Like vertex(), but this method returns vertices in reverse order if the
312      loop represents a polygon hole.  For example, arguments 0, 1, 2 are
313      mapped to vertices n-1, n-2, n-3, where n == num_vertices().  This
314      ensures that the interior of the polygon is always to the left of the
315      vertex chain.
316 
317      REQUIRES: 0 <= i < 2 * num_vertices()
318   */
319   S2Point orientedVertex(int i) const
320   in {
321     assert(i >= 0);
322     assert(i < 2 * numVertices());
323   } do {
324     int j = i - numVertices();
325     if (j < 0) j = i;
326     if (isHole()) j = numVertices() - 1 - j;
327     return _vertices[j];
328   }
329 
330   /// Returns true if this is the special "empty" loop that contains no points.
331   bool isEmpty() const {
332     return isEmptyOrFull() && !containsOrigin();
333   }
334 
335   /// Returns true if this is the special "full" loop that contains all points.
336   bool isFull() const {
337     return isEmptyOrFull() && containsOrigin();
338   }
339 
340   /// Returns true if this loop is either "empty" or "full".
341   bool isEmptyOrFull() const {
342     return numVertices() == 1;
343   }
344 
345   /**
346      The depth of a loop is defined as its nesting level within its containing
347      polygon.  "Outer shell" loops have depth 0, holes within those loops have
348      depth 1, shells within those holes have depth 2, etc.  This field is only
349      used by the S2Polygon implementation.
350   */
351   int depth() const {
352     return _depth;
353   }
354 
355   void setDepth(int depth) {
356     _depth = depth;
357   }
358 
359   /// Returns true if this loop represents a hole in its containing polygon.
360   bool isHole() const {
361     return (_depth & 1) != 0;
362   }
363 
364   /**
365      The sign of a loop is -1 if the loop represents a hole in its containing
366      polygon, and +1 otherwise.
367   */
368   int sign() const {
369     return isHole() ? -1 : 1;
370   }
371 
372   /**
373      Return true if the loop area is at most 2*Pi.  Degenerate loops are
374      handled consistently with s2pred::Sign(), i.e., if a loop can be
375      expressed as the union of degenerate or nearly-degenerate CCW triangles,
376      then it will always be considered normalized.
377   */
378   bool isNormalized() const {
379     // Optimization: if the longitude span is less than 180 degrees, then the
380     // loop covers less than half the sphere and is therefore normalized.
381     if (_bound.lng().getLength() < M_PI) return true;
382 
383     // We allow some error so that hemispheres are always considered normalized.
384     // TODO(ericv): This is no longer required by the S2Polygon implementation,
385     // so alternatively we could create the invariant that a loop is normalized
386     // if and only if its complement is not normalized.
387     return getTurningAngle() >= -getTurningAngleMaxError();
388   }
389 
390   /// Invert the loop if necessary so that the area enclosed by the loop is at most 2*Pi.
391   void normalize()
392   out {
393     assert(isNormalized());
394   } do {
395     if (!isNormalized()) invert();
396   }
397 
398   /**
399      Reverse the order of the loop vertices, effectively complementing the
400      region represented by the loop.  For example, the loop ABCD (with edges
401      AB, BC, CD, DA) becomes the loop DCBA (with edges DC, CB, BA, AD).
402      Notice that the last edge is the same in both cases except that its
403      direction has been reversed.
404   */
405   void invert() {
406     clearIndex();
407     if (isEmptyOrFull()) {
408       _vertices[0] = isFull() ? emptyVertex() : fullVertex();
409     } else {
410       reverse(_vertices);
411     }
412     // origin_inside_ must be set correctly before building the S2ShapeIndex.
413     _originInside ^= true;
414     if (_bound.lat().lo() > -M_PI_2 && _bound.lat().hi() < M_PI_2) {
415       // The complement of this loop contains both poles.
416       _subregionBound = _bound = S2LatLngRect.full();
417     } else {
418       initBound();
419     }
420     initIndex();
421   }
422 
423   /**
424      Return the area of the loop interior, i.e. the region on the left side of
425      the loop.  The return value is between 0 and 4*Pi.  (Note that the return
426      value is not affected by whether this loop is a "hole" or a "shell".)
427   */
428   double getArea() const {
429     // It is suprisingly difficult to compute the area of a loop robustly.  The
430     // main issues are (1) whether degenerate loops are considered to be CCW or
431     // not (i.e., whether their area is close to 0 or 4*Pi), and (2) computing
432     // the areas of small loops with good relative accuracy.
433     //
434     // With respect to degeneracies, we would like GetArea() to be consistent
435     // with S2Loop::Contains(S2Point) in that loops that contain many points
436     // should have large areas, and loops that contain few points should have
437     // small areas.  For example, if a degenerate triangle is considered CCW
438     // according to s2pred::Sign(), then it will contain very few points and
439     // its area should be approximately zero.  On the other hand if it is
440     // considered clockwise, then it will contain virtually all points and so
441     // its area should be approximately 4*Pi.
442 
443     // More precisely, let U be the set of S2Points for which S2::IsUnitLength()
444     // is true, let P(U) be the projection of those points onto the mathematical
445     // unit sphere, and let V(P(U)) be the Voronoi diagram of the projected
446     // points.  Then for every loop x, we would like GetArea() to approximately
447     // equal the sum of the areas of the Voronoi regions of the points p for
448     // which x.Contains(p) is true.
449     //
450     // The second issue is that we want to compute the area of small loops
451     // accurately.  This requires having good relative precision rather than
452     // good absolute precision.  For example, if the area of a loop is 1e-12 and
453     // the error is 1e-15, then the area only has 3 digits of accuracy.  (For
454     // reference, 1e-12 is about 40 square meters on the surface of the earth.)
455     // We would like to have good relative accuracy even for small loops.
456     //
457     // To achieve these goals, we combine two different methods of computing the
458     // area.  This first method is based on the Gauss-Bonnet theorem, which says
459     // that the area enclosed by the loop equals 2*Pi minus the total geodesic
460     // curvature of the loop (i.e., the sum of the "turning angles" at all the
461     // loop vertices).  The big advantage of this method is that as long as we
462     // use s2pred::Sign() to compute the turning angle at each vertex, then
463     // degeneracies are always handled correctly.  In other words, if a
464     // degenerate loop is CCW according to the symbolic perturbations used by
465     // s2pred::Sign(), then its turning angle will be approximately 2*Pi.
466     //
467     // The disadvantage of the Gauss-Bonnet method is that its absolute error is
468     // about 2e-15 times the number of vertices (see GetTurningAngleMaxError).
469     // So, it cannot compute the area of small loops accurately.
470     //
471     // The second method is based on splitting the loop into triangles and
472     // summing the area of each triangle.  To avoid the difficulty and expense
473     // of decomposing the loop into a union of non-overlapping triangles,
474     // instead we compute a signed sum over triangles that may overlap (see the
475     // comments for S2Loop::GetSurfaceIntegral).  The advantage of this method
476     // is that the area of each triangle can be computed with much better
477     // relative accuracy (using l'Huilier's theorem).  The disadvantage is that
478     // the result is a signed area: CCW loops may yield a small positive value,
479     // while CW loops may yield a small negative value (which is converted to a
480     // positive area by adding 4*Pi).  This means that small errors in computing
481     // the signed area may translate into a very large error in the result (if
482     // the sign of the sum is incorrect).
483     //
484     // So, our strategy is to combine these two methods as follows.  First we
485     // compute the area using the "signed sum over triangles" approach (since it
486     // is generally more accurate).  We also estimate the maximum error in this
487     // result.  If the signed area is too close to zero (i.e., zero is within
488     // the error bounds), then we double-check the sign of the result using the
489     // Gauss-Bonnet method.  (In fact we just call IsNormalized(), which is
490     // based on this method.)  If the two methods disagree, we return either 0
491     // or 4*Pi based on the result of IsNormalized().  Otherwise we return the
492     // area that we computed originally.
493 
494     if (isEmptyOrFull()) {
495       return containsOrigin() ? (4 * M_PI) : 0;
496     }
497     double area = getSurfaceIntegral(&signedArea);
498 
499     // TODO(ericv): This error estimate is very approximate.  There are two
500     // issues: (1) SignedArea needs some improvements to ensure that its error
501     // is actually never higher than GirardArea, and (2) although the number of
502     // triangles in the sum is typically N-2, in theory it could be as high as
503     // 2*N for pathological inputs.  But in other respects this error bound is
504     // very conservative since it assumes that the maximum error is achieved on
505     // every triangle.
506     double max_error = getTurningAngleMaxError();
507 
508     // The signed area should be between approximately -4*Pi and 4*Pi.
509     enforce(fabs(area) <= 4 * M_PI + max_error);
510     if (area < 0) {
511       // We have computed the negative of the area of the loop exterior.
512       area += 4 * M_PI;
513     }
514     area = max(0.0, min(4 * M_PI, area));
515 
516     // If the area is close enough to zero or 4*Pi so that the loop orientation
517     // is ambiguous, then we compute the loop orientation explicitly.
518     if (area < max_error && !isNormalized()) {
519       return 4 * M_PI;
520     } else if (area > (4 * M_PI - max_error) && isNormalized()) {
521       return 0.0;
522     } else {
523       return area;
524     }
525 
526   }
527 
528   /**
529      Returns the true centroid of the loop multiplied by the area of the loop
530      (see s2centroids.h for details on centroids).  The result is not unit
531      length, so you may want to normalize it.  Also note that in general, the
532      centroid may not be contained by the loop.
533 
534      We prescale by the loop area for two reasons: (1) it is cheaper to
535      compute this way, and (2) it makes it easier to compute the centroid of
536      more complicated shapes (by splitting them into disjoint regions and
537      adding their centroids).
538 
539      Note that the return value is not affected by whether this loop is a
540      "hole" or a "shell".
541   */
542   S2Point getCentroid() const {
543     // GetSurfaceIntegral() returns either the integral of position over loop
544     // interior, or the negative of the integral of position over the loop
545     // exterior.  But these two values are the same (!), because the integral of
546     // position over the entire sphere is (0, 0, 0).
547     return getSurfaceIntegral(&trueCentroid);
548   }
549 
550   /**
551      Returns the sum of the turning angles at each vertex.  The return value is
552      positive if the loop is counter-clockwise, negative if the loop is
553      clockwise, and zero if the loop is a great circle.  Degenerate and
554      nearly-degenerate loops are handled consistently with s2pred::Sign().
555      So for example, if a loop has zero area (i.e., it is a very small CCW
556      loop) then the turning angle will always be negative.
557 
558      This quantity is also called the "geodesic curvature" of the loop.
559   */
560   double getTurningAngle() const {
561     // For empty and full loops, we return the limit value as the loop area
562     // approaches 0 or 4*Pi respectively.
563     if (isEmptyOrFull()) {
564       return containsOrigin() ? (-2 * M_PI) : (2 * M_PI);
565     }
566     // Don't crash even if the loop is not well-defined.
567     if (numVertices() < 3) return 0;
568 
569     // To ensure that we get the same result when the vertex order is rotated,
570     // and that the result is negated when the vertex order is reversed, we need
571     // to add up the individual turn angles in a consistent order.  (In general,
572     // adding up a set of numbers in a different order can change the sum due to
573     // rounding errors.)
574     //
575     // Furthermore, if we just accumulate an ordinary sum then the worst-case
576     // error is quadratic in the number of vertices.  (This can happen with
577     // spiral shapes, where the partial sum of the turning angles can be linear
578     // in the number of vertices.)  To avoid this we use the Kahan summation
579     // algorithm (http://en.wikipedia.org/wiki/Kahan_summation_algorithm).
580 
581     int n = numVertices();
582     int dir, i = getCanonicalFirstVertex(dir);
583     double sum = turnAngle(vertex((i + n - dir) % n), vertex(i), vertex((i + dir) % n));
584     double compensation = 0;  // Kahan summation algorithm
585     while (--n > 0) {
586       i += dir;
587       double angle = turnAngle(vertex(i - dir), vertex(i), vertex(i + dir));
588       double old_sum = sum;
589       angle += compensation;
590       sum += angle;
591       compensation = (old_sum - sum) + angle;
592     }
593     return dir * (sum + compensation);
594   }
595 
596   /**
597      Return the maximum error in GetTurningAngle().  The return value is not
598      constant; it depends on the loop.
599   */
600   double getTurningAngleMaxError() const {
601     // The maximum error can be bounded as follows:
602     //   2.24 * DBL_EPSILON    for RobustCrossProd(b, a)
603     //   2.24 * DBL_EPSILON    for RobustCrossProd(c, b)
604     //   3.25 * DBL_EPSILON    for Angle()
605     //   2.00 * DBL_EPSILON    for each addition in the Kahan summation
606     //   ------------------
607     //   9.73 * DBL_EPSILON
608     const double kMaxErrorPerVertex = 9.73 * double.epsilon;
609     return kMaxErrorPerVertex * numVertices();
610   }
611 
612   /**
613      Returns the distance from the given point to the loop interior.  If the
614      loop is empty, return S1Angle::Infinity().  "x" should be unit length.
615   */
616   S1Angle getDistance(in S2Point x) {
617     // Note that S2Loop::Contains(S2Point) is slightly more efficient than the
618     // generic version used by S2ClosestEdgeQuery.
619     if (contains(x)) return S1Angle.zero();
620     return getDistanceToBoundary(x);
621   }
622 
623   /**
624      Returns the distance from the given point to the loop boundary.  If the
625      loop is empty or full, return S1Angle::Infinity() (since the loop has no
626      boundary).  "x" should be unit length.
627   */
628   S1Angle getDistanceToBoundary(in S2Point x) {
629     auto options = new S2ClosestEdgeQuery.Options();
630     options.setIncludeInteriors(false);
631     auto t = new S2ClosestEdgeQuery.PointTarget(x);
632     return new S2ClosestEdgeQuery(_index, options).getDistance(t).toS1Angle();
633   }
634 
635   /**
636      If the given point is contained by the loop, return it.  Otherwise return
637      the closest point on the loop boundary.  If the loop is empty, return the
638      input argument.  Note that the result may or may not be contained by the
639      loop.  "x" should be unit length.
640   */
641   S2Point project(in S2Point x) {
642     if (contains(x)) return x;
643     return projectToBoundary(x);
644   }
645 
646   /**
647      Return the closest point on the loop boundary to the given point.  If the
648      loop is empty or full, return the input argument (since the loop has no
649      boundary).  "x" should be unit length.
650   */
651   S2Point projectToBoundary(in S2Point x) {
652     auto options = new S2ClosestEdgeQuery.Options();
653     options.setIncludeInteriors(false);
654     auto q = new S2ClosestEdgeQuery(_index, options);
655     auto target = new S2ClosestEdgeQuery.PointTarget(x);
656     S2ClosestEdgeQuery.Result edge = q.findClosestEdge(target);
657     return q.project(x, edge);
658   }
659 
660   /**
661      Returns true if the region contained by this loop is a superset of the
662      region contained by the given other loop.
663   */
664   bool contains(S2Loop b) {
665     // For this loop A to contains the given loop B, all of the following must
666     // be true:
667     //
668     //  (1) There are no edge crossings between A and B except at vertices.
669     //
670     //  (2) At every vertex that is shared between A and B, the local edge
671     //      ordering implies that A contains B.
672     //
673     //  (3) If there are no shared vertices, then A must contain a vertex of B
674     //      and B must not contain a vertex of A.  (An arbitrary vertex may be
675     //      chosen in each case.)
676     //
677     // The second part of (3) is necessary to detect the case of two loops whose
678     // union is the entire sphere, i.e. two loops that contains each other's
679     // boundaries but not each other's interiors.
680     if (!_subregionBound.contains(b._bound)) return false;
681 
682     // Special cases to handle either loop being empty or full.
683     if (isEmptyOrFull() || b.isEmptyOrFull()) {
684       return isFull() || b.isEmpty();
685     }
686 
687     // Check whether there are any edge crossings, and also check the loop
688     // relationship at any shared vertices.
689     auto relation = new ContainsRelation();
690     if (hasCrossingRelation(this, b, relation)) return false;
691 
692     // There are no crossings, and if there are any shared vertices then A
693     // contains B locally at each shared vertex.
694     if (relation.foundSharedVertex()) return true;
695 
696     // Since there are no edge intersections or shared vertices, we just need to
697     // test condition (3) above.  We can skip this test if we discovered that A
698     // contains at least one point of B while checking for edge crossings.
699     if (!contains(b.vertex(0))) return false;
700 
701     // We still need to check whether (A union B) is the entire sphere.
702     // Normally this check is very cheap due to the bounding box precondition.
703     if ((b._subregionBound.contains(_bound) || b._bound.unite(_bound).isFull())
704         && b.contains(vertex(0))) {
705       return false;
706     }
707     return true;
708   }
709 
710   /**
711      Returns true if the region contained by this loop intersects the region
712      contained by the given other loop.
713   */
714   bool intersects(S2Loop b) {
715     // a->Intersects(b) if and only if !a->Complement()->Contains(b).
716     // This code is similar to Contains(), but is optimized for the case
717     // where both loops enclose less than half of the sphere.
718     if (!_bound.intersects(b._bound)) return false;
719 
720     // Check whether there are any edge crossings, and also check the loop
721     // relationship at any shared vertices.
722     auto relation = new IntersectsRelation();
723     if (hasCrossingRelation(this, b, relation)) return true;
724     if (relation.foundSharedVertex()) return false;
725 
726     // Since there are no edge intersections or shared vertices, the loops
727     // intersect only if A contains B, B contains A, or the two loops contain
728     // each other's boundaries.  These checks are usually cheap because of the
729     // bounding box preconditions.  Note that neither loop is empty (because of
730     // the bounding box check above), so it is safe to access vertex(0).
731 
732     // Check whether A contains B, or A and B contain each other's boundaries.
733     // (Note that A contains all the vertices of B in either case.)
734     if (_subregionBound.contains(b._bound) || _bound.unite(b._bound).isFull()) {
735       if (contains(b.vertex(0))) return true;
736     }
737     // Check whether B contains A.
738     if (b._subregionBound.contains(_bound)) {
739       if (b.contains(vertex(0))) return true;
740     }
741     return false;
742   }
743 
744   /**
745      Returns true if two loops have the same vertices in the same linear order
746      (i.e., cyclic rotations are not allowed).
747   */
748   bool equals(in S2Loop b) const {
749     if (numVertices() != b.numVertices()) return false;
750     for (int i = 0; i < numVertices(); ++i) {
751       if (vertex(i) != b.vertex(i)) return false;
752     }
753     return true;
754   }
755 
756   /**
757      Returns true if two loops have the same boundary.  This is true if and
758      only if the loops have the same vertices in the same cyclic order (i.e.,
759      the vertices may be cyclically rotated).  The empty and full loops are
760      considered to have different boundaries.
761   */
762   bool boundaryEquals(in S2Loop b) const {
763     if (numVertices() != b.numVertices()) return false;
764 
765     // Special case to handle empty or full loops.  Since they have the same
766     // number of vertices, if one loop is empty/full then so is the other.
767     if (isEmptyOrFull()) return isEmpty() == b.isEmpty();
768 
769     for (int offset = 0; offset < numVertices(); ++offset) {
770       if (vertex(offset) == b.vertex(0)) {
771         // There is at most one starting offset since loop vertices are unique.
772         for (int i = 0; i < numVertices(); ++i) {
773           if (vertex(i + offset) != b.vertex(i)) return false;
774         }
775         return true;
776       }
777     }
778     return false;
779   }
780 
781   /**
782      Returns true if two loops have the same boundary except for vertex
783      perturbations.  More precisely, the vertices in the two loops must be in
784      the same cyclic order, and corresponding vertex pairs must be separated
785      by no more than "max_error".
786   */
787   bool boundaryApproxEquals(in S2Loop b, S1Angle max_error = S1Angle.fromRadians(1e-15)) const {
788     if (numVertices() != b.numVertices()) return false;
789 
790     // Special case to handle empty or full loops.  Since they have the same
791     // number of vertices, if one loop is empty/full then so is the other.
792     if (isEmptyOrFull()) return isEmpty() == b.isEmpty();
793 
794     for (int offset = 0; offset < numVertices(); ++offset) {
795       if (approxEquals(vertex(offset), b.vertex(0), max_error)) {
796         bool success = true;
797         for (int i = 0; i < numVertices(); ++i) {
798           if (!approxEquals(vertex(i + offset), b.vertex(i), max_error)) {
799             success = false;
800             break;
801           }
802         }
803         if (success) return true;
804         // Otherwise continue looping.  There may be more than one candidate
805         // starting offset since vertices are only matched approximately.
806       }
807     }
808     return false;
809   }
810 
811   /**
812      Returns true if the two loop boundaries are within "max_error" of each
813      other along their entire lengths.  The two loops may have different
814      numbers of vertices.  More precisely, this method returns true if the two
815      loops have parameterizations a:[0,1] -> S^2, b:[0,1] -> S^2 such that
816      distance(a(t), b(t)) <= max_error for all t.  You can think of this as
817      testing whether it is possible to drive two cars all the way around the
818      two loops such that no car ever goes backward and the cars are always
819      within "max_error" of each other.
820   */
821   bool boundaryNear(in S2Loop b, S1Angle max_error = S1Angle.fromRadians(1e-15)) const {
822     // Special case to handle empty or full loops.
823     if (isEmptyOrFull() || b.isEmptyOrFull()) {
824       return (isEmpty() && b.isEmpty()) || (isFull() && b.isFull());
825     }
826 
827     for (int a_offset = 0; a_offset < numVertices(); ++a_offset) {
828       if (matchBoundaries(this, b, a_offset, max_error)) return true;
829     }
830     return false;
831   }
832 
833   /**
834      This method computes the oriented surface integral of some quantity f(x)
835      over the loop interior, given a function f_tri(A,B,C) that returns the
836      corresponding integral over the spherical triangle ABC.  Here "oriented
837      surface integral" means:
838 
839      (1) f_tri(A,B,C) must be the integral of f if ABC is counterclockwise,
840          and the integral of -f if ABC is clockwise.
841 
842      (2) The result of this function is *either* the integral of f over the
843          loop interior, or the integral of (-f) over the loop exterior.
844 
845      Note that there are at least two common situations where it easy to work
846      around property (2) above:
847 
848       - If the integral of f over the entire sphere is zero, then it doesn't
849         matter which case is returned because they are always equal.
850 
851       - If f is non-negative, then it is easy to detect when the integral over
852         the loop exterior has been returned, and the integral over the loop
853         interior can be obtained by adding the integral of f over the entire
854         unit sphere (a constant) to the result.
855 
856      Also requires that the default constructor for T must initialize the
857      value to zero.  (This is true for built-in types such as "double".)
858   */
859   T getSurfaceIntegral(T)(
860       T function(in Vector!(double, 3), in Vector!(double, 3), in Vector!(double, 3)) fTri) const {
861     // We sum "f_tri" over a collection T of oriented triangles, possibly
862     // overlapping.  Let the sign of a triangle be +1 if it is CCW and -1
863     // otherwise, and let the sign of a point "x" be the sum of the signs of the
864     // triangles containing "x".  Then the collection of triangles T is chosen
865     // such that either:
866     //
867     //  (1) Each point in the loop interior has sign +1, and sign 0 otherwise; or
868     //  (2) Each point in the loop exterior has sign -1, and sign 0 otherwise.
869     //
870     // The triangles basically consist of a "fan" from vertex 0 to every loop
871     // edge that does not include vertex 0.  These triangles will always satisfy
872     // either (1) or (2).  However, what makes this a bit tricky is that
873     // spherical edges become numerically unstable as their length approaches
874     // 180 degrees.  Of course there is not much we can do if the loop itself
875     // contains such edges, but we would like to make sure that all the triangle
876     // edges under our control (i.e., the non-loop edges) are stable.  For
877     // example, consider a loop around the equator consisting of four equally
878     // spaced points.  This is a well-defined loop, but we cannot just split it
879     // into two triangles by connecting vertex 0 to vertex 2.
880     //
881     // We handle this type of situation by moving the origin of the triangle fan
882     // whenever we are about to create an unstable edge.  We choose a new
883     // location for the origin such that all relevant edges are stable.  We also
884     // create extra triangles with the appropriate orientation so that the sum
885     // of the triangle signs is still correct at every point.
886 
887     // The maximum length of an edge for it to be considered numerically stable.
888     // The exact value is fairly arbitrary since it depends on the stability of
889     // the "f_tri" function.  The value below is quite conservative but could be
890     // reduced further if desired.
891     const auto kMaxLength = S1ChordAngle.fromRadians(M_PI - 1e-5);
892 
893     // The default constructor for T must initialize the value to zero.
894     // (This is true for built-in types such as "double".)
895     T sum = to!T(0);
896     S2Point origin = vertex(0);
897     for (int i = 1; i + 1 < numVertices(); ++i) {
898       // Let V_i be vertex(i), let O be the current origin, and let length(A,B)
899       // be the length of edge (A,B).  At the start of each loop iteration, the
900       // "leading edge" of the triangle fan is (O,V_i), and we want to extend
901       // the triangle fan so that the leading edge is (O,V_i+1).
902       //
903       // Invariants:
904       //  1. length(O,V_i) < kMaxLength for all (i > 1).
905       //  2. Either O == V_0, or O is approximately perpendicular to V_0.
906       //  3. "sum" is the oriented integral of f over the area defined by
907       //     (O, V_0, V_1, ..., V_i).
908       enforce(i == 1 || S1ChordAngle(origin, vertex(i)) < kMaxLength);
909       enforce(origin == vertex(0) || fabs(origin.dotProd(vertex(0))) < 1e-15);
910 
911       if (S1ChordAngle(vertex(i + 1), origin) > kMaxLength) {
912         // We are about to create an unstable edge, so choose a new origin O'
913         // for the triangle fan.
914         S2Point old_origin = origin;
915         if (origin == vertex(0)) {
916           // The following point is well-separated from V_i and V_0 (and
917           // therefore V_i+1 as well).
918           origin = robustCrossProd(vertex(0), vertex(i)).normalize();
919         } else if (S1ChordAngle(vertex(i), vertex(0)) < kMaxLength) {
920           // All edges of the triangle (O, V_0, V_i) are stable, so we can
921           // revert to using V_0 as the origin.
922           origin = vertex(0);
923         } else {
924           // (O, V_i+1) and (V_0, V_i) are antipodal pairs, and O and V_0 are
925           // perpendicular.  Therefore V_0.CrossProd(O) is approximately
926           // perpendicular to all of {O, V_0, V_i, V_i+1}, and we can choose
927           // this point O' as the new origin.
928           origin = vertex(0).crossProd(old_origin);
929 
930           // Advance the edge (V_0,O) to (V_0,O').
931           sum += fTri(vertex(0), old_origin, origin);
932         }
933         // Advance the edge (O,V_i) to (O',V_i).
934         sum += fTri(old_origin, vertex(i), origin);
935       }
936       // Advance the edge (O,V_i) to (O,V_i+1).
937       sum += fTri(origin, vertex(i), vertex(i+1));
938     }
939     // If the origin is not V_0, we need to sum one more triangle.
940     if (origin != vertex(0)) {
941       // Advance the edge (O,V_n-1) to (O,V_0).
942       sum += fTri(origin, vertex(numVertices() - 1), vertex(0));
943     }
944     return sum;
945   }
946 
947   /**
948      Constructs a regular polygon with the given number of vertices, all
949      located on a circle of the specified radius around "center".  The radius
950      is the actual distance from "center" to each vertex.
951   */
952   static S2Loop makeRegularLoop(in S2Point center, S1Angle radius, int num_vertices) {
953     Matrix3x3_d m;
954     getFrame(center, m);  // TODO(ericv): Return by value
955     return makeRegularLoop(m, radius, num_vertices);
956   }
957 
958   /**
959      Like the function above, but this version constructs a loop centered
960      around the z-axis of the given coordinate frame, with the first vertex in
961      the direction of the positive x-axis.  (This allows the loop to be
962      rotated for testing purposes.)
963   */
964   static S2Loop makeRegularLoop(in Matrix3x3_d frame, S1Angle radius, int num_vertices) {
965     // We construct the loop in the given frame coordinates, with the center at
966     // (0, 0, 1).  For a loop of radius "r", the loop vertices have the form
967     // (x, y, z) where x^2 + y^2 = sin(r) and z = cos(r).  The distance on the
968     // sphere (arc length) from each vertex to the center is acos(cos(r)) = r.
969     double z = cos(radius.radians());
970     double r = sin(radius.radians());
971     double radian_step = 2 * M_PI / num_vertices;
972     S2Point[] vertices;
973     for (int i = 0; i < num_vertices; ++i) {
974       double angle = i * radian_step;
975       auto p = S2Point(r * cos(angle), r * sin(angle), z);
976       vertices ~= fromFrame(frame, p).normalize();
977     }
978     return new S2Loop(vertices);
979   }
980 
981   /// Returns the total number of bytes used by the loop.
982   size_t spaceUsed() const {
983     size_t size = this.classinfo.m_init.sizeof;
984     size += numVertices() * S2Point.sizeof;
985     // index_ itself is already included in sizeof(*this).
986     size += _index.spaceUsed() - _index.sizeof;
987     return size;
988   }
989 
990   ////////////////////////////////////////////////////////////////////////
991   // S2Region interface (see s2region.h for details):
992 
993   override
994   S2Loop clone() const {
995     return new S2Loop(this);
996   }
997 
998   /**
999      GetRectBound() returns essentially tight results, while GetCapBound()
1000      might have a lot of extra padding.  Both bounds are conservative in that
1001      if the loop contains a point P, then the bound contains P also.
1002   */
1003   override
1004   S2Cap getCapBound() const {
1005     return _bound.getCapBound();
1006   }
1007 
1008   override
1009   S2LatLngRect getRectBound() {
1010     return _bound;
1011   }
1012 
1013   override
1014   void getCellUnionBound(out S2CellId[] cell_ids) const {
1015     return getCapBound().getCellUnionBound(cell_ids);
1016   }
1017 
1018   override
1019   bool contains(in S2Cell target) {
1020     auto it = new MutableS2ShapeIndex.Iterator(_index);
1021     S2ShapeIndex.CellRelation relation = it.locate(target.id());
1022 
1023     // If "target" is disjoint from all index cells, it is not contained.
1024     // Similarly, if "target" is subdivided into one or more index cells then it
1025     // is not contained, since index cells are subdivided only if they (nearly)
1026     // intersect a sufficient number of edges.  (But note that if "target" itself
1027     // is an index cell then it may be contained, since it could be a cell with
1028     // no edges in the loop interior.)
1029     if (relation != S2ShapeIndex.CellRelation.INDEXED) return false;
1030 
1031     // Otherwise check if any edges intersect "target".
1032     if (boundaryApproxIntersects(it, target)) return false;
1033 
1034     // Otherwise check if the loop contains the center of "target".
1035     return contains(it, target.getCenter());
1036   }
1037 
1038   override
1039   bool mayIntersect(in S2Cell target) {
1040     auto it = new MutableS2ShapeIndex.Iterator(_index);
1041     S2ShapeIndex.CellRelation relation = it.locate(target.id());
1042 
1043     // If "target" does not overlap any index cell, there is no intersection.
1044     if (relation == S2ShapeIndex.CellRelation.DISJOINT) return false;
1045 
1046     // If "target" is subdivided into one or more index cells, there is an
1047     // intersection to within the S2ShapeIndex error bound (see Contains).
1048     if (relation == S2ShapeIndex.CellRelation.SUBDIVIDED) return true;
1049 
1050     // If "target" is an index cell, there is an intersection because index cells
1051     // are created only if they have at least one edge or they are entirely
1052     // contained by the loop.
1053     if (it.id() == target.id()) return true;
1054 
1055     // Otherwise check if any edges intersect "target".
1056     if (boundaryApproxIntersects(it, target)) return true;
1057 
1058     // Otherwise check if the loop contains the center of "target".
1059     return contains(it, target.getCenter());
1060   }
1061 
1062   // The point 'p' does not need to be normalized.
1063   override
1064   bool contains(in S2Point p) {
1065     // NOTE(ericv): A bounds check slows down this function by about 50%.  It is
1066     // worthwhile only when it might allow us to delay building the index.
1067     if (!_index.isFresh() && !_bound.contains(p)) return false;
1068 
1069     // For small loops it is faster to just check all the crossings.  We also
1070     // use this method during loop initialization because InitOriginAndBound()
1071     // calls Contains() before InitIndex().  Otherwise, we keep track of the
1072     // number of calls to Contains() and only build the index when enough calls
1073     // have been made so that we think it is worth the effort.  Note that the
1074     // code below is structured so that if many calls are made in parallel only
1075     // one thread builds the index, while the rest continue using brute force
1076     // until the index is actually available.
1077     //
1078     // The constants below were tuned using the benchmarks.  It turns out that
1079     // building the index costs roughly 50x as much as Contains().  (The ratio
1080     // increases slowly from 46x with 64 points to 61x with 256k points.)  The
1081     // textbook approach to this problem would be to wait until the cumulative
1082     // time we would have saved with an index approximately equals the cost of
1083     // building the index, and then build it.  (This gives the optimal
1084     // competitive ratio of 2; look up "competitive algorithms" for details.)
1085     // We set the limit somewhat lower than this (20 rather than 50) because
1086     // building the index may be forced anyway by other API calls, and so we
1087     // want to err on the side of building it too early.
1088 
1089     enum int kMaxBruteForceVertices = 32;
1090     enum int kMaxUnindexedContainsCalls = 20;  // See notes above.
1091     if (_index.numShapeIds() == 0  // InitIndex() not called yet
1092         || numVertices() <= kMaxBruteForceVertices
1093         || (!_index.isFresh() && atomicOp!"+="(_unindexedContainsCalls, 1) != kMaxUnindexedContainsCalls)) {
1094       return bruteForceContains(p);
1095     }
1096     // Otherwise we look up the S2ShapeIndex cell containing this point.  Note
1097     // the index is built automatically the first time an iterator is created.
1098     auto it = new MutableS2ShapeIndex.Iterator(_index);
1099     if (!it.locate(p)) return false;
1100     return contains(it, p);
1101   }
1102 
1103   /**
1104      Appends a serialized representation of the S2Loop to "encoder".
1105 
1106      Generally clients should not use S2Loop::Encode().  Instead they should
1107      encode an S2Polygon, which unlike this method supports (lossless)
1108      compression.
1109 
1110      REQUIRES: "encoder" uses the default constructor, so that its buffer
1111                can be enlarged as necessary by calling Ensure(int).
1112   */
1113   void encode(ORangeT)(Encoder!ORangeT encoder) const
1114   out (; encoder.avail >= 0) {
1115     encoder.ensure(numVertices() * S2Point.sizeof + 20);  // sufficient
1116 
1117     encoder.put8(CURRENT_LOSSLESS_ENCODING_VERSION_NUMBER);
1118     encoder.put32(numVertices());
1119     encoder.putRaw(_vertices);
1120     encoder.put8(_originInside);
1121     encoder.put32(_depth);
1122 
1123     _bound.encode(encoder);
1124   }
1125 
1126   /**
1127      Decodes a loop encoded with Encode() or the private method
1128      EncodeCompressed() (used by the S2Polygon encoder).  Returns true on
1129      success.
1130 
1131      This method may be called with loops that have already been initialized.
1132   */
1133   bool decode(IRangeT)(Decoder!IRangeT decoder) {
1134     if (decoder.avail() < ubyte.sizeof) return false;
1135     ubyte versionNum = decoder.get8();
1136     switch (versionNum) {
1137       case CURRENT_LOSSLESS_ENCODING_VERSION_NUMBER:
1138         return decodeInternal(decoder);
1139       default:
1140         return false;
1141     }
1142   }
1143 
1144   // Provides the same functionality as Decode, except that decoded regions
1145   // are allowed to point directly into the Decoder's memory buffer rather
1146   // than copying the data.  This can be much faster, but the decoded loop is
1147   // only valid within the scope (lifetime) of the Decoder's memory buffer.
1148   // bool DecodeWithinScope(Decoder* const decoder);
1149 
1150   ////////////////////////////////////////////////////////////////////////
1151   // Methods intended primarily for use by the S2Polygon implementation:
1152 
1153   /**
1154      Given two loops of a polygon, return true if A contains B.  This version
1155      of Contains() is cheap because it does not test for edge intersections.
1156      The loops must meet all the S2Polygon requirements; for example this
1157      implies that their boundaries may not cross or have any shared edges
1158      (although they may have shared vertices).
1159   */
1160   bool containsNested(S2Loop b) {
1161     if (!_subregionBound.contains(b._bound)) return false;
1162 
1163     // Special cases to handle either loop being empty or full.  Also bail out
1164     // when B has no vertices to avoid heap overflow on the vertex(1) call
1165     // below.  (This method is called during polygon initialization before the
1166     // client has an opportunity to call IsValid().)
1167     if (isEmptyOrFull() || b.numVertices() < 2) {
1168       return isFull() || b.isEmpty();
1169     }
1170 
1171     // We are given that A and B do not share any edges, and that either one
1172     // loop contains the other or they do not intersect.
1173     int m = findVertex(b.vertex(1));
1174     if (m < 0) {
1175       // Since b->vertex(1) is not shared, we can check whether A contains it.
1176       return contains(b.vertex(1));
1177     }
1178     // Check whether the edge order around b->vertex(1) is compatible with
1179     // A containing B.
1180     return wedgeContains(vertex(m-1), vertex(m), vertex(m+1), b.vertex(0), b.vertex(2));
1181   }
1182 
1183   /**
1184      Return +1 if A contains the boundary of B, -1 if A excludes the boundary
1185      of B, and 0 if the boundaries of A and B cross.  Shared edges are handled
1186      as follows: If XY is a shared edge, define Reversed(XY) to be true if XY
1187      appears in opposite directions in A and B.  Then A contains XY if and
1188      only if Reversed(XY) == B->is_hole().  (Intuitively, this checks whether
1189      A contains a vanishingly small region extending from the boundary of B
1190      toward the interior of the polygon to which loop B belongs.)
1191 
1192      This method is used for testing containment and intersection of
1193      multi-loop polygons.  Note that this method is not symmetric, since the
1194      result depends on the direction of loop A but not on the direction of
1195      loop B (in the absence of shared edges).
1196 
1197      REQUIRES: neither loop is empty.
1198      REQUIRES: if b->is_full(), then !b->is_hole().
1199   */
1200   int compareBoundary(S2Loop b)
1201   in {
1202     assert(!isEmpty() && !b.isEmpty());
1203     assert(!b.isFull() || !b.isHole());
1204   } do {
1205     // The bounds must intersect for containment or crossing.
1206     if (!_bound.intersects(b._bound)) return -1;
1207 
1208     // Full loops are handled as though the loop surrounded the entire sphere.
1209     if (isFull()) return 1;
1210     if (b.isFull()) return -1;
1211 
1212     // Check whether there are any edge crossings, and also check the loop
1213     // relationship at any shared vertices.
1214     auto relation = new CompareBoundaryRelation(b.isHole());
1215     if (hasCrossingRelation(this, b, relation)) return 0;
1216     if (relation.foundSharedVertex()) {
1217       return relation.containsEdge() ? 1 : -1;
1218     }
1219 
1220     // There are no edge intersections or shared vertices, so we can check
1221     // whether A contains an arbitrary vertex of B.
1222     return contains(b.vertex(0)) ? 1 : -1;
1223   }
1224 
1225   /**
1226      Given two loops whose boundaries do not cross (see CompareBoundary),
1227      return true if A contains the boundary of B.  If "reverse_b" is true, the
1228      boundary of B is reversed first (which only affects the result when there
1229      are shared edges).  This method is cheaper than CompareBoundary() because
1230      it does not test for edge intersections.
1231 
1232      REQUIRES: neither loop is empty.
1233      REQUIRES: if b->is_full(), then reverse_b == false.
1234   */
1235   package bool containsNonCrossingBoundary(in S2Loop b, bool reverse_b)
1236   in {
1237     assert(!isEmpty() && !b.isEmpty());
1238     assert(!b.isFull() || !reverse_b);
1239   } do {
1240     // The bounds must intersect for containment.
1241     if (!_bound.intersects(b._bound)) return false;
1242 
1243     // Full loops are handled as though the loop surrounded the entire sphere.
1244     if (isFull()) return true;
1245     if (b.isFull()) return false;
1246 
1247     int m = findVertex(b.vertex(0));
1248     if (m < 0) {
1249       // Since vertex b0 is not shared, we can check whether A contains it.
1250       return contains(b.vertex(0));
1251     }
1252     // Otherwise check whether the edge (b0, b1) is contained by A.
1253     return wedgeContainsSemiwedge(vertex(m-1), vertex(m), vertex(m+1), b.vertex(1), reverse_b);
1254   }
1255 
1256   /**
1257      Wrapper class for indexing a loop (see S2ShapeIndex).  Once this object
1258      is inserted into an S2ShapeIndex it is owned by that index, and will be
1259      automatically deleted when no longer needed by the index.  Note that this
1260      class does not take ownership of the loop itself (see OwningShape below).
1261      You can also subtype this class to store additional data (see S2Shape for
1262      details).
1263   */
1264   static class Shape : S2Shape {
1265   public:
1266     /// Must call Init().
1267     this() {
1268       _loop = null;
1269     }
1270 
1271     /// Initialize the shape.  Does not take ownership of "loop".
1272     this(S2Loop loop) {
1273       initialize(loop);
1274     }
1275 
1276     void initialize(S2Loop loop) {
1277       _loop = loop;
1278     }
1279 
1280     inout(S2Loop) loop() inout {
1281       return _loop;
1282     }
1283 
1284     // S2Shape interface:
1285     final override
1286     int numEdges() const {
1287       return _loop.isEmptyOrFull() ? 0 : _loop.numVertices();
1288     }
1289 
1290     final override
1291     Edge edge(int e) const {
1292       return S2Shape.Edge(_loop.vertex(e), _loop.vertex(e + 1));
1293     }
1294 
1295     final override
1296     int dimension() const {
1297       return 2;
1298     }
1299 
1300     final override
1301     S2Shape.ReferencePoint getReferencePoint() const {
1302       return S2Shape.ReferencePoint(origin(), _loop.containsOrigin());
1303     }
1304 
1305     final override
1306     int numChains() const {
1307       return _loop.isEmptyOrFull() ? 0 : 1;
1308     }
1309 
1310     final override
1311     Chain chain(int i) const
1312     in {
1313       assert(i == 0);
1314     } do {
1315       return Chain(0, numEdges());
1316     }
1317 
1318     final override
1319     Edge chainEdge(int i, int j) const
1320     in {
1321       assert(i == 0);
1322     } do {
1323       return Edge(_loop.vertex(j), _loop.vertex(j + 1));
1324     }
1325 
1326     final override
1327     ChainPosition chainPosition(int e) const {
1328       return ChainPosition(0, e);
1329     }
1330 
1331    private:
1332     S2Loop _loop;
1333   }
1334 
1335   // Like Shape, except that the S2Loop is automatically deleted when this
1336   // object is deleted by the S2ShapeIndex.  This is useful when an S2Loop
1337   // is constructed solely for the purpose of indexing it.
1338   //
1339   // Not needed in GC languages.
1340   // class OwningShape : public Shape { ... }
1341 
1342   int opCmp(in S2Loop other) const {
1343     import std.algorithm : cmp;
1344     return cmp(_vertices, other._vertices);
1345   }
1346 
1347 package:
1348   /// Returns true if this loop contains S2.origin().
1349   bool containsOrigin() const {
1350     return _originInside;
1351   }
1352 
1353 package:
1354   /// Internal copy constructor used only by Clone() that makes a deep copy of its argument.
1355   this(in S2Loop src) {
1356     this();
1357     _depth = src._depth;
1358     _vertices = src._vertices.dup;
1359     _s2DebugOverride = src._s2DebugOverride;
1360     _originInside = src._originInside;
1361     _unindexedContainsCalls = 0;
1362     _bound = src._bound.clone();
1363     _subregionBound = src._subregionBound.clone();
1364     initIndex();
1365   }
1366 
1367 private:
1368   // Any single-vertex loop is interpreted as being either the empty loop or the
1369   // full loop, depending on whether the vertex is in the northern or southern
1370   // hemisphere respectively.
1371 
1372   /// The single vertex in the "empty loop" vertex chain.
1373   static S2Point emptyVertex() {
1374     return S2Point(0, 0, 1);
1375   }
1376 
1377   /// The single vertex in the "full loop" vertex chain.
1378   static S2Point fullVertex() {
1379     return S2Point(0, 0, -1);
1380   }
1381 
1382   void initOriginAndBound() {
1383     import s2.s2predicates : orderedCCW;
1384     import s2.s2pointutil : ortho;
1385     if (numVertices() < 3) {
1386       // Check for the special "empty" and "full" loops (which have one vertex).
1387       if (!isEmptyOrFull()) {
1388         _originInside = false;
1389         return;  // Bail out without trying to access non-existent vertices.
1390       }
1391       // If the vertex is in the southern hemisphere then the loop is full,
1392       // otherwise it is empty.
1393       _originInside = (vertex(0).z() < 0);
1394     } else {
1395       // Point containment testing is done by counting edge crossings starting
1396       // at a fixed point on the sphere (S2::Origin()).  Historically this was
1397       // important, but it is now no longer necessary, and it may be worthwhile
1398       // experimenting with using a loop vertex as the reference point.  In any
1399       // case, we need to know whether the reference point (S2::Origin) is
1400       // inside or outside the loop before we can construct the S2ShapeIndex.
1401       // We do this by first guessing that it is outside, and then seeing
1402       // whether we get the correct containment result for vertex 1.  If the
1403       // result is incorrect, the origin must be inside the loop.
1404       //
1405       // A loop with consecutive vertices A,B,C contains vertex B if and only if
1406       // the fixed vector R = S2::Ortho(B) is contained by the wedge ABC.  The
1407       // wedge is closed at A and open at C, i.e. the point B is inside the loop
1408       // if A=R but not if C=R.  This convention is required for compatibility
1409       // with S2::VertexCrossing.  (Note that we can't use S2::Origin()
1410       // as the fixed vector because of the possibility that B == S2::Origin().)
1411       //
1412       // TODO(ericv): Investigate using vertex(0) as the reference point.
1413 
1414       _originInside = false;  // Initialize before calling Contains().
1415       bool v1_inside = orderedCCW(ortho(vertex(1)), vertex(0), vertex(2), vertex(1));
1416       // Note that Contains(S2Point) only does a bounds check once InitIndex()
1417       // has been called, so it doesn't matter that bound_ is undefined here.
1418       if (v1_inside != contains(vertex(1))) {
1419         _originInside = true;
1420       }
1421     }
1422     // We *must* call InitBound() before InitIndex(), because InitBound() calls
1423     // Contains(S2Point), and Contains(S2Point) does a bounds check whenever the
1424     // index is not fresh (i.e., the loop has been added to the index but the
1425     // index has not been updated yet).
1426     //
1427     // TODO(ericv): When fewer S2Loop methods depend on internal bounds checks,
1428     // consider computing the bound on demand as well.
1429     initBound();
1430     initIndex();
1431   }
1432 
1433   void initBound() {
1434     // Check for the special "empty" and "full" loops.
1435     if (isEmptyOrFull()) {
1436       if (isEmpty()) {
1437         _subregionBound = _bound = S2LatLngRect.empty();
1438       } else {
1439         _subregionBound = _bound = S2LatLngRect.full();
1440       }
1441       return;
1442     }
1443 
1444     // The bounding rectangle of a loop is not necessarily the same as the
1445     // bounding rectangle of its vertices.  First, the maximal latitude may be
1446     // attained along the interior of an edge.  Second, the loop may wrap
1447     // entirely around the sphere (e.g. a loop that defines two revolutions of a
1448     // candy-cane stripe).  Third, the loop may include one or both poles.
1449     // Note that a small clockwise loop near the equator contains both poles.
1450 
1451     auto bounder = new S2LatLngRectBounder();
1452     for (int i = 0; i <= numVertices(); ++i) {
1453       bounder.addPoint(vertex(i));
1454     }
1455     S2LatLngRect b = bounder.getBound();
1456     if (contains(S2Point(0, 0, 1))) {
1457       b = new S2LatLngRect(R1Interval(b.lat().lo(), M_PI_2), S1Interval.full());
1458     }
1459     // If a loop contains the south pole, then either it wraps entirely
1460     // around the sphere (full longitude range), or it also contains the
1461     // north pole in which case b.lng().is_full() due to the test above.
1462     // Either way, we only need to do the south pole containment test if
1463     // b.lng().is_full().
1464     if (b.lng().isFull() && contains(S2Point(0, 0, -1))) {
1465       b.mutableLat().setLo(-M_PI_2);
1466     }
1467     _bound = b;
1468     _subregionBound = S2LatLngRectBounder.expandForSubregions(_bound);
1469   }
1470 
1471   void initIndex() {
1472     import s2.s2debug : flagsS2Debug;
1473     _index.add(new Shape(this));
1474     if (!LAZY_INDEXING) {
1475       _index.forceBuild();
1476     }
1477     if (flagsS2Debug && _s2DebugOverride == S2Debug.ALLOW) {
1478       // Note that FLAGS_s2debug is false in optimized builds (by default).
1479       enforce(isValid());
1480     }
1481   }
1482 
1483   // A version of Contains(S2Point) that does not use the S2ShapeIndex.
1484   // Used by the S2Polygon implementation.
1485   package bool bruteForceContains(in S2Point p) const {
1486     // Empty and full loops don't need a special case, but invalid loops with
1487     // zero vertices do, so we might as well handle them all at once.
1488     if (numVertices() < 3) return _originInside;
1489 
1490     S2Point origin = origin();
1491     auto crosser = new S2CopyingEdgeCrosser(origin, p, vertex(0));
1492     bool inside = _originInside;
1493     for (int i = 1; i <= numVertices(); ++i) {
1494       inside ^= crosser.edgeOrVertexCrossing(vertex(i));
1495     }
1496     return inside;
1497   }
1498 
1499   /**
1500      Internal implementation of the Decode and DecodeWithinScope methods above.
1501      If within_scope is true, memory is allocated for vertices_ and data
1502      is copied from the decoder using std::copy. If it is false, vertices_
1503      will point to the memory area inside the decoder, and the field
1504      owns_vertices_ is set to false.
1505   */
1506   bool decodeInternal(IRangeT)(Decoder!IRangeT decoder) {
1507     // Perform all checks before modifying vertex state. Empty loops are
1508     // explicitly allowed here: a newly created loop has zero vertices
1509     // and such loops encode and decode properly.
1510     if (decoder.avail() < uint.sizeof) return false;
1511     uint num_vertices = decoder.get32();
1512     if (num_vertices > DECODE_MAX_NUM_VERTICES) {
1513       return false;
1514     }
1515     if (decoder.avail() < (num_vertices * S2Point.sizeof + ubyte.sizeof + uint.sizeof)) {
1516       return false;
1517     }
1518     clearIndex();
1519     _vertices = decoder.getRaw!S2Point(num_vertices);
1520 
1521     _originInside = cast(bool) decoder.get8();
1522     _depth = decoder.get32();
1523     if (!_bound.decode(decoder)) return false;
1524     _subregionBound = S2LatLngRectBounder.expandForSubregions(_bound);
1525 
1526     // An initialized loop will have some non-zero count of vertices. A default
1527     // (uninitialized) has zero vertices. This code supports encoding and
1528     // decoding of uninitialized loops, but we only want to call InitIndex for
1529     // initialized loops. Otherwise we defer InitIndex until the call to Init().
1530     if (numVertices() > 0) {
1531       initIndex();
1532     }
1533 
1534     return true;
1535   }
1536 
1537   /**
1538    * Converts the loop vertices to the S2XYZFaceSiTi format and store the result
1539    * in the given array, which must be large enough to store all the vertices.
1540    */
1541   package void getXYZFaceSiTiVertices(ref S2XYZFaceSiTi[] vertices, size_t current_index) const {
1542     for (int i = 0; i < numVertices(); ++i) {
1543       size_t index = current_index + i;
1544       vertices[index].xyz = vertex(i);
1545       vertices[index].cellLevel = XYZtoFaceSiTi(
1546           vertices[index].xyz, vertices[index].face, vertices[index].si, vertices[index].ti);
1547     }
1548   }
1549 
1550   // Encode the loop's vertices using S2EncodePointsCompressed.  Uses
1551   // approximately 8 bytes for the first vertex, going down to less than 4 bytes
1552   // per vertex on Google's geographic repository, plus 24 bytes per vertex that
1553   // does not correspond to the center of a cell at level 'snap_level'. The loop
1554   // vertices must first be converted to the S2XYZFaceSiTi format with
1555   // GetXYZFaceSiTiVertices.
1556   //
1557   // REQUIRES: the loop is initialized and valid.
1558   // void EncodeCompressed(Encoder* encoder, const S2XYZFaceSiTi* vertices,
1559   //                       int snap_level) const;
1560 
1561   // Decode a loop encoded with EncodeCompressed. The parameters must be the
1562   // same as the one used when EncodeCompressed was called.
1563   // bool DecodeCompressed(Decoder* decoder, int snap_level);
1564 
1565   // Returns a bitset of properties used by EncodeCompressed
1566   // to efficiently encode boolean values.  Properties are
1567   // origin_inside and whether the bound was encoded.
1568   // std::bitset<2> GetCompressedEncodingProperties() const;
1569 
1570   /**
1571      Given an iterator that is already positioned at the S2ShapeIndexCell
1572      containing "p", returns Contains(p).
1573   */
1574   bool contains(in MutableS2ShapeIndex.Iterator it, in S2Point p) const {
1575     // Test containment by drawing a line segment from the cell center to the
1576     // given point and counting edge crossings.
1577     const(S2ClippedShape) a_clipped = it.cell().clipped(0);
1578     bool inside = a_clipped.containsCenter();
1579     int a_num_edges = a_clipped.numEdges();
1580     if (a_num_edges > 0) {
1581       S2Point center = it.center();
1582       auto crosser = new S2CopyingEdgeCrosser(center, p);
1583       int ai_prev = -2;
1584       for (int i = 0; i < a_num_edges; ++i) {
1585         int ai = a_clipped.edge(i);
1586         if (ai != ai_prev + 1) crosser.restartAt(vertex(ai));
1587         ai_prev = ai;
1588         inside ^= crosser.edgeOrVertexCrossing(vertex(ai+1));
1589       }
1590     }
1591     return inside;
1592   }
1593 
1594   /**
1595      Returns true if the loop boundary intersects "target".  It may also
1596      return true when the loop boundary does not intersect "target" but
1597      some edge comes within the worst-case error tolerance.
1598 
1599      REQUIRES: it.id().contains(target.id())
1600      [This condition is true whenever it.Locate(target) returns INDEXED.]
1601   */
1602   bool boundaryApproxIntersects(in MutableS2ShapeIndex.Iterator it, in S2Cell target) const
1603   in {
1604     assert(it.id().contains(target.id()));
1605   } do {
1606     import s2.s2edge_clipping :
1607         clipToPaddedFace, intersectsRect, FACE_CLIP_ERROR_UV_COORD, INTERSECTS_RECT_ERROR_UV_DIST;
1608 
1609     const S2ClippedShape a_clipped = it.cell().clipped(0);
1610     int a_num_edges = a_clipped.numEdges();
1611 
1612     // If there are no edges, there is no intersection.
1613     if (a_num_edges == 0) return false;
1614 
1615     // We can save some work if "target" is the index cell itself.
1616     if (it.id() == target.id()) return true;
1617 
1618     // Otherwise check whether any of the edges intersect "target".
1619     static const double kMaxError = FACE_CLIP_ERROR_UV_COORD + INTERSECTS_RECT_ERROR_UV_DIST;
1620     R2Rect bound = target.getBoundUV().expanded(kMaxError);
1621     for (int i = 0; i < a_num_edges; ++i) {
1622       int ai = a_clipped.edge(i);
1623       R2Point v0, v1;
1624       if (clipToPaddedFace(vertex(ai), vertex(ai+1), target.face(), kMaxError, v0, v1)
1625           && intersectsRect(v0, v1, bound)) {
1626         return true;
1627       }
1628     }
1629     return false;
1630   }
1631 
1632   /**
1633      Returns an index "first" and a direction "dir" (either +1 or -1) such that
1634      the vertex sequence (first, first+dir, ..., first+(n-1)*dir) does not
1635      change when the loop vertex order is rotated or inverted.  This allows
1636      the loop vertices to be traversed in a canonical order.  The return
1637      values are chosen such that (first, ..., first+n*dir) are in the range
1638      [0, 2*n-1] as expected by the vertex() method.
1639   */
1640   package int getCanonicalFirstVertex(out int dir) const {
1641     int first = 0;
1642     int n = numVertices();
1643     for (int i = 1; i < n; ++i) {
1644       if (vertex(i) < vertex(first)) first = i;
1645     }
1646     if (vertex(first + 1) < vertex(first + n - 1)) {
1647       dir = 1;
1648       // 0 <= first <= n-1, so (first+n*dir) <= 2*n-1.
1649     } else {
1650       dir = -1;
1651       first += n;
1652       // n <= first <= 2*n-1, so (first+n*dir) >= 0.
1653     }
1654     return first;
1655   }
1656 
1657   /**
1658      Returns the index of a vertex at point "p", or -1 if not found.
1659      The return value is in the range 1..num_vertices_ if found.
1660   */
1661   int findVertex(in S2Point p) {
1662     if (numVertices() < 10) {
1663       // Exhaustive search.  Return value must be in the range [1..N].
1664       for (int i = 1; i <= numVertices(); ++i) {
1665         if (vertex(i) == p) return i;
1666       }
1667       return -1;
1668     }
1669     auto it = new MutableS2ShapeIndex.Iterator(_index);
1670     if (!it.locate(p)) return -1;
1671 
1672     const(S2ClippedShape) a_clipped = it.cell().clipped(0);
1673     for (int i = a_clipped.numEdges() - 1; i >= 0; --i) {
1674       int ai = a_clipped.edge(i);
1675       // Return value must be in the range [1..N].
1676       if (vertex(ai) == p) return (ai == 0) ? numVertices() : ai;
1677       if (vertex(ai+1) == p) return ai+1;
1678     }
1679     return -1;
1680   }
1681 
1682   /**
1683      This method checks all edges of loop A for intersection against all edges
1684      of loop B.  If there is any shared vertex, the wedges centered at this
1685      vertex are sent to "relation".
1686 
1687      If the two loop boundaries cross, this method is guaranteed to return
1688      true.  It also returns true in certain cases if the loop relationship is
1689      equivalent to crossing.  For example, if the relation is Contains() and a
1690      point P is found such that B contains P but A does not contain P, this
1691      method will return true to indicate that the result is the same as though
1692      a pair of crossing edges were found (since Contains() returns false in
1693      both cases).
1694 
1695      See Contains(), Intersects() and CompareBoundary() for the three uses of
1696      this function.
1697   */
1698   static bool hasCrossingRelation(S2Loop a, S2Loop b, LoopRelation relation) {
1699     // We look for S2CellId ranges where the indexes of A and B overlap, and
1700     // then test those edges for crossings.
1701     auto ai = new RangeIterator(a._index);
1702     auto bi = new RangeIterator(b._index);
1703     auto ab = new LoopCrosser(a, b, relation, false);  // Tests edges of A against B
1704     auto ba = new LoopCrosser(b, a, relation, true);   // Tests edges of B against A
1705     int cnt = 0;
1706     while (!ai.done() || !bi.done()) {
1707       if (ai.rangeMax() < bi.rangeMin()) {
1708         // The A and B cells don't overlap, and A precedes B.
1709         ai.seekTo(bi);
1710       } else if (bi.rangeMax() < ai.rangeMin()) {
1711         // The A and B cells don't overlap, and B precedes A.
1712         bi.seekTo(ai);
1713       } else {
1714         // One cell contains the other.  Determine which cell is larger.
1715         long ab_relation = ai.id().lsb() - bi.id().lsb();
1716         if (ab_relation > 0) {
1717           // A's index cell is larger.
1718           if (ab.hasCrossingRelation(ai, bi)) return true;
1719         } else if (ab_relation < 0) {
1720           // B's index cell is larger.
1721           if (ba.hasCrossingRelation(bi, ai)) return true;
1722         } else {
1723           // The A and B cells are the same.  Since the two cells have the same
1724           // center point P, check whether P satisfies the crossing targets.
1725           if (ai.containsCenter() == ab.aCrossingTarget()
1726               && bi.containsCenter() == ab.bCrossingTarget()) {
1727             return true;
1728           }
1729           // Otherwise test all the edge crossings directly.
1730           if (ai.numEdges() > 0 && bi.numEdges() > 0
1731               && ab.cellCrossesCell(ai.clipped(), bi.clipped())) {
1732             return true;
1733           }
1734           ai.next();
1735           bi.next();
1736         }
1737       }
1738     }
1739     return false;
1740   }
1741 
1742   /**
1743      When the loop is modified (Invert(), or Init() called again) then the
1744      indexing structures need to be cleared since they become invalid.
1745   */
1746   void clearIndex() {
1747     atomicStore!(MemoryOrder.raw)(_unindexedContainsCalls, 0);
1748     _index.clear();
1749   }
1750 
1751   /**
1752      The nesting depth, if this field belongs to an S2Polygon.  We define it
1753      here to optimize field packing.
1754   */
1755   int _depth = 0;
1756 
1757   /**
1758      We store the vertices in an array rather than a vector because we don't
1759      need any STL methods, and computing the number of vertices using size()
1760      would be relatively expensive (due to division by sizeof(S2Point) == 24).
1761      When DecodeWithinScope is used to initialize the loop, we do not
1762      take ownership of the memory for vertices_, and the owns_vertices_ field
1763      is used to prevent deallocation and overwriting.
1764   */
1765   S2Point[] _vertices;
1766 
1767   S2Debug _s2DebugOverride = S2Debug.ALLOW;
1768   bool _originInside = false;  // Does the loop contain S2::Origin()?
1769 
1770   /**
1771      In general we build the index the first time it is needed, but we make an
1772      exception for Contains(S2Point) because this method has a simple brute
1773      force implementation that is also relatively cheap.  For this one method
1774      we keep track of the number of calls made and only build the index once
1775      enough calls have been made that we think an index would be worthwhile.
1776   */
1777   shared int _unindexedContainsCalls;
1778 
1779   /**
1780      "bound_" is a conservative bound on all points contained by this loop:
1781      if A.Contains(P), then A.bound_.Contains(S2LatLng(P)).
1782   */
1783   S2LatLngRect _bound;
1784 
1785   /**
1786      Since "bound_" is not exact, it is possible that a loop A contains
1787      another loop B whose bounds are slightly larger.  "subregion_bound_"
1788      has been expanded sufficiently to account for this error, i.e.
1789      if A.Contains(B), then A.subregion_bound_.Contains(B.bound_).
1790   */
1791   S2LatLngRect _subregionBound;
1792 
1793   /// Spatial index for this loop.
1794   MutableS2ShapeIndex _index;
1795 }
1796 
1797 /// Loop relation for Contains().
1798 class ContainsRelation : LoopRelation {
1799 public:
1800   this() {
1801     _foundSharedVertex = false;
1802   }
1803 
1804   bool foundSharedVertex() const {
1805     return _foundSharedVertex;
1806   }
1807 
1808   // If A.Contains(P) == false && B.Contains(P) == true, it is equivalent to
1809   // having an edge crossing (i.e., Contains returns false).
1810   override
1811   int aCrossingTarget() const {
1812     return false;
1813   }
1814 
1815   override
1816   int bCrossingTarget() const {
1817     return true;
1818   }
1819 
1820   override
1821   bool wedgesCross(
1822       in S2Point a0, in S2Point ab1, in S2Point a2,
1823       in S2Point b0, in S2Point b2) {
1824     _foundSharedVertex = true;
1825     return !wedgeContains(a0, ab1, a2, b0, b2);
1826   }
1827 
1828 private:
1829   bool _foundSharedVertex;
1830 }
1831 
1832 /// Loop relation for Intersects().
1833 class IntersectsRelation : LoopRelation {
1834  public:
1835   this() {
1836     _foundSharedVertex = false;
1837   }
1838 
1839   bool foundSharedVertex() const {
1840     return _foundSharedVertex;
1841   }
1842 
1843   // If A.Contains(P) == true && B.Contains(P) == true, it is equivalent to
1844   // having an edge crossing (i.e., Intersects returns true).
1845   final override
1846   int aCrossingTarget() const {
1847     return true;
1848   }
1849 
1850   final override
1851   int bCrossingTarget() const {
1852     return true;
1853   }
1854 
1855   override
1856   bool wedgesCross(
1857       in S2Point a0, in S2Point ab1, in S2Point a2,
1858       in S2Point b0, in S2Point b2) {
1859     _foundSharedVertex = true;
1860     return wedgeIntersects(a0, ab1, a2, b0, b2);
1861   }
1862 
1863 private:
1864   bool _foundSharedVertex;
1865 }
1866 
1867 // Returns true if the wedge (a0, ab1, a2) contains the "semiwedge" defined as
1868 // any non-empty open set of rays immediately CCW from the edge (ab1, b2).  If
1869 // "reverse_b" is true, then substitute "clockwise" for "CCW"; this simulates
1870 // what would happen if the direction of loop B was reversed.
1871 private bool wedgeContainsSemiwedge(
1872     in S2Point a0, in S2Point ab1, in S2Point a2, in S2Point b2, bool reverse_b) {
1873   if (b2 == a0 || b2 == a2) {
1874     // We have a shared or reversed edge.
1875     return (b2 == a0) == reverse_b;
1876   } else {
1877     return orderedCCW(a0, a2, b2, ab1);
1878   }
1879 }
1880 
1881 /// Loop relation for CompareBoundary().
1882 class CompareBoundaryRelation : LoopRelation {
1883 public:
1884   this(bool reverse_b) {
1885     _reverseB = reverse_b;
1886     _foundSharedVertex = false;
1887     _containsEdge = false;
1888     _excludesEdge = false;
1889   }
1890 
1891   bool foundSharedVertex() const {
1892     return _foundSharedVertex;
1893   }
1894 
1895   bool containsEdge() const {
1896     return _containsEdge;
1897   }
1898 
1899   // The CompareBoundary relation does not have a useful early-exit condition,
1900   // so we return -1 for both crossing targets.
1901   //
1902   // Aside: A possible early exit condition could be based on the following.
1903   //   If A contains a point of both B and ~B, then A intersects Boundary(B).
1904   //   If ~A contains a point of both B and ~B, then ~A intersects Boundary(B).
1905   //   So if the intersections of {A, ~A} with {B, ~B} are all non-empty,
1906   //   the return value is 0, i.e., Boundary(A) intersects Boundary(B).
1907   // Unfortunately it isn't worth detecting this situation because by the
1908   // time we have seen a point in all four intersection regions, we are also
1909   // guaranteed to have seen at least one pair of crossing edges.
1910   override
1911   int aCrossingTarget() const {
1912     return -1;
1913   }
1914 
1915   override
1916   int bCrossingTarget() const {
1917     return -1;
1918   }
1919 
1920   override
1921   bool wedgesCross(
1922       in S2Point a0, in S2Point ab1, in S2Point a2,
1923       in S2Point b0, in S2Point b2) {
1924     // Because we don't care about the interior of B, only its boundary, it is
1925     // sufficient to check whether A contains the semiwedge (ab1, b2).
1926     _foundSharedVertex = true;
1927     if (wedgeContainsSemiwedge(a0, ab1, a2, b2, _reverseB)) {
1928       _containsEdge = true;
1929     } else {
1930       _excludesEdge = true;
1931     }
1932     return _containsEdge & _excludesEdge;
1933   }
1934 
1935 protected:
1936   const bool _reverseB;      // True if loop B should be reversed.
1937   bool _foundSharedVertex;   // True if any wedge was processed.
1938   bool _containsEdge;        // True if any edge of B is contained by A.
1939   bool _excludesEdge;        // True if any edge of B is excluded by A.
1940 }
1941 
1942 /// LoopRelation is an abstract class that defines a relationship between two
1943 /// loops (Contains, Intersects, or CompareBoundary).
1944 abstract class LoopRelation {
1945 public:
1946   this() {}
1947 
1948   /**
1949      Optionally, a_target() and b_target() can specify an early-exit condition
1950      for the loop relation.  If any point P is found such that
1951 
1952        A.Contains(P) == a_crossing_target() &&
1953        B.Contains(P) == b_crossing_target()
1954 
1955      then the loop relation is assumed to be the same as if a pair of crossing
1956      edges were found.  For example, the Contains() relation has
1957 
1958        a_crossing_target() == 0
1959        b_crossing_target() == 1
1960 
1961      because if A.Contains(P) == 0 (false) and B.Contains(P) == 1 (true) for
1962      any point P, then it is equivalent to finding an edge crossing (i.e.,
1963      since Contains() returns false in both cases).
1964 
1965      Loop relations that do not have an early-exit condition of this form
1966      should return -1 for both crossing targets.
1967   */
1968   int aCrossingTarget() const;
1969   int bCrossingTarget() const;
1970 
1971   /**
1972      Given a vertex "ab1" that is shared between the two loops, return true if
1973      the two associated wedges (a0, ab1, b2) and (b0, ab1, b2) are equivalent
1974      to an edge crossing.  The loop relation is also allowed to maintain its
1975      own internal state, and can return true if it observes any sequence of
1976      wedges that are equivalent to an edge crossing.
1977   */
1978   bool wedgesCross(
1979       in S2Point a0, in S2Point ab1,
1980       in S2Point a2, in S2Point b0,
1981       in S2Point b2);
1982 }
1983 
1984 /**
1985    RangeIterator is a wrapper over MutableS2ShapeIndex::Iterator with extra
1986    methods that are useful for merging the contents of two or more
1987    S2ShapeIndexes.
1988 */
1989 class RangeIterator {
1990 public:
1991   /// Construct a new RangeIterator positioned at the first cell of the index.
1992   this(MutableS2ShapeIndex index) {
1993     _it = new MutableS2ShapeIndex.Iterator(index, S2ShapeIndex.InitialPosition.BEGIN);
1994     refresh();
1995   }
1996 
1997   /// The current S2CellId and cell contents.
1998   S2CellId id() const {
1999     return _it.id();
2000   }
2001 
2002   const(S2ShapeIndexCell) cell() const {
2003     return _it.cell();
2004   }
2005 
2006   /// The min and max leaf cell ids covered by the current cell.  If Done() is
2007   /// true, these methods return a value larger than any valid cell id.
2008   S2CellId rangeMin() const {
2009     return _rangeMin;
2010   }
2011 
2012   S2CellId rangeMax() const {
2013     return _rangeMax;
2014   }
2015 
2016   /// Various other convenience methods for the current cell.
2017   const(S2ClippedShape) clipped() const {
2018     return cell().clipped(0);
2019   }
2020 
2021   int numEdges() const {
2022     return clipped().numEdges();
2023   }
2024 
2025   bool containsCenter() const {
2026     return clipped().containsCenter();
2027   }
2028 
2029   void next() {
2030     _it.next();
2031     refresh();
2032   }
2033 
2034   bool done() {
2035     return _it.done();
2036   }
2037 
2038   /// Positions the iterator at the first cell that overlaps or follows
2039   /// "target", i.e. such that range_max() >= target.range_min().
2040   void seekTo(in RangeIterator target) {
2041     _it.seek(target.rangeMin());
2042     // If the current cell does not overlap "target", it is possible that the
2043     // previous cell is the one we are looking for.  This can only happen when
2044     // the previous cell contains "target" but has a smaller S2CellId.
2045     if (_it.done() || _it.id().rangeMin() > target.rangeMax()) {
2046       if (_it.prev() && _it.id().rangeMax() < target.id()) _it.next();
2047     }
2048     refresh();
2049   }
2050 
2051   /// Positions the iterator at the first cell that follows "target", i.e. the
2052   /// first cell such that range_min() > target.range_max().
2053   void seekBeyond(in RangeIterator target) {
2054     _it.seek(target.rangeMax().next());
2055     if (!_it.done() && _it.id().rangeMin() <= target.rangeMax()) {
2056       _it.next();
2057     }
2058     refresh();
2059   }
2060 
2061 private:
2062   /// Updates internal state after the iterator has been repositioned.
2063   void refresh() {
2064     _rangeMin = id().rangeMin();
2065     _rangeMax = id().rangeMax();
2066   }
2067 
2068   MutableS2ShapeIndex.Iterator _it;
2069   S2CellId _rangeMin, _rangeMax;
2070   S2ClippedShape _clipped;
2071 }
2072 
2073 /**
2074    LoopCrosser is a helper class for determining whether two loops cross.
2075    It is instantiated twice for each pair of loops to be tested, once for the
2076    pair (A,B) and once for the pair (B,A), in order to be able to process
2077    edges in either loop nesting order.
2078 */
2079 class LoopCrosser {
2080 public:
2081   /**
2082      If "swapped" is true, the loops A and B have been swapped.  This affects
2083      how arguments are passed to the given loop relation, since for example
2084      A.Contains(B) is not the same as B.Contains(A).
2085   */
2086   this(S2Loop a, S2Loop b, LoopRelation relation, bool swapped) {
2087     _a = a;
2088     _b = b;
2089     _relation = relation;
2090     _swapped = swapped;
2091     _aCrossingTarget = relation.aCrossingTarget();
2092     _bCrossingTarget = relation.bCrossingTarget();
2093     _bQuery = new S2CrossingEdgeQuery(b._index);
2094     if (swapped) swap(_aCrossingTarget, _bCrossingTarget);
2095     _crosser = new S2CopyingEdgeCrosser();
2096   }
2097 
2098   /**
2099      Returns the crossing targets for the loop relation, taking into account
2100      whether the loops have been swapped.
2101   */
2102   int aCrossingTarget() const {
2103     return _aCrossingTarget;
2104   }
2105 
2106   int bCrossingTarget() const {
2107     return _bCrossingTarget;
2108   }
2109 
2110   /**
2111      Given two iterators positioned such that ai->id().Contains(bi->id()),
2112      return true if there is a crossing relationship anywhere within ai->id().
2113      Specifically, this method returns true if there is an edge crossing, a
2114      wedge crossing, or a point P that matches both "crossing targets".
2115      Advances both iterators past ai->id().
2116   */
2117   bool hasCrossingRelation(RangeIterator ai, RangeIterator bi)
2118   in {
2119     assert(ai.id().contains(bi.id()));
2120   } do {
2121     if (ai.numEdges() == 0) {
2122       if (ai.containsCenter() == _aCrossingTarget) {
2123         // All points within ai->id() satisfy the crossing target for A, so it's
2124         // worth iterating through the cells of B to see whether any cell
2125         // centers also satisfy the crossing target for B.
2126         do {
2127           if (bi.containsCenter() == _bCrossingTarget) return true;
2128           bi.next();
2129         } while (bi.id() <= ai.rangeMax());
2130       } else {
2131         // The crossing target for A is not satisfied, so we skip over the cells
2132         // of B using binary search.
2133         bi.seekBeyond(ai);
2134       }
2135     } else {
2136       // The current cell of A has at least one edge, so check for crossings.
2137       if (hasCrossing(ai, bi)) return true;
2138     }
2139     ai.next();
2140     return false;
2141   }
2142 
2143   /**
2144      Given two index cells, return true if there are any edge crossings or
2145      wedge crossings within those cells.
2146   */
2147   bool cellCrossesCell(in S2ClippedShape a_clipped, in S2ClippedShape b_clipped) {
2148     // Test all edges of "a_clipped" against all edges of "b_clipped".
2149     int a_num_edges = a_clipped.numEdges();
2150     for (int i = 0; i < a_num_edges; ++i) {
2151       startEdge(a_clipped.edge(i));
2152       if (edgeCrossesCell(b_clipped)) return true;
2153     }
2154     return false;
2155   }
2156 
2157 private:
2158   /**
2159      Given two iterators positioned such that ai->id().Contains(bi->id()),
2160      return true if there is an edge crossing or wedge crosssing anywhere
2161      within ai->id().  Advances "bi" (only) past ai->id().
2162   */
2163   bool hasCrossing(RangeIterator ai, RangeIterator bi)
2164   in {
2165     assert(ai.id().contains(bi.id()));
2166   } do {
2167     // If ai->id() intersects many edges of B, then it is faster to use
2168     // S2CrossingEdgeQuery to narrow down the candidates.  But if it intersects
2169     // only a few edges, it is faster to check all the crossings directly.
2170     // We handle this by advancing "bi" and keeping track of how many edges we
2171     // would need to test.
2172 
2173     enum int kEdgeQueryMinEdges = 20;  // Tuned using benchmarks.
2174     int total_edges = 0;
2175     _bCells.length = 0;
2176     do {
2177       if (bi.numEdges() > 0) {
2178         total_edges += bi.numEdges();
2179         if (total_edges >= kEdgeQueryMinEdges) {
2180           // There are too many edges to test them directly, so use
2181           // S2CrossingEdgeQuery.
2182           if (cellCrossesAnySubcell(ai.clipped(), ai.id())) return true;
2183           bi.seekBeyond(ai);
2184           return false;
2185         }
2186         _bCells ~= bi.cell();
2187       }
2188       bi.next();
2189     } while (bi.id() <= ai.rangeMax());
2190 
2191     // Test all the edge crossings directly.
2192     for (int c = 0; c < _bCells.length; ++c) {
2193       if (cellCrossesCell(ai.clipped(), _bCells[c].clipped(0))) {
2194         return true;
2195       }
2196     }
2197     return false;
2198   }
2199 
2200   /**
2201      Given an index cell of A, return true if there are any edge or wedge
2202      crossings with any index cell of B contained within "b_id".
2203   */
2204   bool cellCrossesAnySubcell(in S2ClippedShape a_clipped, S2CellId b_id) {
2205     // Test all edges of "a_clipped" against all edges of B.  The relevant B
2206     // edges are guaranteed to be children of "b_id", which lets us find the
2207     // correct index cells more efficiently.
2208     auto b_root = new S2PaddedCell(b_id, 0);
2209     int a_num_edges = a_clipped.numEdges();
2210     for (int i = 0; i < a_num_edges; ++i) {
2211       int aj = a_clipped.edge(i);
2212       // Use an S2CrossingEdgeQuery starting at "b_root" to find the index cells
2213       // of B that might contain crossing edges.
2214       _bQuery.getCells(_a.vertex(aj), _a.vertex(aj+1), b_root, _bCells);
2215       if (_bCells.empty()) continue;
2216       startEdge(aj);
2217       for (int c = 0; c < _bCells.length; ++c) {
2218         if (edgeCrossesCell(_bCells[c].clipped(0))) return true;
2219       }
2220     }
2221     return false;
2222   }
2223 
2224   /// Prepare to check the given edge of loop A for crossings.
2225   void startEdge(int aj) {
2226     // Start testing the given edge of A for crossings.
2227     _crosser.initialize(_a.vertex(aj), _a.vertex(aj+1));
2228     _aj = aj;
2229     _bjPrev = -2;
2230   }
2231 
2232   /**
2233      Check the current edge of loop A for crossings with all edges of the
2234      given index cell of loop B.
2235   */
2236   bool edgeCrossesCell(in S2ClippedShape b_clipped) {
2237     // Test the current edge of A against all edges of "b_clipped".
2238     int b_num_edges = b_clipped.numEdges();
2239     for (int j = 0; j < b_num_edges; ++j) {
2240       int bj = b_clipped.edge(j);
2241       if (bj != _bjPrev + 1) _crosser.restartAt(_b.vertex(bj));
2242       _bjPrev = bj;
2243       int crossing = _crosser.crossingSign(_b.vertex(bj + 1));
2244       if (crossing < 0) continue;
2245       if (crossing > 0) return true;
2246       // We only need to check each shared vertex once, so we only
2247       // consider the case where a_vertex(aj_+1) == b_.vertex(bj+1).
2248       if (_a.vertex(_aj+1) == _b.vertex(bj+1)) {
2249         if (_swapped
2250             ? _relation.wedgesCross(
2251                 _b.vertex(bj), _b.vertex(bj+1), _b.vertex(bj+2),
2252                 _a.vertex(_aj), _a.vertex(_aj+2))
2253             : _relation.wedgesCross(
2254                 _a.vertex(_aj), _a.vertex(_aj+1), _a.vertex(_aj+2),
2255                 _b.vertex(bj), _b.vertex(bj+2))) {
2256           return true;
2257         }
2258       }
2259     }
2260     return false;
2261   }
2262 
2263   const(S2Loop) _a;
2264   const(S2Loop) _b;
2265   LoopRelation _relation;
2266   const(bool) _swapped;
2267   int _aCrossingTarget, _bCrossingTarget;
2268 
2269   // State maintained by StartEdge() and EdgeCrossesCell().
2270   S2CopyingEdgeCrosser _crosser;
2271   int _aj, _bjPrev;
2272 
2273   // Temporary data declared here to avoid repeated memory allocations.
2274   S2CrossingEdgeQuery _bQuery;
2275   const(S2ShapeIndexCell)[] _bCells;
2276 }
2277 
2278 private bool matchBoundaries(in S2Loop a, in S2Loop b, int a_offset, S1Angle max_error) {
2279   // The state consists of a pair (i,j).  A state transition consists of
2280   // incrementing either "i" or "j".  "i" can be incremented only if
2281   // a(i+1+a_offset) is near the edge from b(j) to b(j+1), and a similar rule
2282   // applies to "j".  The function returns true iff we can proceed all the way
2283   // around both loops in this way.
2284   //
2285   // Note that when "i" and "j" can both be incremented, sometimes only one
2286   // choice leads to a solution.  We handle this using a stack and
2287   // backtracking.  We also keep track of which states have already been
2288   // explored to avoid duplicating work.
2289 
2290   struct Boundary {
2291     int first;
2292     int second;
2293   }
2294   Boundary[] pending;
2295   bool[Boundary] done;
2296   pending ~= Boundary(0, 0);
2297   while (!pending.empty()) {
2298     int i = pending.back().first;
2299     int j = pending.back().second;
2300     pending.popBack();
2301     if (i == a.numVertices() && j == b.numVertices()) {
2302       return true;
2303     }
2304     done[Boundary(i, j)] = true;
2305 
2306     // If (i == na && offset == na-1) where na == a->num_vertices(), then
2307     // then (i+1+offset) overflows the [0, 2*na-1] range allowed by vertex().
2308     // So we reduce the range if necessary.
2309     int io = i + a_offset;
2310     if (io >= a.numVertices()) {
2311       io -= a.numVertices();
2312     }
2313 
2314     if (i < a.numVertices() && Boundary(i + 1, j) !in done
2315         && getDistance(a.vertex(io + 1), b.vertex(j), b.vertex(j + 1)) <= max_error) {
2316       pending ~= Boundary(i + 1, j);
2317     }
2318     if (j < b.numVertices() && Boundary(i, j + 1) !in done
2319         && getDistance(b.vertex(j + 1), a.vertex(io), a.vertex(io + 1)) <= max_error) {
2320       pending ~= Boundary(i, j + 1);
2321     }
2322   }
2323   return false;
2324 }
2325 
2326 private enum ubyte CURRENT_LOSSLESS_ENCODING_VERSION_NUMBER = 1;
2327 private enum uint DECODE_MAX_NUM_VERTICES = 50000000;