1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 // Original Author: ericv@google.com (Eric Veach)
17 // Converted to D:  madric@gmail.com (Vijay Nayar)
18 
19 module s2.builder.graph;
20 
21 import s2.s2builder;
22 import s2.s2error;
23 import s2.s2point;
24 import s2.id_set_lexicon;
25 
26 import std.algorithm;
27 import std.exception;
28 import std.range;
29 import std.typecons;
30 
31 /**
32  * An S2Builder::Graph represents a collection of snapped edges that is passed
33  * to a Layer for assembly.  (Example layers include polygons, polylines, and
34  * polygon meshes.)  The Graph object does not own any of its underlying data;
35  * it is simply a view of data that is stored elsewhere.  You will only
36  * need this interface if you want to implement a new Layer subtype.
37  *
38  * The graph consists of vertices and directed edges.  Vertices are numbered
39  * sequentially starting from zero.  An edge is represented as a pair of
40  * vertex ids.  The edges are sorted in lexicographic order, therefore all of
41  * the outgoing edges from a particular vertex form a contiguous range.
42  *
43  * S2Builder::Graph is movable and copyable.  Note that although this class
44  * does not own the underlying vertex and edge data, S2Builder guarantees that
45  * all Graph objects passed to S2Builder::Layer::Build() methods will remain
46  * valid until all layers have been built.
47  *
48  * TODO(ericv): Consider pulling out the methods that are helper functions for
49  * Layer implementations (such as GetDirectedLoops) into s2builderutil_graph.h.
50  */
51 class Graph {
52 public:
53   // Identifies a vertex in the graph.  Vertices are numbered sequentially
54   // starting from zero.
55   alias VertexId = int;
56 
57   // Defines an edge as an (origin, destination) vertex pair.
58   alias Edge = Tuple!(VertexId, VertexId);
59 
60   // Identifies an edge in the graph.  Edges are numbered sequentially
61   // starting from zero.
62   alias EdgeId = int;
63 
64   alias EdgeType = S2Builder.EdgeType;
65 
66   // Identifies an S2Builder *input* edge (before snapping).
67   alias InputEdgeId = S2Builder.InputEdgeId;
68 
69   // Identifies a set of S2Builder input edges.
70   alias InputEdgeIdSetId = S2Builder.InputEdgeIdSetId;
71 
72   // Identifies a set of edge labels.
73   alias LabelSetId = S2Builder.LabelSetId;
74 
75   // Determines whether a degenerate polygon is empty or full.
76   alias IsFullPolygonPredicate = S2Builder.IsFullPolygonPredicate;
77 
78   alias SiblingPairs = GraphOptions.SiblingPairs;
79   alias DegenerateEdges = GraphOptions.DegenerateEdges;
80   alias DuplicateEdges = GraphOptions.DuplicateEdges;
81 
82   /// The default constructor exists only for the benefit of STL containers.
83   /// The graph must be initialized (using the assignment operator) before it
84   /// is used.
85   this() {
86     _options = new GraphOptions();
87     _numVertices = -1;
88     _vertices = null;
89     _edges = null;
90     _inputEdgeIdSetIds = null;
91     _inputEdgeIdSetLexicon = null;
92     _labelSetIds = null;
93     _labelSetLexicon = null;
94   }
95 
96   /**
97    * Note that most of the parameters are passed by const reference and must
98    * exist for the duration of the Graph object.  Notes on parameters:
99    * "options":
100    *    - the GraphOptions used to build the Graph.  In some cases these
101    *      can be different than the options provided by the Layer.
102    * "vertices":
103    *   - a vector of S2Points indexed by VertexId.
104    * "edges":
105    *   - a vector of VertexId pairs (sorted in lexicographic order)
106    *     indexed by EdgeId.
107    * "input_edge_id_set_ids":
108    *   - a vector indexed by EdgeId that allows access to the set of
109    *     InputEdgeIds that were mapped to the given edge, by looking up the
110    *     returned value (an InputEdgeIdSetId) in "input_edge_id_set_lexicon".
111    * "input_edge_id_set_lexicon":
112    *   - a class that maps an InputEdgeIdSetId to a set of InputEdgeIds.
113    * "label_set_ids":
114    *   - a vector indexed by InputEdgeId that allows access to the set of
115    *     labels that were attached to the given input edge, by looking up the
116    *     returned value (a LabelSetId) in the "label_set_lexicon".
117    * "label_set_lexicon":
118    *   - a class that maps a LabelSetId to a set of S2Builder::Labels.
119    * "is_full_polygon_predicate":
120    *   - a predicate called to determine whether a graph consisting only of
121    *     polygon degeneracies represents the empty polygon or the full polygon
122    *     (see s2builder.h for details).
123    */
124   this(
125       in GraphOptions options,
126       in S2Point[] vertices,
127       in Edge[] edges,
128       in InputEdgeIdSetId[] input_edge_id_set_ids,
129       in IdSetLexicon input_edge_id_set_lexicon,
130       in LabelSetId[] label_set_ids,
131       in IdSetLexicon label_set_lexicon,
132       // TODO(ericv/hagzonal): Fix st_lib and remove default parameter.
133       IsFullPolygonPredicate is_full_polygon_predicate = IsFullPolygonPredicate()) {
134     _options = options;
135     _numVertices = cast(int) vertices.length;
136     _vertices = vertices;
137     _edges = edges;
138     _inputEdgeIdSetIds = input_edge_id_set_ids;
139     _inputEdgeIdSetLexicon = input_edge_id_set_lexicon;
140     _labelSetIds = label_set_ids;
141     _labelSetLexicon = label_set_lexicon;
142     _isFullPolygonPredicate = is_full_polygon_predicate;
143     debug enforce(isSorted(edges));
144   }
145 
146   const(GraphOptions) options() const {
147     return _options;
148   }
149 
150   /// Returns the number of vertices in the graph.
151   VertexId numVertices() const {
152     return _numVertices;  // vertices_.size() requires division by 24.
153   }
154 
155   /// Returns the vertex at the given index.
156   const(S2Point) vertex(VertexId v) const {
157     return vertices()[v];
158   }
159 
160   /// Returns the entire set of vertices.
161   const(S2Point[]) vertices() const {
162     return _vertices;
163   }
164 
165   /// Returns the total number of edges in the graph.
166   EdgeId numEdges() const {
167     return cast(EdgeId)(edges().length);
168   }
169 
170   /// Returns the endpoints of the given edge (as vertex indices).
171   Edge edge(EdgeId e) const {
172     return edges()[e];
173   }
174 
175   /// Returns the entire set of edges.
176   const(Edge[]) edges() const {
177     return _edges;
178   }
179 
180   /// Given an edge (src, dst), returns the reverse edge (dst, src).
181   static Edge reverse(in Edge e) {
182     return Edge(e[1], e[0]);
183   }
184 
185   /**
186    * Returns a vector of edge ids sorted in lexicographic order by
187    * (destination, origin).  All of the incoming edges to each vertex form a
188    * contiguous subrange of this ordering.
189    */
190   EdgeId[] getInEdgeIds() const {
191     EdgeId[] in_edge_ids = new EdgeId[](numEdges());
192     for (EdgeId i = 0; i < numEdges(); i++) in_edge_ids[i] = i;
193     sort!((ai, bi) {
194           return stableLessThan(reverse(edge(ai)), reverse(edge(bi)), ai, bi);
195         })(in_edge_ids);
196     return in_edge_ids;
197   }
198 
199   /**
200    * Given a graph such that every directed edge has a sibling, returns a map
201    * from EdgeId to the sibling EdgeId.  This method is identical to
202    * GetInEdgeIds() except that (1) it requires edges to have siblings, and
203    * (2) undirected degenerate edges are grouped together in pairs such that
204    * one edge is the sibling of the other.  Handles duplicate edges correctly
205    * and is also consistent with GetLeftTurnMap().
206    *
207    * REQUIRES: An option is chosen that guarantees sibling pairs:
208    *     (options.sibling_pairs() == { REQUIRE, CREATE } ||
209    *      options.edge_type() == UNDIRECTED)
210    */
211   EdgeId[] getSiblingMap() const {
212     EdgeId[] in_edge_ids = getInEdgeIds();
213     makeSiblingMap(in_edge_ids);
214     return in_edge_ids;
215   }
216 
217   /**
218    * Like GetSiblingMap(), but constructs the map starting from the vector of
219    * incoming edge ids returned by GetInEdgeIds().  (This operation is a no-op
220    * except unless undirected degenerate edges are present, in which case such
221    * edges are grouped together in pairs to satisfy the requirement that every
222    * edge must have a sibling edge.)
223    */
224   void makeSiblingMap(ref EdgeId[] in_edge_ids) const {
225     debug enforce(
226         _options.siblingPairs() == SiblingPairs.REQUIRE
227         || _options.siblingPairs() == SiblingPairs.CREATE
228         || _options.edgeType() == EdgeType.UNDIRECTED);
229     for (EdgeId e = 0; e < numEdges(); ++e) {
230       debug enforce(edge(e) == reverse(edge(in_edge_ids[e])));
231     }
232     if (_options.edgeType() == EdgeType.DIRECTED) return;
233     if (_options.degenerateEdges() == DegenerateEdges.DISCARD) return;
234 
235     for (EdgeId e = 0; e < numEdges(); ++e) {
236       VertexId v = edge(e)[0];
237       if (edge(e)[1] == v) {
238         debug enforce(e + 1 < numEdges());
239         debug enforce(edge(e + 1)[0] == v);
240         debug enforce(edge(e + 1)[1] == v);
241         debug enforce(in_edge_ids[e] == e);
242         debug enforce(in_edge_ids[e + 1] == e + 1);
243         in_edge_ids[e] = e + 1;
244         in_edge_ids[e + 1] = e;
245         ++e;
246       }
247     }
248   }
249 
250   /// A helper class for VertexOutMap that represents the outgoing edges
251   /// from a given vertex.
252   // class VertexOutEdges {
253   // public:
254   //   const Edge* begin() const { return begin_; }
255   //   const Edge* end() const { return end_; }
256   //   size_t size() const { return end_ - begin_; }
257   // private:
258   //   friend class VertexOutMap;
259   //   VertexOutEdges(const Edge* begin, const Edge* end);
260   //   const Edge* begin_;
261   //   const Edge* end_;
262   // };
263 
264   /// A helper class for VertexOutMap that represents the outgoing edge *ids*
265   /// from a given vertex.
266   // class VertexOutEdgeIds {
267   // public:
268   //   // An iterator over a range of edge ids (like boost::counting_iterator).
269   //   class Iterator {
270   //   public:
271   //     explicit Iterator(EdgeId id) : id_(id) {}
272   //     const EdgeId& operator*() const { return id_; }
273   //     Iterator& operator++() { ++id_; return *this; }
274   //     Iterator operator++(int) { return Iterator(id_++); }
275   //     size_t operator-(const Iterator& x) const { return id_ - x.id_; }
276   //     bool operator==(const Iterator& x) const { return id_ == x.id_; }
277   //     bool operator!=(const Iterator& x) const { return id_ != x.id_; }
278   //   private:
279   //     EdgeId id_;
280   //   };
281   //   Iterator begin() const { return Iterator(begin_); }
282   //   Iterator end() const { return Iterator(end_); }
283   //   size_t size() const { return end_ - begin_; }
284   // private:
285   //   friend class VertexOutMap;
286   //   VertexOutEdgeIds(EdgeId begin, EdgeId end);
287   //   EdgeId begin_, end_;
288   // };
289 
290   /**
291    * A class that maps vertices to their outgoing edge ids.  Example usage:
292    *   VertexOutMap out(g);
293    *   for (Graph::EdgeId e : out.edge_ids(v)) { ... }
294    *   for (const Graph::Edge& edge : out.edges(v)) { ... }
295    */
296   static class VertexOutMap {
297   public:
298     this(const(Graph) g) {
299       _edges = g.edges();
300       _edgeBegins = new EdgeId[](g.numVertices() + 1);
301       EdgeId e = 0;
302       for (VertexId v = 0; v <= g.numVertices(); ++v) {
303         while (e < g.numEdges() && g.edge(e)[0] < v) ++e;
304         _edgeBegins[v] = e;
305       }
306     }
307 
308     int degree(VertexId v) const {
309       return cast(int) edgeIds(v).length;
310     }
311 
312     const(Edge[]) edges(VertexId v) const {
313       return _edges[_edgeBegins[v] .. _edgeBegins[v + 1]];
314     }
315 
316     // Returns a range of EdgeId from the given VertexId to the next.
317     auto edgeIds(VertexId v) const {
318       return iota(_edgeBegins[v], _edgeBegins[v + 1]);
319     }
320 
321     /// Returns a range of Edge (or edge ids) between a specific pair of vertices.
322     auto edges(VertexId v0, VertexId v1) const {
323       return assumeSorted(_edges[_edgeBegins[v0] .. _edgeBegins[v0 + 1]])
324           .equalRange(Edge(v0, v1));
325     }
326 
327     EdgeId[] edgeIds(VertexId v0, VertexId v1) const {
328       auto trisectRanges = assumeSorted(_edges[_edgeBegins[v0] .. _edgeBegins[v0 + 1]])
329           .trisect(Edge(v0, v1));
330 
331       // Start past the ids that are less than those that match Edge(v0, v1).
332       EdgeId startId = _edgeBegins[v0] + cast(int) trisectRanges[0].length;
333       return iota(startId, startId + cast(int) trisectRanges[1].length).array;
334     }
335 
336   private:
337     const(Edge[]) _edges;
338     EdgeId[] _edgeBegins;
339   }
340 
341   // A helper class for VertexInMap that represents the incoming edge *ids*
342   // to a given vertex.
343   // class VertexInEdgeIds {
344   //  public:
345   //   const EdgeId* begin() const { return begin_; }
346   //   const EdgeId* end() const { return end_; }
347   //   size_t size() const { return end_ - begin_; }
348 
349   //  private:
350   //   friend class VertexInMap;
351   //   VertexInEdgeIds(const EdgeId* begin, const EdgeId* end);
352   //   const EdgeId* begin_;
353   //   const EdgeId* end_;
354   // }
355 
356   // A class that maps vertices to their incoming edge ids.  Example usage:
357   //   VertexInMap in(g);
358   //   for (Graph::EdgeId e : in.edge_ids(v)) { ... }
359   static class VertexInMap {
360   public:
361     this(in Graph g) {
362       _inEdgeIds = g.getInEdgeIds();
363       _inEdgeBegins = new EdgeId[](g.numVertices() + 1);
364       EdgeId e = 0;
365       for (VertexId v = 0; v <= g.numVertices(); ++v) {
366         while (e < g.numEdges() && g.edge(_inEdgeIds[e])[1] < v) ++e;
367         _inEdgeBegins[v] = e;
368       }
369     }
370 
371     int degree(VertexId v) const {
372       return cast(int)(edgeIds(v).length);
373     }
374 
375     const(EdgeId[]) edgeIds(VertexId v) const {
376       return _inEdgeIds[_inEdgeBegins[v] .. _inEdgeBegins[v + 1]];
377     }
378 
379     // Returns a sorted vector of all incoming edges (see GetInEdgeIds).
380     const(EdgeId[]) inEdgeIds() const {
381       return _inEdgeIds;
382     }
383 
384   private:
385     EdgeId[] _inEdgeIds;
386     EdgeId[] _inEdgeBegins;
387   }
388 
389   /// Defines a value larger than any valid InputEdgeId.
390   static immutable InputEdgeId MAX_INPUT_EDGE_ID = InputEdgeId.max;
391 
392   /// The following value of InputEdgeId means that an edge does not
393   /// corresponds to any input edge.
394   static immutable InputEdgeId NO_INPUT_EDGE_ID = MAX_INPUT_EDGE_ID - 1;
395 
396   /**
397    * Returns the set of input edge ids that were snapped to the given
398    * edge.  ("Input edge ids" are assigned to input edges sequentially in
399    * the order they are added to the builder.)  For example, if input
400    * edges 2 and 17 were snapped to edge 12, then input_edge_ids(12)
401    * returns a set containing the numbers 2 and 17.  Example usage:
402    *
403    *   for (InputEdgeId input_edge_id : g.input_edge_ids(e)) { ... }
404    *
405    * Please note the following:
406    *
407    *  - When edge chains are simplified, the simplified edge is assigned all
408    *    the input edge ids associated with edges of the chain.
409    *
410    *  - Edges can also have multiple input edge ids due to edge merging
411    *    (if DuplicateEdges::MERGE is specified).
412    *
413    *  - Siblings edges automatically created by EdgeType::UNDIRECTED or
414    *    SiblingPairs::CREATE have an empty set of input edge ids.  (However
415    *    you can use a LabelFetcher to retrieve the set of labels associated
416    *    with both edges of a given sibling pair.)
417    */
418   const(IdSetLexicon.IdSet) inputEdgeIds(EdgeId e) const {
419     return inputEdgeIdSetLexicon().idSet(inputEdgeIdSetIds()[e]);
420   }
421 
422   /**
423    * Low-level method that returns an integer representing the entire set of
424    * input edge ids that were snapped to the given edge.  The elements of the
425    * IdSet can be accessed using input_edge_id_set_lexicon().
426    */
427   InputEdgeIdSetId inputEdgeIdSetId(EdgeId e) const {
428     return inputEdgeIdSetIds()[e];
429   }
430 
431   /// Low-level method that returns a vector where each element represents the
432   /// set of input edge ids that were snapped to a particular output edge.
433   const(InputEdgeIdSetId[]) inputEdgeIdSetIds() const {
434     return _inputEdgeIdSetIds;
435   }
436 
437   /// Returns a mapping from an InputEdgeIdSetId to a set of input edge ids.
438   const(IdSetLexicon) inputEdgeIdSetLexicon() const {
439     return _inputEdgeIdSetLexicon;
440   }
441 
442   /**
443    * Returns the minimum input edge id that was snapped to this edge, or -1 if
444    * no input edges were snapped (see SiblingPairs::CREATE).  This is
445    * useful for layers that wish to preserve the input edge ordering as much
446    * as possible (e.g., to ensure idempotency).
447    */
448   InputEdgeId minInputEdgeId(EdgeId e) const {
449     const(IdSetLexicon.IdSet) id_set = inputEdgeIds(e);
450     return (id_set.length == 0) ? NO_INPUT_EDGE_ID : id_set[0];
451   }
452 
453   /// Returns a vector containing the minimum input edge id for every edge.
454   /// If an edge has no input ids, kNoInputEdgeId is used.
455   InputEdgeId[] getMinInputEdgeIds() const {
456     auto min_input_ids = new InputEdgeId[numEdges()];
457     for (EdgeId e = 0; e < numEdges(); ++e) {
458       min_input_ids[e] = minInputEdgeId(e);
459     }
460     return min_input_ids;
461   }
462 
463   /// Returns a vector of EdgeIds sorted by minimum input edge id.  This is an
464   /// approximation of the input edge ordering.
465   EdgeId[] getInputEdgeOrder(in InputEdgeId[] input_ids) const {
466     auto order = new EdgeId[input_ids.length];
467     for (EdgeId i = 0; i < order.length; i++) order[i] = i;
468     // Comparison function ensures sort is stable.
469     sort!((EdgeId a, EdgeId b) => Edge(input_ids[a], a) < Edge(input_ids[b], b))(order);
470     return order;
471   }
472 
473   /**
474    * Convenience class to return the set of labels associated with a given
475    * graph edge.  Note that due to snapping, one graph edge may correspond to
476    * several different input edges and will have all of their labels.
477    * This class is the preferred way to retrieve edge labels.
478    *
479    * The reason this is a class rather than a graph method is because for
480    * undirected edges, we need to fetch the labels associated with both
481    * siblings.  This is because only the original edge of the sibling pair has
482    * labels; the automatically generated sibling edge does not.
483    */
484   static class LabelFetcher {
485   public:
486     /**
487      * Prepares to fetch labels associated with the given edge type.  For
488      * EdgeType::UNDIRECTED, labels associated with both edges of the sibling
489      * pair will be returned.  "edge_type" is a parameter (rather than using
490      * g.options().edge_type()) so that clients can explicitly control whether
491      * labels from one or both siblings are returned.
492      */
493     this(in Graph g, EdgeType edge_type) {
494       _g = g;
495       _edgeType = edge_type;
496       if (edge_type == EdgeType.UNDIRECTED) _siblingMap = g.getSiblingMap();
497     }
498 
499     /**
500      * Returns the set of labels associated with edge "e" (and also the labels
501      * associated with the sibling of "e" if edge_type() is UNDIRECTED).
502      * Labels are sorted and duplicate labels are automatically removed.
503      *
504      * This method uses an output parameter rather than returning by value in
505      * order to avoid allocating a new vector on every call to this method.
506      */
507     void fetch(EdgeId e, ref S2Builder.Label[] labels) {
508       labels.length = 0;
509       foreach (InputEdgeId input_edge_id; _g.inputEdgeIds(e)) {
510         foreach (S2Builder.Label label; _g.labels(input_edge_id)) {
511           labels ~= label;
512         }
513       }
514       if (_edgeType == EdgeType.UNDIRECTED) {
515         foreach (InputEdgeId input_edge_id; _g.inputEdgeIds(_siblingMap[e])) {
516           foreach (S2Builder.Label label; _g.labels(input_edge_id)) {
517             labels ~= label;
518           }
519         }
520       }
521       if (labels.length > 1) {
522         labels = sort(labels).uniq.array;
523       }
524     }
525 
526   private:
527     const(Graph) _g;
528     EdgeType _edgeType;
529     EdgeId[] _siblingMap;
530   }
531 
532   /// Returns the set of labels associated with a given input edge.  Example:
533   ///   for (Label label : g.labels(input_edge_id)) { ... }
534   const(IdSetLexicon.IdSet) labels(InputEdgeId id) const {
535     return labelSetLexicon().idSet(labelSetIds()[id]);
536   }
537 
538   /**
539    * Low-level method that returns an integer representing the set of
540    * labels associated with a given input edge.  The elements of
541    * the IdSet can be accessed using label_set_lexicon().
542    */
543   LabelSetId labelSetId(InputEdgeId e) const {
544     return _labelSetIds[e];
545   }
546 
547   /// Low-level method that returns a vector where each element represents the
548   /// set of labels associated with a particular output edge.
549   const(LabelSetId[]) labelSetIds() const {
550     return _labelSetIds;
551   }
552 
553   /// Returns a mapping from a LabelSetId to a set of labels.
554   const(IdSetLexicon) labelSetLexicon() const {
555     return _labelSetLexicon;
556   }
557 
558   /**
559    * Convenience method that calls is_full_polygon_predicate() to determine
560    * whether a graph that consists only of polygon degeneracies represents the
561    * empty polygon or the full polygon (see s2builder.h for details).
562    */
563   bool isFullPolygon(ref S2Error error) const {
564     return _isFullPolygonPredicate(this, error);
565   }
566 
567   /**
568    * Returns a method that determines whether a graph that consists only of
569    * polygon degeneracies represents the empty polygon or the full polygon
570    * (see s2builder.h for details).
571    */
572   const(IsFullPolygonPredicate) isFullPolygonPredicate() const {
573     return _isFullPolygonPredicate;
574   }
575 
576   /**
577    * Returns a map "m" that maps each edge e=(v0,v1) to the following outgoing
578    * edge around "v1" in clockwise order.  \(This corresponds to making a "left
579    * turn" at the vertex.\)  By starting at a given edge and making only left
580    * turns, you can construct a loop whose interior does not contain any edges
581    * in the same connected component.
582    *
583    * If the incoming and outgoing edges around a vertex do not alternate
584    * perfectly \(e.g., there are two incoming edges in a row\), then adjacent
585    * \(incoming, outgoing\) pairs are repeatedly matched and removed.  This is
586    * similar to finding matching parentheses in a string such as "\(\(\)\(\)\)\(\)".
587    *
588    * For sibling edge pairs, the incoming edge is assumed to immediately
589    * follow the outgoing edge in clockwise order.  Thus a left turn is made
590    * from an edge to its sibling only if there are no other outgoing edges.
591    * With respect to the parentheses analogy, a sibling pair is "\(\)".
592    * Similarly, if there are multiple copies of a sibling edge pair then the
593    * duplicate incoming and outgoing edges are sorted in alternating order
594    * \(e.g., "\)\(\)\("\).
595    *
596    * Degenerate edges \(edges from a vertex to itself\) are treated as loops
597    * consisting of a single edge.  This avoids the problem of deciding the
598    * connectivity and ordering of such edges when they share a vertex with
599    * other edges \(possibly including other degenerate edges\).
600    *
601    * If it is not possible to make a left turn from every input edge, this
602    * method returns false and sets "error" appropriately.  In this situation
603    * the left turn map is still valid except that any incoming edge where it
604    * is not possible to make a left turn will have its entry set to -1.
605    *
606    * "in_edge_ids" should be equal to GetInEdgeIds() or GetSiblingMap().
607    */
608   bool getLeftTurnMap(
609       in EdgeId[] in_edge_ids, ref EdgeId[] left_turn_map, ref S2Error error) const {
610     left_turn_map.length = numEdges();
611     left_turn_map[] = -1;
612     if (numEdges() == 0) return true;
613 
614     // Declare vectors outside the loop to avoid reallocating them each time.
615     VertexEdge[] v0_edges;
616     EdgeId[] e_in;
617     EdgeId[] e_out;
618 
619     // Walk through the two sorted arrays of edges (outgoing and incoming) and
620     // gather all the edges incident to each vertex.  Then we sort those edges
621     // and add an entry to the left turn map from each incoming edge to the
622     // immediately following outgoing edge in clockwise order.
623     int outId = 0;
624     int inId = 0;
625     Edge out_edge = edge(outId);
626     Edge in_edge = edge(in_edge_ids[inId]);
627     auto sentinel = Edge(numVertices(), numVertices());
628     Edge min_edge = min(out_edge, reverse(in_edge));
629     while (min_edge != sentinel) {
630       // Gather all incoming and outgoing edges around vertex "v0".
631       VertexId v0 = min_edge[0];
632       for (; min_edge[0] == v0; min_edge = min(out_edge, reverse(in_edge))) {
633         VertexId v1 = min_edge[1];
634         // Count the number of copies of "min_edge" in each direction.
635         int out_begin = outId;
636         int in_begin = inId;
637         while (out_edge == min_edge) {
638           out_edge = (++outId == numEdges()) ? sentinel : Edge(edge(outId));
639         }
640         while (reverse(in_edge) == min_edge) {
641           in_edge = (++inId == numEdges()) ? sentinel : Edge(edge(in_edge_ids[inId]));
642         }
643         if (v0 != v1) {
644           addVertexEdges(out_begin, outId, in_begin, inId, v1, v0_edges);
645         } else {
646           // Each degenerate edge becomes its own loop.
647           for (; in_begin < inId; ++in_begin) {
648             left_turn_map[in_begin] = in_begin;
649           }
650         }
651       }
652       if (v0_edges.empty()) continue;
653 
654       // Sort the edges in clockwise order around "v0".
655       VertexId min_endpoint = v0_edges.front().endpoint;
656       sort!((in VertexEdge a, in VertexEdge b) {
657             import s2.s2predicates : orderedCCW;
658             if (a.endpoint == b.endpoint) return a.rank < b.rank;
659             if (a.endpoint == min_endpoint) return true;
660             if (b.endpoint == min_endpoint) return false;
661             return !orderedCCW(
662                 vertex(a.endpoint), vertex(b.endpoint), vertex(min_endpoint), vertex(v0));
663           })(v0_edges);
664       // Match incoming with outgoing edges.  We do this by keeping a stack of
665       // unmatched incoming edges.  We also keep a stack of outgoing edges with
666       // no previous incoming edge, and match these at the end by wrapping
667       // around circularly to the start of the edge ordering.
668       foreach (const VertexEdge e; v0_edges) {
669         if (e.incoming) {
670           e_in ~= in_edge_ids[e.index];
671         } else if (!e_in.empty()) {
672           left_turn_map[e_in.back()] = e.index;
673           e_in.popBack();
674         } else {
675           e_out ~= e.index;  // Matched below.
676         }
677       }
678       // Pair up additional edges using the fact that the ordering is circular.
679       .reverse(e_out);
680       for (; !e_out.empty() && !e_in.empty(); e_out.popBack(), e_in.popBack()) {
681         left_turn_map[e_in.back()] = e_out.back();
682       }
683       // We only need to process unmatched incoming edges, since we are only
684       // responsible for creating left turn map entries for those edges.
685       if (!e_in.empty() && error.ok()) {
686         error.initialize(S2Error.Code.BUILDER_EDGES_DO_NOT_FORM_LOOPS,
687             "Given edges do not form loops (indegree != outdegree)");
688       }
689       e_in.length = 0;
690       e_out.length = 0;
691       v0_edges.length = 0;
692     }
693     return error.ok();
694   }
695 
696   /**
697    * Rotates the edges of "loop" if necessary so that the edge(s) with the
698    * largest input edge ids are last.  This ensures that when an output loop
699    * is equivalent to an input loop, their cyclic edge orders are the same.
700    * "min_input_ids" is the output of GetMinInputEdgeIds().
701    */
702   static void canonicalizeLoopOrder(in InputEdgeId[] min_input_ids, ref EdgeId[] loop) {
703     if (loop.empty()) return;
704     // Find the position of the element with the highest input edge id.  If
705     // there are multiple such elements together (i.e., the edge was split
706     // into several pieces by snapping it to several vertices), then we choose
707     // the last such position in cyclic order (this attempts to preserve the
708     // original loop order even when new vertices are added).  For example, if
709     // the input edge id sequence is (7, 7, 4, 5, 6, 7) then we would rotate
710     // it to obtain (4, 5, 6, 7, 7, 7).
711 
712     // The reason that we put the highest-numbered edge last, rather than the
713     // lowest-numbered edge first, is that S2Loop::Invert() reverses the loop
714     // edge order *except* for the last edge.  For example, the loop ABCD (with
715     // edges AB, BC, CD, DA) becomes DCBA (with edges DC, CB, BA, AD).  Note
716     // that the last edge is the same except for its direction (DA vs. AD).
717     // This has the advantage that if an undirected loop is assembled with the
718     // wrong orientation and later inverted (e.g. by S2Polygon::InitOriented),
719     // we still end up preserving the original cyclic vertex order.
720     int pos = 0;
721     bool saw_gap = false;
722     for (int i = 1; i < loop.length; ++i) {
723       int cmp = min_input_ids[loop[i]] - min_input_ids[loop[pos]];
724       if (cmp < 0) {
725         saw_gap = true;
726       } else if (cmp > 0 || !saw_gap) {
727         pos = i;
728         saw_gap = false;
729       }
730     }
731     if (++pos == loop.length) pos = 0;  // Convert loop end to loop start.
732     bringToFront(loop[0 .. pos], loop[pos .. $]);
733   }
734 
735   /**
736    * Sorts the given edge chains (i.e., loops or polylines) by the minimum
737    * input edge id of each chains's first edge.  This ensures that when the
738    * output consists of multiple loops or polylines, they are sorted in the
739    * same order as they were provided in the input.
740    */
741   static void canonicalizeVectorOrder(in InputEdgeId[] min_input_ids, ref EdgeId[][] chains) {
742     sort!((in EdgeId[] a, in EdgeId[] b) {
743           return min_input_ids[a[0]] < min_input_ids[b[0]];
744         })(chains);
745   }
746 
747   /// A loop consisting of a sequence of edges.
748   alias EdgeLoop = EdgeId[];
749 
750   /**
751    * Indicates whether loops should be simple cycles (no repeated vertices) or
752    * circuits (which allow repeated vertices but not repeated edges).  In
753    * terms of how the loops are built, this corresponds to closing off a loop
754    * at the first repeated vertex vs. the first repeated edge.
755    */
756   enum LoopType { SIMPLE, CIRCUIT }
757 
758   /**
759    * Builds loops from a set of directed edges, turning left at each vertex
760    * until either a repeated vertex (for LoopType::SIMPLE) or a repeated edge
761    * (for LoopType::CIRCUIT) is found.  (Use LoopType::SIMPLE if you intend to
762    * construct an S2Loop.)
763    *
764    * Each loop is represented as a sequence of edges.  The edge ordering and
765    * loop ordering are automatically canonicalized in order to preserve the
766    * input ordering as much as possible.  Loops are non-crossing provided that
767    * the graph contains no crossing edges.  If some edges cannot be turned
768    * into loops, returns false and sets "error" appropriately.
769    *
770    * If any degenerate edges are present, then each such edge is treated as a
771    * separate loop.  This is mainly useful in conjunction with
772    * options.degenerate_edges() == DISCARD_EXCESS, in order to build polygons
773    * that preserve degenerate geometry.
774    *
775    * REQUIRES: options.degenerate_edges() == {DISCARD, DISCARD_EXCESS}
776    * REQUIRES: options.edge_type() == DIRECTED
777    */
778   bool getDirectedLoops(LoopType loop_type, ref EdgeLoop[] loops, ref S2Error error) const
779   in {
780     assert(_options.degenerateEdges() == DegenerateEdges.DISCARD
781         || _options.degenerateEdges() == DegenerateEdges.DISCARD_EXCESS);
782     assert(_options.edgeType() == EdgeType.DIRECTED);
783   } do {
784     EdgeId[] left_turn_map;
785     if (!getLeftTurnMap(getInEdgeIds(), left_turn_map, error)) return false;
786     InputEdgeId[] min_input_ids = getMinInputEdgeIds();
787 
788     // If we are breaking loops at repeated vertices, we maintain a map from
789     // VertexId to its position in "path".
790     int[] path_index;
791     if (loop_type == LoopType.SIMPLE) {
792       path_index.length = numVertices();
793       fill(path_index, -1);
794     }
795 
796     // Visit edges in arbitrary order, and try to build a loop from each edge.
797     EdgeId[] path;
798     for (EdgeId start = 0; start < numEdges(); ++start) {
799       if (left_turn_map[start] < 0) continue;
800 
801       // Build a loop by making left turns at each vertex until we return to
802       // "start".  We use "left_turn_map" to keep track of which edges have
803       // already been visited by setting its entries to -1 as we go along.  If
804       // we are building vertex cycles, then whenever we encounter a vertex that
805       // is already part of the path, we "peel off" a loop by removing those
806       // edges from the path so far.
807       for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
808         path ~= e;
809         next = left_turn_map[e];
810         left_turn_map[e] = -1;
811         if (loop_type == LoopType.SIMPLE) {
812           path_index[edge(e)[0]] = cast(int) path.length - 1;
813           int loop_start = path_index[edge(e)[1]];
814           if (loop_start < 0) continue;
815           // Peel off a loop from the path.
816           EdgeId[] loop = path[loop_start .. $];
817           path.length = loop_start;
818           foreach (EdgeId e2; loop) path_index[edge(e2)[0]] = -1;
819           canonicalizeLoopOrder(min_input_ids, loop);
820           loops ~= loop;
821         }
822       }
823       if (loop_type == LoopType.SIMPLE) {
824         debug enforce(path.empty());  // Invariant.
825       } else {
826         canonicalizeLoopOrder(min_input_ids, path);
827         loops ~= path;
828         path.length = 0;
829       }
830     }
831     canonicalizeVectorOrder(min_input_ids, loops);
832     return true;
833   }
834 
835   /**
836    * Builds loops from a set of directed edges, turning left at each vertex
837    * until a repeated edge is found (i.e., LoopType::CIRCUIT).  The loops are
838    * further grouped into connected components, where each component consists
839    * of one or more loops connected by shared vertices.
840    *
841    * This method is used to build polygon meshes from directed or undirected
842    * input edges.  To convert the output of this method into a mesh, the
843    * client must determine how the loops in different components are related
844    * to each other: for example, several loops from different components may
845    * bound the same region on the sphere, in which case all of those loops are
846    * combined into a single polygon.  (See s2shapeutil::BuildPolygonBoundaries
847    * and s2builderutil::LaxPolygonVectorLayer for details.)
848    *
849    * Note that loops may include both edges of a sibling pair.  When several
850    * such edges are connected in a chain or a spanning tree, they form a
851    * zero-area "filament".  The entire loop may be a filament (i.e., a
852    * degenerate loop with an empty interior), or the loop may have have
853    * non-empty interior with several filaments that extend inside it, or the
854    * loop may consist of several "holes" connected by filaments.  These
855    * filaments do not change the interior of any loop, so if you are only
856    * interested in point containment then they can safely be removed by
857    * setting the "degenerate_boundaries" parameter to DISCARD.  (They can't be
858    * removed by setting (options.sibling_pairs() == DISCARD) because the two
859    * siblings might belong to different polygons of the mesh.)  Note that you
860    * can prevent multiple copies of sibling pairs by specifying
861    * options.duplicate_edges() == MERGE.
862    *
863    * Each loop is represented as a sequence of edges.  The edge ordering and
864    * loop ordering are automatically canonicalized in order to preserve the
865    * input ordering as much as possible.  Loops are non-crossing provided that
866    * the graph contains no crossing edges.  If some edges cannot be turned
867    * into loops, returns false and sets "error" appropriately.
868    *
869    * REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS }
870    *           (but requires DISCARD if degenerate_boundaries == DISCARD)
871    * REQUIRES: options.sibling_pairs() == { REQUIRE, CREATE }
872    *           [i.e., every edge must have a sibling edge]
873    */
874   enum DegenerateBoundaries { DISCARD, KEEP }
875 
876   alias DirectedComponent = EdgeLoop[];
877 
878   bool getDirectedComponents(
879       DegenerateBoundaries degenerate_boundaries,
880       ref DirectedComponent[] components,
881       ref S2Error error) const
882   in {
883     assert(_options.degenerateEdges() == DegenerateEdges.DISCARD
884         || (_options.degenerateEdges() == DegenerateEdges.DISCARD_EXCESS
885             && degenerate_boundaries == DegenerateBoundaries.KEEP));
886     assert(_options.siblingPairs() == SiblingPairs.REQUIRE
887         || _options.siblingPairs() == SiblingPairs.CREATE);
888     assert(_options.edgeType() == EdgeType.DIRECTED);  // Implied by above.
889   } do {
890     EdgeId[] sibling_map = getInEdgeIds();
891     EdgeId[] left_turn_map;
892     if (!getLeftTurnMap(sibling_map, left_turn_map, error)) return false;
893     makeSiblingMap(sibling_map);
894     InputEdgeId[] min_input_ids = getMinInputEdgeIds();
895     EdgeId[] frontier;  // Unexplored sibling edges.
896 
897     // A map from EdgeId to the position of that edge in "path".  Only needed if
898     // degenerate boundaries are being discarded.
899     int[] path_index;
900     if (degenerate_boundaries == DegenerateBoundaries.DISCARD) {
901       path_index.length = numEdges();
902       path_index[] = -1;
903     }
904     for (EdgeId min_start = 0; min_start < numEdges(); ++min_start) {
905       if (left_turn_map[min_start] < 0) continue;  // Already used.
906 
907       // Build a connected component by keeping a stack of unexplored siblings
908       // of the edges used so far.
909       DirectedComponent component;
910       frontier ~= min_start;
911       while (!frontier.empty()) {
912         EdgeId start = frontier.back();
913         frontier.popBack();
914         if (left_turn_map[start] < 0) continue;  // Already used.
915 
916         // Build a path by making left turns at each vertex until we return to
917         // "start".  Whenever we encounter an edge that is a sibling of an edge
918         // that is already on the path, we "peel off" a loop consisting of any
919         // edges that were between these two edges.
920         EdgeId[] path;
921         for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
922           path ~= e;
923           next = left_turn_map[e];
924           left_turn_map[e] = -1;
925           // If the sibling hasn't been visited yet, add it to the frontier.
926           EdgeId sibling = sibling_map[e];
927           if (left_turn_map[sibling] >= 0) {
928             frontier ~= sibling;
929           }
930           if (degenerate_boundaries == DegenerateBoundaries.DISCARD) {
931             path_index[e] = cast(int) path.length - 1;
932             int sibling_index = path_index[sibling];
933             if (sibling_index < 0) continue;
934 
935             // Common special case: the edge and its sibling are adjacent, in
936             // which case we can simply remove them from the path and continue.
937             if (sibling_index == path.length - 2) {
938               path.length = sibling_index;
939               // We don't need to update "path_index" for these two edges
940               // because both edges of the sibling pair have now been used.
941               continue;
942             }
943             // Peel off a loop from the path.
944             // TODO: Resume here.
945             EdgeId[] loop = path[sibling_index + 1 .. $ - 1];
946             path.length = sibling_index;
947             // Mark the edges that are no longer part of the path.
948             foreach (EdgeId e2; loop) path_index[e2] = -1;
949             canonicalizeLoopOrder(min_input_ids, loop);
950             component ~= loop;
951           }
952         }
953         // Mark the edges that are no longer part of the path.
954         if (degenerate_boundaries == DegenerateBoundaries.DISCARD) {
955           foreach (EdgeId e2; path) path_index[e2] = -1;
956         }
957         canonicalizeLoopOrder(min_input_ids, path);
958         component ~= path;
959       }
960       canonicalizeVectorOrder(min_input_ids, component);
961       components ~= component;
962     }
963     // Sort the components to correspond to the input edge ordering.
964     sort!((in DirectedComponent a, in DirectedComponent b) {
965           return min_input_ids[a[0][0]] < min_input_ids[b[0][0]];
966         })(components);
967     return true;
968   }
969 
970   alias UndirectedComponent = EdgeLoop[][2];
971 
972   /**
973    * Builds loops from a set of undirected edges, turning left at each vertex
974    * until either a repeated vertex (for LoopType::SIMPLE) or a repeated edge
975    * (for LoopType::CIRCUIT) is found.  The loops are further grouped into
976    * "components" such that all the loops in a component are connected by
977    * shared vertices.  Finally, the loops in each component are divided into
978    * two "complements" such that every edge in one complement is the sibling
979    * of an edge in the other complement.  This corresponds to the fact that
980    * given any set of non-crossing undirected loops, there are exactly two
981    * possible interpretations of the region that those loops represent (where
982    * one possibility is the complement of the other).  This method does not
983    * attempt to resolve this ambiguity, but instead returns both possibilities
984    * for each connected component and lets the client choose among them.
985    *
986    * This method is used to build single polygons.  (Use GetDirectedComponents
987    * to build polygon meshes, even when the input edges are undirected.)  To
988    * convert the output of this method into a polygon, the client must choose
989    * one complement from each component such that the entire set of loops is
990    * oriented consistently (i.e., they define a region such that the interior
991    * of the region is always on the left).  The non-chosen complements form
992    * another set of loops that are also oriented consistently but represent
993    * the complementary region on the sphere.  Finally, the client needs to
994    * choose one of these two sets of loops based on heuristics (e.g., the area
995    * of each region), since both sets of loops are equally valid
996    * interpretations of the input.
997    *
998    * Each loop is represented as a sequence of edges.  The edge ordering and
999    * loop ordering are automatically canonicalized in order to preserve the
1000    * input ordering as much as possible.  Loops are non-crossing provided that
1001    * the graph contains no crossing edges.  If some edges cannot be turned
1002    * into loops, returns false and sets "error" appropriately.
1003    *
1004    * REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS }
1005    * REQUIRES: options.edge_type() == UNDIRECTED
1006    * REQUIRES: options.siblings_pairs() == { DISCARD, DISCARD_EXCESS, KEEP }
1007    *           [since REQUIRE, CREATE convert the edge_type() to DIRECTED]
1008    */
1009   bool getUndirectedComponents(
1010       LoopType loop_type, ref UndirectedComponent[] components, ref S2Error error) const
1011   in {
1012     assert(_options.degenerateEdges() == DegenerateEdges.DISCARD
1013         || _options.degenerateEdges() == DegenerateEdges.DISCARD_EXCESS);
1014     assert(_options.edgeType() == EdgeType.UNDIRECTED);
1015   } do {
1016     import std.typecons : Tuple, tuple;
1017     EdgeId[] sibling_map = getInEdgeIds();
1018     EdgeId[] left_turn_map;
1019     if (!getLeftTurnMap(sibling_map, left_turn_map, error)) return false;
1020     makeSiblingMap(sibling_map);
1021     InputEdgeId[] min_input_ids = getMinInputEdgeIds();
1022 
1023     // A stack of unexplored sibling edges.  Each sibling edge has a "slot"
1024     // (0 or 1) that indicates which of the two complements it belongs to.
1025     Tuple!(EdgeId, int)[] frontier;
1026 
1027     // If we are breaking loops at repeated vertices, we maintain a map from
1028     // VertexId to its position in "path".
1029     int[] path_index;
1030     if (loop_type == LoopType.SIMPLE) {
1031       path_index.length = numVertices();
1032       path_index[] = -1;
1033     }
1034 
1035     for (EdgeId min_start = 0; min_start < numEdges(); ++min_start) {
1036       if (left_turn_map[min_start] < 0) continue;  // Already used.
1037 
1038       // Build a connected component by keeping a stack of unexplored siblings
1039       // of the edges used so far.
1040       UndirectedComponent component;
1041       frontier ~= tuple(min_start, 0);
1042       while (!frontier.empty()) {
1043         EdgeId start = frontier.back()[0];
1044         int slot = frontier.back()[1];
1045         frontier.popBack();
1046         if (left_turn_map[start] < 0) continue;  // Already used.
1047 
1048         // Build a path by making left turns at each vertex until we return to
1049         // "start".  We use "left_turn_map" to keep track of which edges have
1050         // already been visited, and which complement they were assigned to, by
1051         // setting its entries to negative values as we go along.
1052         EdgeId[] path;
1053         for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
1054           path ~= e;
1055           next = left_turn_map[e];
1056           left_turn_map[e] = markEdgeUsed(slot);
1057           // If the sibling hasn't been visited yet, add it to the frontier.
1058           EdgeId sibling = sibling_map[e];
1059           if (left_turn_map[sibling] >= 0) {
1060             frontier ~= tuple(sibling, 1 - slot);
1061           } else if (left_turn_map[sibling] != markEdgeUsed(1 - slot)) {
1062             // Two siblings edges can only belong the same complement if the
1063             // given undirected edges do not form loops.
1064             error.initialize(S2Error.Code.BUILDER_EDGES_DO_NOT_FORM_LOOPS,
1065                 "Given undirected edges do not form loops");
1066             return false;
1067           }
1068           if (loop_type == LoopType.SIMPLE) {
1069             // Whenever we encounter a vertex that is already part of the path,
1070             // we "peel off" a loop by removing those edges from the path.
1071             path_index[edge(e)[0]] = cast(int) path.length - 1;
1072             int loop_start = path_index[edge(e)[1]];
1073             if (loop_start < 0) continue;
1074             EdgeId[] loop = path[loop_start .. $];
1075             path.length = loop_start;
1076             // Mark the vertices that are no longer part of the path.
1077             foreach (EdgeId e2; loop) path_index[edge(e2)[0]] = -1;
1078             canonicalizeLoopOrder(min_input_ids, loop);
1079             component[slot] ~= loop;
1080           }
1081         }
1082         if (loop_type == LoopType.SIMPLE) {
1083           enforce(path.empty());  // Invariant.
1084         } else {
1085           canonicalizeLoopOrder(min_input_ids, path);
1086           component[slot] ~= path;
1087         }
1088       }
1089       canonicalizeVectorOrder(min_input_ids, component[0]);
1090       canonicalizeVectorOrder(min_input_ids, component[1]);
1091       // To save some work in S2PolygonLayer, we swap the two loop sets of the
1092       // component so that the loop set whose first loop most closely follows
1093       // the input edge ordering is first.  (If the input was a valid S2Polygon,
1094       // then this component will contain normalized loops.)
1095       if (min_input_ids[component[0][0][0]] > min_input_ids[component[1][0][0]]) {
1096         swap(component[0], component[1]);
1097       }
1098       components ~= component;
1099     }
1100     // Sort the components to correspond to the input edge ordering.
1101     sort!((in UndirectedComponent a, in UndirectedComponent b) {
1102           return min_input_ids[a[0][0][0]] < min_input_ids[b[0][0][0]];
1103         })(components);
1104     return true;
1105   }
1106 
1107   /// Encodes the index of one of the two complements of each component
1108   /// (a.k.a. the "slot", either 0 or 1) as a negative EdgeId.
1109   private static EdgeId markEdgeUsed(int slot) {
1110     return -1 - slot;
1111   }
1112 
1113   /**
1114    * Indicates whether polylines should be "paths" (which don't allow
1115    * duplicate vertices, except possibly the first and last vertex) or
1116    * "walks" (which allow duplicate vertices and edges).
1117    */
1118   enum PolylineType { PATH, WALK }
1119 
1120   /**
1121    * Builds polylines from a set of edges.  If "polyline_type" is PATH, then
1122    * only vertices of indegree and outdegree 1 (or degree 2 in the case of
1123    * undirected edges) will appear in the interior of polylines.  This
1124    * essentially generates one polyline for each edge chain in the graph.  If
1125    * "polyline_type" is WALK, then polylines may pass through the same vertex
1126    * or even the same edge multiple times (if duplicate edges are present),
1127    * and each polyline will be as long as possible.  This option is useful for
1128    * reconstructing a polyline that has been snapped to a lower resolution,
1129    * since snapping can cause edges to become identical.
1130    *
1131    * This method attempts to preserve the input edge ordering in order to
1132    * implement idempotency, even when there are repeated edges or loops.  This
1133    * is true whether directed or undirected edges are used.  Degenerate edges
1134    * are also handled appropriately.
1135    *
1136    * REQUIRES: options.sibling_pairs() == { DISCARD, DISCARD_EXCESS, KEEP }
1137    */
1138   alias EdgePolyline = EdgeId[];
1139   EdgePolyline[] getPolylines(PolylineType polyline_type) const
1140   in {
1141     assert(_options.siblingPairs() == SiblingPairs.DISCARD
1142         || _options.siblingPairs() == SiblingPairs.DISCARD_EXCESS
1143         || _options.siblingPairs() == SiblingPairs.KEEP);
1144   } do {
1145     auto builder = new PolylineBuilder(this);
1146     if (polyline_type == PolylineType.PATH) {
1147       return builder.buildPaths();
1148     } else {
1149       return builder.buildWalks();
1150     }
1151   }
1152 
1153   ////////////////////////////////////////////////////////////////////////
1154   //////////////// Helper Functions for Creating Graphs //////////////////
1155 
1156   /**
1157    * Given an unsorted collection of edges, transform them according to the
1158    * given set of GraphOptions.  This includes actions such as discarding
1159    * degenerate edges; merging duplicate edges; and canonicalizing sibling
1160    * edge pairs in several possible ways (e.g. discarding or creating them).
1161    * The output is suitable for passing to the Graph constructor.
1162    *
1163    * If options.edge_type() == EdgeType::UNDIRECTED, then all input edges
1164    * should already have been transformed into a pair of directed edges.
1165    *
1166    * "input_ids" is a vector of the same length as "edges" that indicates
1167    * which input edges were snapped to each edge.  This vector is also updated
1168    * appropriately as edges are discarded, merged, etc.
1169    *
1170    * Note that "options" may be modified by this method: in particular, the
1171    * edge_type() can be changed if sibling_pairs() is CREATE or REQUIRE (see
1172    * the description of S2Builder::GraphOptions).
1173    */
1174   static void processEdges(
1175       GraphOptions options, ref Edge[] edges, ref InputEdgeIdSetId[] input_ids,
1176       IdSetLexicon id_set_lexicon, ref S2Error error) {
1177     auto processor = new EdgeProcessor(options, &edges, &input_ids, id_set_lexicon);
1178     processor.run(error);
1179     // Certain values of sibling_pairs() discard half of the edges and change
1180     // the edge_type() to DIRECTED (see the description of GraphOptions).
1181     if (options.siblingPairs() == SiblingPairs.REQUIRE
1182         || options.siblingPairs() == SiblingPairs.CREATE) {
1183       options.setEdgeType(EdgeType.DIRECTED);
1184     }
1185   }
1186 
1187   /**
1188    * Given a set of vertices and edges, removes all vertices that do not have
1189    * any edges and returned the new, minimal set of vertices.  Also updates
1190    * each edge in "edges" to correspond to the new vertex numbering.  (Note
1191    * that this method does *not* merge duplicate vertices, it simply removes
1192    * vertices of degree zero.)
1193    *
1194    * The new vertex ordering is a subsequence of the original ordering,
1195    * therefore if the edges were lexicographically sorted before calling this
1196    * method then they will still be sorted after calling this method.
1197    *
1198    * The extra argument "tmp" points to temporary storage used by this method.
1199    * All calls to this method from a single thread can reuse the same
1200    * temporary storage.  It should initially point to an empty vector.  This
1201    * can make a big difference to efficiency when this method is called many
1202    * times (e.g. to extract the vertices for different layers), since the
1203    * incremental running time for each layer becomes O(edges.size()) rather
1204    * than O(vertices.size() + edges.size()).
1205    */
1206   static S2Point[] filterVertices(in S2Point[] vertices, ref Edge[] edges, ref VertexId[] tmp) {
1207     // Gather the vertices that are actually used.
1208     VertexId[] used;
1209     used.reserve(2 * edges.length);
1210     foreach (e; edges) {
1211       used ~= e[0];
1212       used ~= e[1];
1213     }
1214     // Sort the vertices and find the distinct ones.
1215     used = sort(used).uniq().array;
1216 
1217     // Build the list of new vertices, and generate a map from old vertex id to
1218     // new vertex id.
1219     VertexId[] vmap = tmp;
1220     vmap.length = vertices.length;
1221     auto new_vertices = new S2Point[used.length];
1222     for (int i = 0; i < used.length; ++i) {
1223       new_vertices[i] = vertices[used[i]];
1224       vmap[used[i]] = i;
1225     }
1226     // Update the edges.
1227     foreach (e; edges) {
1228       e[0] = vmap[e[0]];
1229       e[1] = vmap[e[1]];
1230     }
1231     return new_vertices;
1232   }
1233 
1234   // A comparison function that allows stable sorting with std::sort (which is
1235   // fast but not stable).  It breaks ties between equal edges by comparing
1236   // their edge ids.
1237   static bool stableLessThan(in Edge a, in Edge b, EdgeId ai, EdgeId bi) {
1238     // The following is simpler but the compiler (2016) doesn't optimize it as
1239     // well as it should:
1240     //   return make_pair(a, ai) < make_pair(b, bi);
1241     if (a[0] < b[0]) return true;
1242     if (b[0] < a[0]) return false;
1243     if (a[1] < b[1]) return true;
1244     if (b[1] < a[1]) return false;
1245     return ai < bi;  // Stable sort.
1246   }
1247 
1248 private:
1249 
1250   static class EdgeProcessor {
1251   public:
1252     this(
1253         in GraphOptions options,
1254         Edge[]* edges,
1255         InputEdgeIdSetId[]* input_ids,
1256         IdSetLexicon id_set_lexicon) {
1257       _options = options;
1258       _edges = edges;
1259       _inputIds = input_ids;
1260       _idSetLexicon = id_set_lexicon;
1261 
1262       // TODO: Resume here.
1263 
1264       // Sort the outgoing and incoming edges in lexigraphic order.  We use a
1265       // stable sort to ensure that each undirected edge becomes a sibling pair,
1266       // even if there are multiple identical input edges.
1267       _outEdges = iota(0, cast(int) (*_edges).length).array;
1268       sort!((EdgeId a, EdgeId b) {
1269             return stableLessThan((*_edges)[a], (*_edges)[b], a, b);
1270           })(_outEdges);
1271       _inEdges = iota(0, cast(int) (*_edges).length).array;
1272       sort!((EdgeId a, EdgeId b) {
1273             return stableLessThan(reverse((*_edges)[a]), reverse((*_edges)[b]), a, b);
1274           })(_inEdges);
1275       _newEdges.reserve((*_edges).length);
1276       _newInputIds.reserve((*_edges).length);
1277     }
1278 
1279     void run(ref S2Error error) {
1280       int num_edges = cast(int) (*_edges).length;
1281       if (num_edges == 0) return;
1282 
1283       // Walk through the two sorted arrays performing a merge join.  For each
1284       // edge, gather all the duplicate copies of the edge in both directions
1285       // (outgoing and incoming).  Then decide what to do based on "options_" and
1286       // how many copies of the edge there are in each direction.
1287       int outId = 0;
1288       int inId = 0;
1289       Edge out_edge = (*_edges)[_outEdges[outId]];
1290       Edge in_edge = (*_edges)[_inEdges[inId]];
1291       Edge sentinel = tuple(VertexId.max, VertexId.max);
1292       for (;;) {
1293         Edge edge = min(out_edge, reverse(in_edge));
1294         if (edge == sentinel) break;
1295 
1296         int out_begin = outId;
1297         int in_begin = inId;
1298         while (out_edge == edge) {
1299           out_edge = (++outId == num_edges) ? sentinel : (*_edges)[_outEdges[outId]];
1300         }
1301         while (reverse(in_edge) == edge) {
1302           in_edge = (++inId == num_edges) ? sentinel : (*_edges)[_inEdges[inId]];
1303         }
1304         int n_out = outId - out_begin;
1305         int n_in = inId - in_begin;
1306         if (edge[0] == edge[1]) {
1307           debug enforce(n_in == n_out);
1308           if (_options.degenerateEdges() == DegenerateEdges.DISCARD) {
1309             continue;
1310           }
1311           if (_options.degenerateEdges() == DegenerateEdges.DISCARD_EXCESS
1312               && ((out_begin > 0 && (*_edges)[_outEdges[out_begin - 1]][0] == edge[0])
1313                   || (outId < num_edges && (*_edges)[_outEdges[outId]][0] == edge[0])
1314                   || (in_begin > 0 && (*_edges)[_inEdges[in_begin - 1]][1] == edge[0])
1315                   || (inId < num_edges && (*_edges)[_inEdges[inId]][1] == edge[0]))) {
1316             continue;  // There were non-degenerate incident edges, so discard.
1317           }
1318           if (_options.edgeType() == EdgeType.UNDIRECTED
1319               && (_options.siblingPairs() == SiblingPairs.REQUIRE
1320                   || _options.siblingPairs() == SiblingPairs.CREATE)) {
1321             // When we have undirected edges and are guaranteed to have siblings,
1322             // we cut the number of edges in half (see s2builder.h).
1323             debug enforce((n_out & 1) == 0);  // Number of edges is always even.
1324             addEdges(_options.duplicateEdges() == DuplicateEdges.MERGE ? 1 : (n_out / 2),
1325                 edge, mergeInputIds(out_begin, outId));
1326           } else if (_options.duplicateEdges() == DuplicateEdges.MERGE) {
1327             addEdges(_options.edgeType() == EdgeType.UNDIRECTED ? 2 : 1,
1328                 edge, mergeInputIds(out_begin, outId));
1329           } else if (_options.siblingPairs() == SiblingPairs.DISCARD ||
1330               _options.siblingPairs() == SiblingPairs.DISCARD_EXCESS) {
1331             // Any SiblingPair option that discards edges causes the labels of all
1332             // duplicate edges to be merged together (see s2builder.h).
1333             addEdges(n_out, edge, mergeInputIds(out_begin, outId));
1334           } else {
1335             copyEdges(out_begin, outId);
1336           }
1337         } else if (_options.siblingPairs() == SiblingPairs.KEEP) {
1338           if (n_out > 1 && _options.duplicateEdges() == DuplicateEdges.MERGE) {
1339             addEdge(edge, mergeInputIds(out_begin, outId));
1340           } else {
1341             copyEdges(out_begin, outId);
1342           }
1343         } else if (_options.siblingPairs() == SiblingPairs.DISCARD) {
1344           if (_options.edgeType() == EdgeType.DIRECTED) {
1345             // If n_out == n_in: balanced sibling pairs
1346             // If n_out < n_in:  unbalanced siblings, in the form AB, BA, BA
1347             // If n_out > n_in:  unbalanced siblings, in the form AB, AB, BA
1348             if (n_out <= n_in) continue;
1349             // Any option that discards edges causes the labels of all duplicate
1350             // edges to be merged together (see s2builder.h).
1351             addEdges(_options.duplicateEdges() == DuplicateEdges.MERGE
1352                 ? 1 : (n_out - n_in), edge, mergeInputIds(out_begin, outId));
1353           } else {
1354             if ((n_out & 1) == 0) continue;
1355             addEdge(edge, mergeInputIds(out_begin, outId));
1356           }
1357         } else if (_options.siblingPairs() == SiblingPairs.DISCARD_EXCESS) {
1358           if (_options.edgeType() == EdgeType.DIRECTED) {
1359             // See comments above.  The only difference is that if there are
1360             // balanced sibling pairs, we want to keep one such pair.
1361             if (n_out < n_in) continue;
1362             addEdges(_options.duplicateEdges() == DuplicateEdges.MERGE
1363                 ? 1 : max(1, n_out - n_in), edge, mergeInputIds(out_begin, outId));
1364           } else {
1365             addEdges((n_out & 1) ? 1 : 2, edge, mergeInputIds(out_begin, outId));
1366           }
1367         } else {
1368           debug enforce(_options.siblingPairs() == SiblingPairs.REQUIRE
1369               || _options.siblingPairs() == SiblingPairs.CREATE);
1370           if (error.ok() && _options.siblingPairs() == SiblingPairs.REQUIRE
1371               && (_options.edgeType() == EdgeType.DIRECTED
1372                   ? (n_out != n_in) : ((n_out & 1) != 0))) {
1373             error.initialize(S2Error.Code.BUILDER_MISSING_EXPECTED_SIBLING_EDGES,
1374                 "Expected all input edges to have siblings, but some were missing");
1375           }
1376           if (_options.duplicateEdges() == DuplicateEdges.MERGE) {
1377             addEdge(edge, mergeInputIds(out_begin, outId));
1378           } else if (_options.edgeType() == EdgeType.UNDIRECTED) {
1379             addEdges((n_out + 1) / 2, edge, mergeInputIds(out_begin, outId));
1380           } else {
1381             copyEdges(out_begin, outId);
1382             if (n_in > n_out) {
1383               addEdges(n_in - n_out, edge, mergeInputIds(outId, outId));
1384             }
1385           }
1386         }
1387       }
1388       *_edges = _newEdges;
1389       *_inputIds = _newInputIds;
1390     }
1391 
1392   private:
1393     void addEdge(Edge edge, InputEdgeIdSetId input_edge_id_set_id) {
1394       _newEdges ~= edge;
1395       _newInputIds ~= input_edge_id_set_id;
1396     }
1397 
1398     void addEdges(int num_edges, Edge edge, InputEdgeIdSetId input_edge_id_set_id) {
1399       for (int i = 0; i < num_edges; ++i) {
1400         addEdge(edge, input_edge_id_set_id);
1401       }
1402     }
1403 
1404     void copyEdges(int out_begin, int out_end) {
1405       for (int i = out_begin; i < out_end; ++i) {
1406         addEdge((*_edges)[_outEdges[i]], (*_inputIds)[_outEdges[i]]);
1407       }
1408     }
1409 
1410     InputEdgeIdSetId mergeInputIds(int out_begin, int out_end) {
1411       if (out_end - out_begin == 1) {
1412         return (*_inputIds)[_outEdges[out_begin]];
1413       }
1414       _tmpIds.length = 0;
1415       for (int i = out_begin; i < out_end; ++i) {
1416         foreach (id; _idSetLexicon.idSet((*_inputIds)[_outEdges[i]])) {
1417           _tmpIds ~= id;
1418         }
1419       }
1420       return _idSetLexicon.add(_tmpIds);
1421     }
1422 
1423     const(GraphOptions) _options;
1424     Edge[]* _edges;
1425     InputEdgeIdSetId[]* _inputIds;
1426     IdSetLexicon _idSetLexicon;
1427     EdgeId[] _outEdges;
1428     EdgeId[] _inEdges;
1429 
1430     Edge[] _newEdges;
1431     InputEdgeIdSetId[] _newInputIds;
1432 
1433     InputEdgeId[] _tmpIds;
1434   }
1435 
1436   static class PolylineBuilder {
1437   public:
1438     this(in Graph g) {
1439       _g = g;
1440       _in = new VertexInMap(g);
1441       _out = new VertexOutMap(g);
1442       _minInputIds = g.getMinInputEdgeIds();
1443       _directed = _g.options().edgeType() == Graph.EdgeType.DIRECTED;
1444       _edgesLeft = g.numEdges() / (_directed ? 1 : 2);
1445       _used.length = g.numEdges();
1446       _used[] = false;
1447       if (!_directed) {
1448         _siblingMap = _in.inEdgeIds().dup;
1449         g.makeSiblingMap(_siblingMap);
1450       }
1451     }
1452 
1453     EdgePolyline[] buildPaths() {
1454       // First build polylines starting at all the vertices that cannot be in the
1455       // polyline interior (i.e., indegree != 1 or outdegree != 1 for directed
1456       // edges, or degree != 2 for undirected edges).  We consider the possible
1457       // starting edges in input edge id order so that we preserve the input path
1458       // direction even when undirected edges are used.  (Undirected edges are
1459       // represented by sibling pairs where only the edge in the input direction
1460       // is labeled with an input edge id.)
1461       EdgePolyline[] polylines;
1462       EdgeId[] edges = _g.getInputEdgeOrder(_minInputIds);
1463       foreach (i; 0 .. edges.length) {
1464         EdgeId e = edges[i];
1465         if (!_used[e] && !isInterior(_g.edge(e)[0])) {
1466           polylines ~= buildPath(e);
1467         }
1468       }
1469       // If there are any edges left, they form non-intersecting loops.  We build
1470       // each loop and then canonicalize its edge order.  We consider candidate
1471       // starting edges in input edge id order in order to preserve the input
1472       // direction of undirected loops.  Even so, we still need to canonicalize
1473       // the edge order to ensure that when an input edge is split into an edge
1474       // chain, the loop does not start in the middle of such a chain.
1475       for (int i = 0; i < edges.length && _edgesLeft > 0; ++i) {
1476         EdgeId e = edges[i];
1477         if (_used[e]) continue;
1478         EdgePolyline polyline = buildPath(e);
1479         canonicalizeLoopOrder(_minInputIds, polyline);
1480         polylines ~= polyline;
1481       }
1482       debug enforce(_edgesLeft == 0);
1483 
1484       // Sort the polylines to correspond to the input order (if possible).
1485       canonicalizeVectorOrder(_minInputIds, polylines);
1486       return polylines;
1487     }
1488 
1489     EdgePolyline[] buildWalks() {
1490       // Note that some of this code is worst-case quadratic in the maximum vertex
1491       // degree.  This could be fixed with a few extra arrays, but it should not
1492       // be a problem in practice.
1493 
1494       // First, build polylines from all vertices where outdegree > indegree (or
1495       // for undirected edges, vertices whose degree is odd).  We consider the
1496       // possible starting edges in input edge id order, for idempotency in the
1497       // case where multiple input polylines share vertices or edges.
1498       EdgePolyline[] polylines;
1499       EdgeId[] edges = _g.getInputEdgeOrder(_minInputIds);
1500       for (int i = 0; i < edges.length; ++i) {
1501         EdgeId e = edges[i];
1502         if (_used[e]) continue;
1503         VertexId v = _g.edge(e)[0];
1504         int excess = excessDegree(v);
1505         if (excess <= 0) continue;
1506         if (v !in _excessUsed) _excessUsed[v] = 0;
1507         excess -= _excessUsed[v];
1508         if (_directed ? (excess <= 0) : (excess % 2 == 0)) continue;
1509         ++_excessUsed[v];
1510         polylines ~= buildWalk(v);
1511         --_excessUsed[_g.edge(polylines.back().back())[1]];
1512       }
1513       // Now all vertices have outdegree == indegree (or even degree if undirected
1514       // edges are being used).  Therefore all remaining edges can be assembled
1515       // into loops.  We first try to expand the existing polylines if possible by
1516       // adding loops to them.
1517       if (_edgesLeft > 0) {
1518         foreach (ref Graph.EdgePolyline polyline; polylines) {
1519           maximizeWalk(polyline);
1520         }
1521       }
1522       // Finally, if there are still unused edges then we build loops.  If the
1523       // input is a polyline that forms a loop, then for idempotency we need to
1524       // start from the edge with minimum input edge id.  If the minimal input
1525       // edge was split into several edges, then we start from the first edge of
1526       // the chain.
1527       for (int i = 0; i < edges.length && _edgesLeft > 0; ++i) {
1528         EdgeId e = edges[i];
1529         if (_used[e]) continue;
1530 
1531         // Determine whether the origin of this edge is the start of an edge
1532         // chain.  To do this, we test whether (outdegree - indegree == 1) for the
1533         // origin, considering only unused edges with the same minimum input edge
1534         // id.  (Undirected edges have input edge ids in one direction only.)
1535         VertexId v = _g.edge(e)[0];
1536         InputEdgeId id = _minInputIds[e];
1537         int excess = 0;
1538         for (int j = i; j < edges.length && _minInputIds[edges[j]] == id; ++j) {
1539           EdgeId e2 = edges[j];
1540           if (_used[e2]) continue;
1541           if (_g.edge(e2)[0] == v) ++excess;
1542           if (_g.edge(e2)[1] == v) --excess;
1543         }
1544         // It is also acceptable to start a polyline from any degenerate edge.
1545         if (excess == 1 || _g.edge(e)[1] == v) {
1546           Graph.EdgePolyline polyline = buildWalk(v);
1547           maximizeWalk(polyline);
1548           polylines ~= polyline;
1549         }
1550       }
1551       debug enforce(_edgesLeft == 0);
1552 
1553       // Sort the polylines to correspond to the input order (if possible).
1554       canonicalizeVectorOrder(_minInputIds, polylines);
1555       return polylines;
1556     }
1557 
1558   private:
1559     bool isInterior(VertexId v) {
1560       if (_directed) {
1561         return _in.degree(v) == 1 && _out.degree(v) == 1;
1562       } else {
1563         return _out.degree(v) == 2;
1564       }
1565     }
1566 
1567     int excessDegree(VertexId v) {
1568       return _directed ? _out.degree(v) - _in.degree(v) : _out.degree(v) % 2;
1569     }
1570 
1571     EdgePolyline buildPath(EdgeId e) {
1572       // We simply follow edges until either we reach a vertex where there is a
1573       // choice about which way to go (where is_interior(v) is false), or we
1574       // return to the starting vertex (if the polyline is actually a loop).
1575       EdgePolyline polyline;
1576       VertexId start = _g.edge(e)[0];
1577       for (;;) {
1578         polyline ~= e;
1579         debug enforce(!_used[e]);
1580         _used[e] = true;
1581         if (!_directed) _used[_siblingMap[e]] = true;
1582         --_edgesLeft;
1583         VertexId v = _g.edge(e)[1];
1584         if (!isInterior(v) || v == start) break;
1585         if (_directed) {
1586           debug enforce(_out.degree(v) == 1);
1587           e = _out.edgeIds(v).front();
1588         } else {
1589           debug enforce(_out.degree(v) == 2);
1590           foreach (EdgeId e2; _out.edgeIds(v)) if (!_used[e2]) e = e2;
1591         }
1592       }
1593       return polyline;
1594     }
1595 
1596     EdgePolyline buildWalk(VertexId v) {
1597       EdgePolyline polyline;
1598       for (;;) {
1599         // Follow the edge with the smallest input edge id.
1600         EdgeId best_edge = -1;
1601         InputEdgeId best_out_id = InputEdgeId.max;
1602         foreach (EdgeId e; _out.edgeIds(v)) {
1603           if (_used[e] || _minInputIds[e] >= best_out_id) continue;
1604           best_out_id = _minInputIds[e];
1605           best_edge = e;
1606         }
1607         if (best_edge < 0) return polyline;
1608         // For idempotency when there are multiple input polylines, we stop the
1609         // walk early if "best_edge" might be a continuation of a different
1610         // incoming edge.
1611         if (v !in _excessUsed) _excessUsed[v] = 0;
1612         int excess = excessDegree(v) - _excessUsed[v];
1613         if (_directed ? (excess < 0) : (excess % 2) == 1) {
1614           foreach (EdgeId e; _in.edgeIds(v)) {
1615             if (!_used[e] && _minInputIds[e] <= best_out_id) {
1616               return polyline;
1617             }
1618           }
1619         }
1620         polyline ~= best_edge;
1621         _used[best_edge] = true;
1622         if (!_directed) _used[_siblingMap[best_edge]] = true;
1623         --_edgesLeft;
1624         v = _g.edge(best_edge)[1];
1625       }
1626     }
1627 
1628     void maximizeWalk(ref EdgePolyline polyline) {
1629       // Examine all vertices of the polyline and check whether there are any
1630       // unused outgoing edges.  If so, then build a loop starting at that vertex
1631       // and insert it into the polyline.  (The walk is guaranteed to be a loop
1632       // because this method is only called when all vertices have equal numbers
1633       // of unused incoming and outgoing edges.)
1634       for (int i = 0; i <= polyline.length; ++i) {
1635         VertexId v = (i == 0 ? _g.edge(polyline[i])[0] : _g.edge(polyline[i - 1])[1]);
1636         foreach (EdgeId e; _out.edgeIds(v)) {
1637           if (!_used[e]) {
1638             EdgePolyline loop = buildWalk(v);
1639             debug enforce(_g.edge(loop.back())[1] == v);
1640             polyline = polyline[0 .. i] ~ loop ~ polyline[i .. $];
1641             debug enforce(_used[e]);  // All outgoing edges from "v" are now used.
1642             break;
1643           }
1644         }
1645       }
1646     }
1647 
1648     const(Graph) _g;
1649     VertexInMap _in;
1650     VertexOutMap _out;
1651     EdgeId[] _siblingMap;
1652     InputEdgeId[] _minInputIds;
1653     bool _directed;
1654     int _edgesLeft;
1655     bool[] _used;
1656 
1657     // A map of (outdegree(v) - indegree(v)) considering used edges only.
1658     int[VertexId] _excessUsed;
1659   }
1660 
1661   const(GraphOptions) _options;
1662   VertexId _numVertices;  // Cached to avoid division by 24.
1663 
1664   const(S2Point[]) _vertices;
1665   const(Edge[]) _edges;
1666   const(InputEdgeIdSetId[]) _inputEdgeIdSetIds;
1667   const(IdSetLexicon) _inputEdgeIdSetLexicon;
1668   const(LabelSetId[]) _labelSetIds;
1669   const(IdSetLexicon) _labelSetLexicon;
1670   IsFullPolygonPredicate _isFullPolygonPredicate;
1671 }
1672 
1673 /// A struct for sorting the incoming and outgoing edges around a vertex "v0".
1674 private struct VertexEdge {
1675   bool incoming;            // Is this an incoming edge to "v0"?
1676   Graph.EdgeId index;       // Index of this edge in "edges_" or "in_edge_ids"
1677   Graph.VertexId endpoint;  // The other (not "v0") endpoint of this edge
1678   int rank;                 // Secondary key for edges with the same endpoint
1679 }
1680 
1681 /**
1682  * Given a set of duplicate outgoing edges (v0, v1) and a set of duplicate
1683  * incoming edges (v1, v0), this method assigns each edge an integer "rank" so
1684  * that the edges are sorted in a consistent order with respect to their
1685  * orderings around "v0" and "v1".  Usually there is just one edge, in which
1686  * case this is easy.  Sometimes there is one edge in each direction, in which
1687  * case the outgoing edge is always ordered before the incoming edge.
1688  *
1689  * In general, we allow any number of duplicate edges in each direction, in
1690  * which case outgoing edges are interleaved with incoming edges so as to
1691  * create as many degenerate (two-edge) loops as possible.  In order to get a
1692  * consistent ordering around "v0" and "v1", we move forwards through the list
1693  * of outgoing edges and backwards through the list of incoming edges.  If
1694  * there are more incoming edges, they go at the beginning of the ordering,
1695  * while if there are more outgoing edges then they go at the end.
1696  *
1697  * For example, suppose there are 2 edges "a,b" from "v0" to "v1", and 4 edges
1698  * "w,x,y,z" from "v1" to "v0".  Using lower/upper case letters to represent
1699  * incoming/outgoing edges, the clockwise ordering around v0 would be zyAxBw,
1700  * and the clockwise ordering around v1 would be WbXaYZ.  (Try making a
1701  * diagram with each edge as a separate arc.)
1702  */
1703 private void addVertexEdges(
1704     Graph.EdgeId out_begin, Graph.EdgeId out_end,
1705     Graph.EdgeId in_begin, Graph.EdgeId in_end,
1706     Graph.VertexId v1, ref VertexEdge[] v0_edges) {
1707   int rank = 0;
1708   // Any extra incoming edges go at the beginning of the ordering.
1709   while (in_end - in_begin > out_end - out_begin) {
1710     v0_edges ~= VertexEdge(true, --in_end, v1, rank++);
1711   }
1712   // Next we interleave as many outgoing and incoming edges as possible.
1713   while (in_end > in_begin) {
1714     v0_edges ~= VertexEdge(false, out_begin++, v1, rank++);
1715     v0_edges ~= VertexEdge(true, --in_end, v1, rank++);
1716   }
1717   // Any extra outgoing edges to at the end of the ordering.
1718   while (out_end > out_begin) {
1719     v0_edges ~= VertexEdge(false, out_begin++, v1, rank++);
1720   }
1721 }
1722