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.util.s2polyline_vector_layer;
20 
21 import s2.id_set_lexicon;
22 import s2.mutable_s2shape_index;
23 import s2.s2point;
24 import s2.s2builder;
25 import s2.builder.graph;
26 import s2.builder.layer;
27 import s2.s2debug;
28 import s2.s2error;
29 import s2.s2polyline;
30 
31 import std.range;
32 
33 alias DegenerateEdges = GraphOptions.DegenerateEdges;
34 
35 /**
36  * A layer type that assembles edges (directed or undirected) into multiple
37  * S2Polylines.  Returns an error if S2Builder found any problem with the
38  * input edges; this layer type does not generate any errors of its own.
39  *
40  * Duplicate edges are handled correctly (e.g., if a polyline backtracks on
41  * itself, or loops around and retraces some of its previous edges.)  The
42  * implementation attempts to preserve the order of the input edges whenever
43  * possible, so that if the input is a polyline and it is not modified by
44  * S2Builder, then the output will be the same polyline even if the polyline
45  * forms a loop.  However, note that this is not guaranteed when undirected
46  * edges are used: for example, if the input consists of a single undirected
47  * edge, then either directed edge may be returned.
48  */
49 class S2PolylineVectorLayer : Layer {
50 public:
51   static struct Options {
52   public:
53     /**
54      * Indicates whether the input edges provided to S2Builder are directed or
55      * undirected.
56      *
57      * Directed edges should be used whenever possible to avoid ambiguity.
58      * The implementation attempts to preserve the structure of directed input
59      * edges whenever possible, so that if the input is a vector of disjoint
60      * polylines and none of them need to be modified then the output will be
61      * the same polylines in the same order.  With undirected edges, there are
62      * no such guarantees.
63      *
64      * DEFAULT: S2Builder::EdgeType::DIRECTED
65      */
66     S2Builder.EdgeType edgeType() const {
67       return _edgeType;
68     }
69 
70     void setEdgeType(S2Builder.EdgeType edge_type) {
71       _edgeType = edge_type;
72     }
73 
74 
75     alias PolylineType = Graph.PolylineType;
76 
77     /**
78      * Indicates whether polylines should be "paths" (which don't allow
79      * duplicate vertices, except possibly the first and last vertex) or
80      * "walks" (which allow duplicate vertices and edges).
81      *
82      * If your input consists of polylines, and you want to split them into
83      * separate pieces whenever they self-intersect or cross each other, then
84      * use PolylineType::PATH (and probably use split_crossing_edges()).  If
85      * you don't mind if your polylines backtrack or contain loops, then use
86      * PolylineType::WALK.
87      *
88      * DEFAULT: PolylineType::PATH
89      */
90     PolylineType polylineType() const {
91       return _polylineType;
92     }
93 
94     void setPolylineType(PolylineType polyline_type) {
95       _polylineType = polyline_type;
96     }
97 
98     alias DuplicateEdges = GraphOptions.DuplicateEdges;
99 
100     /**
101      * Indicates whether duplicate edges in the input should be kept (KEEP) or
102      * merged together (MERGE).  Note you can use edge labels to determine
103      * which input edges were merged into a given output edge.
104      *
105      * DEFAULT: DuplicateEdges::KEEP
106      */
107     DuplicateEdges duplicateEdges() const {
108       return _duplicateEdges;
109     }
110 
111     void setDuplicateEdges(DuplicateEdges duplicate_edges) {
112       _duplicateEdges = duplicate_edges;
113     }
114 
115     alias SiblingPairs = GraphOptions.SiblingPairs;
116 
117     /**
118      * Indicates whether sibling edge pairs (i.e., pairs consisting of an edge
119      * and its reverse edge) should be kept (KEEP) or discarded (DISCARD).
120      * For example, if a polyline backtracks on itself, the DISCARD option
121      * would cause this section of the polyline to be removed.  Note that this
122      * option may cause a single polyline to split into several pieces (e.g.,
123      * if a polyline has a "lollipop" shape).
124      *
125      * REQUIRES: sibling_pairs == { DISCARD, KEEP }
126      *           (the CREATE and REQUIRE options are not allowed)
127      *
128      * DEFAULT: SiblingPairs::KEEP
129      */
130     SiblingPairs siblingPairs() const {
131       return _siblingPairs;
132     }
133 
134     void setSiblingPairs(SiblingPairs sibling_pairs)
135     in {
136       assert(sibling_pairs == SiblingPairs.KEEP || sibling_pairs == SiblingPairs.DISCARD);
137     } do {
138       _siblingPairs = sibling_pairs;
139     }
140 
141     /**
142      * If true, calls FindValidationError() on each output polyline.  If any
143      * error is found, it will be returned by S2Builder::Build().
144      *
145      * Note that this option calls set_s2debug_override(S2Debug::DISABLE) in
146      * order to turn off the default error checking in debug builds.
147      *
148      * DEFAULT: false
149      */
150     bool validate() const {
151       return _validate;
152     }
153 
154     void setValidate(bool validate) {
155       _validate = validate;
156       setS2debugOverride(S2Debug.DISABLE);
157     }
158 
159     // This method can turn off the automatic validity checks triggered by the
160     // --s2debug flag (which is on by default in debug builds).  The main
161     // reason to do this is if your code already does its own error checking,
162     // or if you need to work with invalid geometry for some reason.
163     //
164     // In any case, polylines have very few restrictions so they are unlikely
165     // to have errors.  Errors include vertices that aren't unit length (which
166     // can only happen if they are present in the input data), or adjacent
167     // vertices that are at antipodal points on the sphere (unlikely with real
168     // data).  The other possible error is adjacent identical vertices, but
169     // this can't happen because S2Builder does not generate such polylines.
170     //
171     // DEFAULT: S2Debug::ALLOW
172     S2Debug s2debugOverride() const {
173       return _s2debugOverride;
174     }
175 
176     void setS2debugOverride(S2Debug s2debug_override) {
177       _s2debugOverride = s2debug_override;
178     }
179 
180   private:
181     S2Builder.EdgeType _edgeType = S2Builder.EdgeType.DIRECTED;
182     PolylineType _polylineType = PolylineType.PATH;
183     DuplicateEdges _duplicateEdges = DuplicateEdges.KEEP;
184     SiblingPairs _siblingPairs = SiblingPairs.KEEP;
185     bool _validate = false;
186     S2Debug _s2debugOverride = S2Debug.ALLOW;
187   }
188 
189   /// Specifies that a vector of polylines should be constructed using the
190   /// given options.
191   this(S2Polyline[]* polylines, Options options = Options()) {
192     initialize(polylines, null, null, options);
193   }
194 
195   alias LabelSetIds = LabelSetId[][];
196 
197   /**
198    * Specifies that a vector of polylines should be constructed using the
199    * given options, and that any labels attached to the input edges should be
200    * returned in "label_set_ids" and "label_set_lexicion".
201    *
202    * The labels associated with the edge "polyline[i].vertex({j, j+1})" can be
203    * retrieved as follows:
204    *
205    *   for (int32 label : label_set_lexicon.id_set(label_set_ids[i][j])) {...}
206    */
207   this(S2Polyline[]* polylines,
208       LabelSetIds* label_set_ids,
209       IdSetLexicon* label_set_lexicon,
210       Options options = Options()) {
211     initialize(polylines, label_set_ids, label_set_lexicon, options);
212   }
213 
214   // Layer interface:
215   override
216   GraphOptions graphOptions() const {
217     return new GraphOptions(_options.edgeType(), DegenerateEdges.DISCARD,
218         _options.duplicateEdges(), _options.siblingPairs());
219   }
220 
221   override
222   void build(in Graph g, ref S2Error error) {
223     Graph.EdgePolyline[] edge_polylines = g.getPolylines(_options.polylineType());
224     (*_polylines).reserve(edge_polylines.length);
225     if (_labelSetIds) (*_labelSetIds).reserve(edge_polylines.length);
226     S2Point[] vertices;  // Temporary storage for vertices.
227     Label[] labels;  // Temporary storage for labels.
228     foreach (edge_polyline; edge_polylines) {
229       vertices ~= g.vertex(g.edge(edge_polyline[0])[0]);
230       foreach (Graph.EdgeId e; edge_polyline) {
231         vertices ~= g.vertex(g.edge(e)[1]);
232       }
233       S2Polyline polyline = new S2Polyline(vertices, _options.s2debugOverride());
234       vertices.length = 0;
235       if (_options.validate()) {
236         polyline.findValidationError(error);
237       }
238       (*_polylines) ~= polyline;
239       if (_labelSetIds) {
240         auto fetcher = new Graph.LabelFetcher(g, _options.edgeType());
241         LabelSetId[] polyline_labels;
242         polyline_labels.reserve(edge_polyline.length);
243         foreach (Graph.EdgeId e; edge_polyline) {
244           fetcher.fetch(e, labels);
245           polyline_labels ~= _labelSetLexicon.add(labels);
246         }
247         (*_labelSetIds) ~= polyline_labels;
248       }
249     }
250   }
251 
252 private:
253   void initialize(S2Polyline[]* polylines, LabelSetIds* label_set_ids,
254       IdSetLexicon* label_set_lexicon, Options options)
255   in {
256     assert((label_set_ids is null) == (label_set_lexicon is null));
257   } do {
258     _polylines = polylines;
259     _labelSetIds = label_set_ids;
260     _labelSetLexicon = label_set_lexicon;
261     _options = options;
262   }
263 
264   S2Polyline[]* _polylines;
265   LabelSetIds* _labelSetIds;
266   IdSetLexicon* _labelSetLexicon;
267   Options _options;
268 }
269 
270 /// Like S2PolylineVectorLayer, but adds the polylines to a MutableS2ShapeIndex.
271 class IndexedS2PolylineVectorLayer : Layer {
272 public:
273   alias Options = S2PolylineVectorLayer.Options;
274 
275   this(MutableS2ShapeIndex index, Options options = Options()) {
276     _index = index;
277     _layer = new S2PolylineVectorLayer(&_polylines, options);
278   }
279 
280   override
281   GraphOptions graphOptions() const {
282     return _layer.graphOptions();
283   }
284 
285   override
286   void build(in Graph g, ref S2Error error) {
287     _layer.build(g, error);
288     if (error.ok()) {
289       foreach (polyline; _polylines) {
290         _index.add(new S2Polyline.Shape(polyline));
291       }
292     }
293   }
294 
295 private:
296   MutableS2ShapeIndex _index;
297   S2Polyline[] _polylines;
298   S2PolylineVectorLayer _layer;
299 }