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 }