/src/s2geometry/src/s2/s2boolean_operation.h
Line | Count | Source |
1 | | // Copyright 2017 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 | | // Author: ericv@google.com (Eric Veach) |
17 | | |
18 | | #ifndef S2_S2BOOLEAN_OPERATION_H_ |
19 | | #define S2_S2BOOLEAN_OPERATION_H_ |
20 | | |
21 | | #include <cstdint> |
22 | | #include <memory> |
23 | | #include <utility> |
24 | | #include <vector> |
25 | | |
26 | | #include "absl/base/nullability.h" |
27 | | #include "absl/log/absl_log.h" |
28 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
29 | | #include "s2/s2builder.h" |
30 | | #include "s2/s2builder_graph.h" |
31 | | #include "s2/s2builder_layer.h" |
32 | | #include "s2/s2error.h" |
33 | | #include "s2/s2memory_tracker.h" |
34 | | #include "s2/s2shape_index.h" |
35 | | #include "s2/value_lexicon.h" |
36 | | |
37 | | // This class implements boolean operations (intersection, union, difference, |
38 | | // and symmetric difference) for regions whose boundaries are defined by |
39 | | // geodesic edges. |
40 | | // |
41 | | // S2BooleanOperation operates on exactly two input regions at a time. Each |
42 | | // region is represented as an S2ShapeIndex and may contain any number of |
43 | | // points, polylines, and polygons. The region is essentially the union of |
44 | | // these objects, except that polygon interiors must be disjoint from all |
45 | | // other geometry (including other polygon interiors). If the input geometry |
46 | | // for a region does not meet this condition, it can be normalized by |
47 | | // computing its union first. Duplicate polygon edges are not allowed (even |
48 | | // among different polygons), however polylines may have duplicate edges and |
49 | | // may even be self-intersecting. Note that points or polylines are allowed |
50 | | // to coincide with the boundaries of polygons. |
51 | | // |
52 | | // Degeneracies are fully supported. Supported degeneracy types include the |
53 | | // following: |
54 | | // |
55 | | // - Point polylines consisting of a single degenerate edge AA. |
56 | | // |
57 | | // - Point loops consisting of a single vertex A. Such loops may represent |
58 | | // either shells or holes according to whether the loop adds to or |
59 | | // subtracts from the surrounding region of the polygon. |
60 | | // |
61 | | // - Sibling edge pairs of the form {AB, BA}. Such sibling pairs may |
62 | | // represent either shells or holes according to whether they add to or |
63 | | // subtract from the surrounding region. The edges of a sibling pair may |
64 | | // belong to the same polygon loop (e.g. a loop AB) or to different polygon |
65 | | // loops or polygons (e.g. the polygons {ABC, CBD}). |
66 | | // |
67 | | // A big advantage of degeneracy support is that geometry may be simplified |
68 | | // without completely losing small details. For example, if a polygon |
69 | | // representing a land area with many lakes and rivers is simplified using a |
70 | | // tolerance of 1 kilometer, every water feature in the input is guaranteed to |
71 | | // be within 1 kilometer of some water feature in the input (even if some |
72 | | // lakes and rivers are merged and/or reduced to degenerate point or sibling |
73 | | // edge pair holes). Mathematically speaking, degeneracy support allows |
74 | | // geometry to be simplified while guaranteeing that the Hausdorff distance |
75 | | // between the boundaries of the original and simplified geometries is at |
76 | | // most the simplification tolerance. It also allows geometry to be |
77 | | // simplified without changing its dimension, thus preserving boundary |
78 | | // semantics. (Note that the boundary of a polyline ABCD is {A,D}, whereas |
79 | | // the boundary of a degenerate shell ABCDCB is its entire set of vertices and |
80 | | // edges.) |
81 | | // |
82 | | // Points and polyline edges are treated as multisets: if the same point or |
83 | | // polyline edge appears multiple times in the input, it will appear multiple |
84 | | // times in the output. For example, the union of a point with an identical |
85 | | // point consists of two points. This feature is useful for modeling large |
86 | | // sets of points or polylines as a single region while maintaining their |
87 | | // distinct identities, even when the points or polylines intersect each |
88 | | // other. It is also useful for reconstructing polylines that loop back on |
89 | | // themselves (e.g., time series such as GPS tracks). If duplicate geometry |
90 | | // is not desired, it can easily be removed by choosing the appropriate |
91 | | // S2Builder output layer options. |
92 | | // |
93 | | // Self-intersecting polylines can be manipulated without materializing new |
94 | | // vertices at the self-intersection points. This feature is important when |
95 | | // processing polylines with large numbers of self-intersections such as GPS |
96 | | // tracks (e.g., consider the path of a race car in the Indy 500). |
97 | | // |
98 | | // Polylines are always considered to be directed. Polyline edges between the |
99 | | // same pair of vertices are defined to intersect even if the two edges are in |
100 | | // opposite directions. (Undirected polylines can be modeled by specifying |
101 | | // GraphOptions::EdgeType::UNDIRECTED in the S2Builder output layer.) |
102 | | // |
103 | | // The output of each operation is sent to an S2Builder::Layer provided by the |
104 | | // client. This allows clients to build any representation of the geometry |
105 | | // they choose. It also allows the client to do additional postprocessing of |
106 | | // the output before building data structures; for example, the client can |
107 | | // easily discard degeneracies or convert them to another data type. |
108 | | // |
109 | | // The boundaries of polygons and polylines can be modeled as open, semi-open, |
110 | | // or closed. Polyline boundaries are controlled by the PolylineModel class, |
111 | | // whose options are as follows: |
112 | | // |
113 | | // - In the OPEN model, polylines do not contain their first or last vertex |
114 | | // except for one special case: namely, if the polyline forms a loop and |
115 | | // the polyline_loops_have_boundaries() option is set to false, then the |
116 | | // first/last vertex is contained. |
117 | | // |
118 | | // - In the SEMI_OPEN model, polylines contain all vertices except the last. |
119 | | // Therefore if one polyline starts where another polyline stops, the two |
120 | | // polylines do not intersect. |
121 | | // |
122 | | // - In the CLOSED model, polylines contain all of their vertices. |
123 | | // |
124 | | // When multiple polylines are present, they are processed independently and |
125 | | // have no effect on each other. For example, in the OPEN boundary model the |
126 | | // polyline ABC contains the vertex B, while set of polylines {AB, BC} does |
127 | | // not. (If you want to treat the polylines as a union instead, with |
128 | | // boundaries merged according to the "mod 2" rule, this can be achieved by |
129 | | // reassembling the edges into maximal polylines using S2PolylineVectorLayer |
130 | | // with EdgeType::UNDIRECTED, DuplicateEdges::MERGE, and PolylineType::WALK.) |
131 | | // |
132 | | // Polygon boundaries are controlled by the PolygonModel class, which has the |
133 | | // following options: |
134 | | // |
135 | | // - In the OPEN model, polygons do not contain their vertices or edges. |
136 | | // This implies that a polyline that follows the boundary of a polygon will |
137 | | // not intersect it. |
138 | | // |
139 | | // - In the SEMI_OPEN model, polygon point containment is defined such that |
140 | | // if several polygons tile the region around a vertex, then exactly one of |
141 | | // those polygons contains that vertex. Similarly polygons contain all of |
142 | | // their edges, but none of their reversed edges. This implies that a |
143 | | // polyline and polygon edge with the same endpoints intersect if and only |
144 | | // if they are in the same direction. (This rule ensures that if a |
145 | | // polyline is intersected with a polygon and its complement, the two |
146 | | // resulting polylines do not have any edges in common.) |
147 | | // |
148 | | // - In the CLOSED model, polygons contain all their vertices, edges, and |
149 | | // reversed edges. This implies that a polyline that shares an edge (in |
150 | | // either direction) with a polygon is defined to intersect it. Similarly, |
151 | | // this is the only model where polygons that touch at a vertex or along an |
152 | | // edge intersect. |
153 | | // |
154 | | // Note that PolylineModel and PolygonModel are defined as separate classes in |
155 | | // order to allow for possible future extensions. |
156 | | // |
157 | | // Operations between geometry of different dimensions are defined as follows: |
158 | | // |
159 | | // - For UNION, the higher-dimensional shape always wins. For example the |
160 | | // union of a closed polygon A with a polyline B that coincides with the |
161 | | // boundary of A consists only of the polygon A. |
162 | | // |
163 | | // - For INTERSECTION, the lower-dimensional shape always wins. For example, |
164 | | // the intersection of a closed polygon A with a point B that coincides |
165 | | // with a vertex of A consists only of the point B. |
166 | | // |
167 | | // - For DIFFERENCE, higher-dimensional shapes are not affected by |
168 | | // subtracting lower-dimensional shapes. For example, subtracting a point |
169 | | // or polyline from a polygon A yields the original polygon A. This rule |
170 | | // exists because in general, it is impossible to represent the output |
171 | | // using the specified boundary model(s). (Consider subtracting one vertex |
172 | | // from a PolylineModel::CLOSED polyline, or subtracting one edge from a |
173 | | // PolygonModel::CLOSED polygon.) If you want to perform operations like |
174 | | // this, consider representing all boundaries explicitly (topological |
175 | | // boundaries) using OPEN boundary models. Another option for polygons is |
176 | | // to subtract a degenerate loop, which yields a polygon with a degenerate |
177 | | // hole (see S2LaxPolygonShape). |
178 | | // |
179 | | // Note that in the case of Precision::EXACT operations, the above remarks |
180 | | // only apply to the output before snapping. Snapping may cause nearby |
181 | | // distinct edges to become coincident, e.g. a polyline may become coincident |
182 | | // with a polygon boundary. However also note that S2BooleanOperation is |
183 | | // perfectly happy to accept such geometry as input. |
184 | | // |
185 | | // Example usage: |
186 | | // S2ShapeIndex a, b; // Input geometry, e.g. containing polygons. |
187 | | // S2Polygon polygon; // Output geometry. |
188 | | // S2BooleanOperation::Options options; |
189 | | // options.set_snap_function(snap_function); |
190 | | // S2BooleanOperation op(S2BooleanOperation::OpType::INTERSECTION, |
191 | | // std::make_unique<S2PolygonLayer>(&polygon), |
192 | | // options); |
193 | | // S2Error error; |
194 | | // if (!op.Build(a, b, &error)) { |
195 | | // ABSL_LOG(ERROR) << error; |
196 | | // ... |
197 | | // } |
198 | | // |
199 | | // If the output includes objects of different dimensions, they can be |
200 | | // assembled into different layers with code like this: |
201 | | // |
202 | | // vector<S2Point> points; |
203 | | // vector<unique_ptr<S2Polyline>> polylines; |
204 | | // S2Polygon polygon; |
205 | | // S2BooleanOperation op( |
206 | | // S2BooleanOperation::OpType::UNION, |
207 | | // std::make_unique<s2builderutil::S2PointVectorLayer>(&points), |
208 | | // std::make_unique<s2builderutil::S2PolylineVectorLayer>(&polylines), |
209 | | // std::make_unique<S2PolygonLayer>(&polygon)); |
210 | | |
211 | | class S2BooleanOperation { |
212 | | public: |
213 | | // The supported operation types. |
214 | | enum class OpType : uint8_t { |
215 | | UNION, // Contained by either region. |
216 | | INTERSECTION, // Contained by both regions. |
217 | | DIFFERENCE, // Contained by the first region but not the second. |
218 | | SYMMETRIC_DIFFERENCE // Contained by one region but not the other. |
219 | | }; |
220 | | // Translates OpType to one of the strings above. |
221 | | static absl::string_view OpTypeToString(OpType op_type); |
222 | | |
223 | | // Defines whether polygons are considered to contain their vertices and/or |
224 | | // edges (see definitions above). |
225 | | enum class PolygonModel : uint8_t { OPEN, SEMI_OPEN, CLOSED }; |
226 | | |
227 | | // Translates PolygonModel to one of the strings above. |
228 | | static absl::string_view PolygonModelToString(PolygonModel model); |
229 | | |
230 | | // Defines whether polylines are considered to contain their endpoints |
231 | | // (see definitions above). |
232 | | enum class PolylineModel : uint8_t { OPEN, SEMI_OPEN, CLOSED }; |
233 | | |
234 | | // Translates PolylineModel to one of the strings above. |
235 | | static absl::string_view PolylineModelToString(PolylineModel model); |
236 | | |
237 | | // With Precision::EXACT, the operation is evaluated using the exact input |
238 | | // geometry. Predicates that use this option will produce exact results; |
239 | | // for example, they can distinguish between a polyline that barely |
240 | | // intersects a polygon from one that barely misses it. Constructive |
241 | | // operations (ones that yield new geometry, as opposed to predicates) are |
242 | | // implemented by computing the exact result and then snap rounding it |
243 | | // according to the given snap_function() (see below). This is as close as |
244 | | // it is possible to get to the exact result while requiring that vertex |
245 | | // coordinates have type "double". |
246 | | // |
247 | | // With Precision::SNAPPED, the input regions are snapped together *before* |
248 | | // the operation is evaluated. So for example, two polygons that overlap |
249 | | // slightly will be treated as though they share a common boundary, and |
250 | | // similarly two polygons that are slightly separated from each other will |
251 | | // be treated as though they share a common boundary. Snapped results are |
252 | | // useful for dealing with points, since in S2 the only points that lie |
253 | | // exactly on a polyline or polygon edge are the endpoints of that edge. |
254 | | // |
255 | | // Conceptually, the difference between these two options is that with |
256 | | // Precision::SNAPPED, the inputs are snap rounded (together), whereas with |
257 | | // Precision::EXACT only the result is snap rounded. |
258 | | enum class Precision : uint8_t { EXACT, SNAPPED }; |
259 | | |
260 | | // SourceId identifies an edge from one of the two input S2ShapeIndexes. |
261 | | // It consists of a region id (0 or 1), a shape id within that region's |
262 | | // S2ShapeIndex, and an edge id within that shape. |
263 | | class SourceId { |
264 | | public: |
265 | | SourceId(); |
266 | | SourceId(int region_id, int32_t shape_id, int32_t edge_id); |
267 | | explicit SourceId(int32_t special_edge_id); |
268 | 0 | int region_id() const { return region_id_; } |
269 | 0 | int32_t shape_id() const { return shape_id_; } |
270 | 0 | int32_t edge_id() const { return edge_id_; } |
271 | | // TODO(ericv): Convert to functions, define all 6 comparisons. |
272 | | bool operator==(SourceId other) const; |
273 | | bool operator<(SourceId other) const; |
274 | | |
275 | | private: |
276 | | // TODO(user): Use in-class initializers when C++20 is allowed in |
277 | | // opensource. |
278 | | uint32_t region_id_ : 1; |
279 | | uint32_t shape_id_ : 31; |
280 | | int32_t edge_id_; |
281 | | }; |
282 | | |
283 | | class Options { |
284 | | public: |
285 | | Options(); |
286 | | |
287 | | // Convenience constructor that calls set_snap_function(). |
288 | | explicit Options(const S2Builder::SnapFunction& snap_function); |
289 | | |
290 | | // Specifies the function to be used for snap rounding. |
291 | | // |
292 | | // DEFAULT: s2builderutil::IdentitySnapFunction(S1Angle::Zero()) |
293 | | // - This does no snapping and preserves all input vertices exactly unless |
294 | | // there are crossing edges, in which case the snap radius is increased |
295 | | // to the maximum intersection point error (S2::kIntersectionError). |
296 | | const S2Builder::SnapFunction& snap_function() const; |
297 | | void set_snap_function(const S2Builder::SnapFunction& snap_function); |
298 | | |
299 | | // Defines whether polygons are considered to contain their vertices |
300 | | // and/or edges (see comments above). |
301 | | // |
302 | | // DEFAULT: PolygonModel::SEMI_OPEN |
303 | | PolygonModel polygon_model() const; |
304 | | void set_polygon_model(PolygonModel model); |
305 | | |
306 | | // Defines whether polylines are considered to contain their vertices (see |
307 | | // comments above). |
308 | | // |
309 | | // DEFAULT: PolylineModel::CLOSED |
310 | | PolylineModel polyline_model() const; |
311 | | void set_polyline_model(PolylineModel model); |
312 | | |
313 | | // Specifies whether a polyline loop is considered to have a non-empty |
314 | | // boundary. By default this option is true, meaning that even if the |
315 | | // first and last vertices of a polyline are the same, the polyline is |
316 | | // considered to have a well-defined "start" and "end". For example, if |
317 | | // the polyline boundary model is OPEN then the polyline loop would not |
318 | | // include the start/end vertices. These are the best semantics for most |
319 | | // applications, such as GPS tracks or road network segments. |
320 | | // |
321 | | // If the polyline forms a loop and this option is set to false, then |
322 | | // instead the first and last vertices are considered to represent a |
323 | | // single vertex in the interior of the polyline. In this case the |
324 | | // boundary of the polyline is empty, meaning that the first/last vertex |
325 | | // will be contained by the polyline even if the boundary model is OPEN. |
326 | | // (Note that this option also has a small effect on the CLOSED boundary |
327 | | // model, because the first/last vertices of a polyline loop are |
328 | | // considered to represent one vertex rather than two.) |
329 | | // |
330 | | // The main reason for this option is to implement the "mod 2 union" |
331 | | // boundary semantics of the OpenGIS Simple Features spec. This can be |
332 | | // achieved by making sure that all polylines are constructed using |
333 | | // S2Builder::Graph::PolylineType::WALK (which ensures that all polylines |
334 | | // are as long as possible), and then setting this option to false. |
335 | | // |
336 | | // DEFAULT: true |
337 | | bool polyline_loops_have_boundaries() const; |
338 | | void set_polyline_loops_have_boundaries(bool value); |
339 | | |
340 | | // Specifies that a new vertex should be added whenever a polyline edge |
341 | | // crosses another polyline edge. Note that this can cause the size of |
342 | | // polylines with many self-intersections to increase quadratically. |
343 | | // |
344 | | // If false, new vertices are added only when a polyline from one input |
345 | | // region cross a polyline from the other input region. This allows |
346 | | // self-intersecting input polylines to be modified as little as possible. |
347 | | // |
348 | | // DEFAULT: false |
349 | | bool split_all_crossing_polyline_edges() const; |
350 | | void set_split_all_crossing_polyline_edges(bool value); |
351 | | |
352 | | // Specifies whether the operation should use the exact input geometry |
353 | | // (Precision::EXACT), or whether the two input regions should be snapped |
354 | | // together first (Precision::SNAPPED). |
355 | | // |
356 | | // DEFAULT: Precision::EXACT |
357 | | Precision precision() const; |
358 | | // TODO(b/78590369): Precision.SNAPPED is not yet implemented. |
359 | | // void set_precision(Precision precision); |
360 | | |
361 | | // If true, the input geometry is interpreted as representing nearby |
362 | | // geometry that has been snapped or simplified. It then outputs a |
363 | | // conservative result based on the value of polygon_model() and |
364 | | // polyline_model(). For the most part, this only affects the handling of |
365 | | // degeneracies. |
366 | | // |
367 | | // - If the model is OPEN, the result is as open as possible. For |
368 | | // example, the intersection of two identical degenerate shells is empty |
369 | | // under PolygonModel::OPEN because they could have been disjoint before |
370 | | // snapping. Similarly, two identical degenerate polylines have an |
371 | | // empty intersection under PolylineModel::OPEN. |
372 | | // |
373 | | // - If the model is CLOSED, the result is as closed as possible. In the |
374 | | // case of the DIFFERENCE operation, this is equivalent to evaluating |
375 | | // A - B as Closure(A) - Interior(B). For other operations, it affects |
376 | | // only the handling of degeneracies. For example, the union of two |
377 | | // identical degenerate holes is empty under PolygonModel::CLOSED |
378 | | // (i.e., the hole disappears) because the holes could have been |
379 | | // disjoint before snapping. |
380 | | // |
381 | | // - If the model is SEMI_OPEN, the result is as degenerate as possible. |
382 | | // New degeneracies will not be created, but all degeneracies that |
383 | | // coincide with the opposite region's boundary are retained unless this |
384 | | // would cause a duplicate polygon edge to be created. This model is |
385 | | // is very useful for working with input data that has both positive and |
386 | | // negative degeneracies (i.e., degenerate shells and holes). |
387 | | // |
388 | | // DEFAULT: false |
389 | | bool conservative_output() const; |
390 | | // TODO(b/315152896): Implement support for conservative output. |
391 | | // void set_conservative_output(bool conservative); |
392 | | |
393 | | // If specified, then each output edge will be labelled with one or more |
394 | | // SourceIds indicating which input edge(s) it corresponds to. This |
395 | | // can be useful if your input geometry has additional data that needs to |
396 | | // be propagated from the input to the output (e.g., elevations). |
397 | | // |
398 | | // You can access the labels by using an S2Builder::Layer type that |
399 | | // supports labels, such as S2PolygonLayer. The layer outputs a |
400 | | // "label_set_lexicon" and an "label_set_id" for each edge. You can then |
401 | | // look up the source information for each edge like this: |
402 | | // |
403 | | // for (int32_t label : label_set_lexicon.id_set(label_set_id)) { |
404 | | // const SourceId& src = source_id_lexicon.value(label); |
405 | | // // region_id() specifies which S2ShapeIndex the edge is from (0 or 1). |
406 | | // DoSomething(src.region_id(), src.shape_id(), src.edge_id()); |
407 | | // } |
408 | | // |
409 | | // DEFAULT: nullptr |
410 | | ValueLexicon<SourceId>* source_id_lexicon() const; |
411 | | // TODO(b/314819022): Implement support for source_id_lexicon. |
412 | | // void set_source_id_lexicon(ValueLexicon<SourceId>* source_id_lexicon); |
413 | | |
414 | | // Specifies that internal memory usage should be tracked using the given |
415 | | // S2MemoryTracker. If a memory limit is specified and more more memory |
416 | | // than this is required then an error will be returned. Example usage: |
417 | | // |
418 | | // S2MemoryTracker tracker; |
419 | | // tracker.set_limit(500 << 20); // 500 MB |
420 | | // S2BooleanOperation::Options options; |
421 | | // options.set_memory_tracker(&tracker); |
422 | | // S2BooleanOperation op(..., options); |
423 | | // ... |
424 | | // S2Error error; |
425 | | // if (!op.Build(..., &error)) { |
426 | | // if (error.code() == S2Error::RESOURCE_EXHAUSTED) { |
427 | | // ABSL_LOG(ERROR) << error; // Memory limit exceeded |
428 | | // } |
429 | | // } |
430 | | // |
431 | | // CAVEATS: |
432 | | // |
433 | | // - Memory used by the input S2ShapeIndexes and the output S2Builder |
434 | | // layers is not counted towards the total. |
435 | | // |
436 | | // - While memory tracking is reasonably complete and accurate, it does |
437 | | // not account for every last byte. It is intended only for the |
438 | | // purpose of preventing clients from running out of memory. |
439 | | // |
440 | | // DEFAULT: nullptr (memory tracking disabled) |
441 | | S2MemoryTracker* memory_tracker() const; |
442 | | void set_memory_tracker(S2MemoryTracker* tracker); |
443 | | |
444 | | // Options may be assigned and copied. |
445 | | Options(const Options& options); |
446 | | Options& operator=(const Options& options); |
447 | | |
448 | | private: |
449 | | std::unique_ptr<S2Builder::SnapFunction> snap_function_; |
450 | | PolygonModel polygon_model_ = PolygonModel::SEMI_OPEN; |
451 | | PolylineModel polyline_model_ = PolylineModel::CLOSED; |
452 | | bool polyline_loops_have_boundaries_ = true; |
453 | | bool split_all_crossing_polyline_edges_ = false; |
454 | | Precision precision_ = Precision::EXACT; |
455 | | bool conservative_output_ = false; |
456 | | ValueLexicon<SourceId>* source_id_lexicon_ = nullptr; |
457 | | S2MemoryTracker* memory_tracker_ = nullptr; |
458 | | }; |
459 | | |
460 | | #ifndef SWIG |
461 | | // Specifies that the output boundary edges should be sent to a single |
462 | | // S2Builder layer. This version can be used when the dimension of the |
463 | | // output geometry is known (e.g., intersecting two polygons to yield a |
464 | | // third polygon). |
465 | | S2BooleanOperation(OpType op_type, |
466 | | std::unique_ptr<S2Builder::Layer> layer, |
467 | | const Options& options = Options()); |
468 | | |
469 | | // Specifies that the output boundary edges should be sent to three |
470 | | // different layers according to their dimension. Points (represented by |
471 | | // degenerate edges) are sent to layer 0, polyline edges are sent to |
472 | | // layer 1, and polygon edges are sent to layer 2. |
473 | | // |
474 | | // The dimension of an edge is defined as the minimum dimension of the two |
475 | | // input edges that produced it. For example, the intersection of two |
476 | | // crossing polyline edges is a considered to be a degenerate polyline |
477 | | // rather than a point, so it is sent to layer 1. Clients can easily |
478 | | // reclassify such polylines as points if desired, but this rule makes it |
479 | | // easier for clients that want to process point, polyline, and polygon |
480 | | // inputs differently. |
481 | | // |
482 | | // The layers are always built in the order 0, 1, 2, and all arguments to |
483 | | // the Build() calls are guaranteed to be valid until the last call returns. |
484 | | // All Graph objects have the same set of vertices and the same lexicon |
485 | | // objects, in order to make it easier to write classes that process all the |
486 | | // edges in parallel. |
487 | | S2BooleanOperation(OpType op_type, |
488 | | std::vector<std::unique_ptr<S2Builder::Layer>> layers, |
489 | | const Options& options = Options()); |
490 | | #endif |
491 | | |
492 | 0 | OpType op_type() const { return op_type_; } |
493 | 0 | const Options& options() const { return options_; } |
494 | | |
495 | | // Executes the given operation. Returns true on success, and otherwise |
496 | | // sets "error" appropriately. (This class does not generate any errors |
497 | | // itself, but the S2Builder::Layer might.) |
498 | | bool Build(const S2ShapeIndex& a, const S2ShapeIndex& b, |
499 | | S2Error* absl_nonnull error); |
500 | | |
501 | | // Convenience method that returns true if the result of the given operation |
502 | | // is empty. |
503 | | static bool IsEmpty(OpType op_type, |
504 | | const S2ShapeIndex& a, const S2ShapeIndex& b, |
505 | | const Options& options = Options()); |
506 | | |
507 | | // Convenience method that returns true if A intersects B. |
508 | | static bool Intersects(const S2ShapeIndex& a, const S2ShapeIndex& b, |
509 | 0 | const Options& options = Options()) { |
510 | 0 | return !IsEmpty(OpType::INTERSECTION, b, a, options); |
511 | 0 | } |
512 | | |
513 | | // Convenience method that returns true if A contains B, i.e., if the |
514 | | // difference (B - A) is empty. |
515 | | static bool Contains(const S2ShapeIndex& a, const S2ShapeIndex& b, |
516 | 0 | const Options& options = Options()) { |
517 | 0 | return IsEmpty(OpType::DIFFERENCE, b, a, options); |
518 | 0 | } |
519 | | |
520 | | // Convenience method that returns true if the symmetric difference of A and |
521 | | // B is empty. (Note that A and B may still not be identical, e.g. A may |
522 | | // contain two copies of a polyline while B contains one.) |
523 | | static bool Equals(const S2ShapeIndex& a, const S2ShapeIndex& b, |
524 | 0 | const Options& options = Options()) { |
525 | 0 | return IsEmpty(OpType::SYMMETRIC_DIFFERENCE, b, a, options); |
526 | 0 | } |
527 | | |
528 | | private: |
529 | | class Impl; // The actual implementation. |
530 | | |
531 | | // Internal constructor to reduce code duplication. |
532 | | S2BooleanOperation(OpType op_type, const Options& options); |
533 | | |
534 | | // Specifies that "result_empty" should be set to indicate whether the exact |
535 | | // result of the operation is empty. This constructor is used to efficiently |
536 | | // test boolean relationships (see IsEmpty above). |
537 | | S2BooleanOperation(OpType op_type, bool* result_empty, |
538 | | const Options& options = Options()); |
539 | | |
540 | | Options options_; |
541 | | OpType op_type_; |
542 | | |
543 | | // The input regions. |
544 | | const S2ShapeIndex* regions_[2]; |
545 | | |
546 | | // The output consists either of zero layers, one layer, or three layers. |
547 | | std::vector<std::unique_ptr<S2Builder::Layer>> layers_; |
548 | | |
549 | | // The following field is set if and only if there are no output layers. |
550 | | bool* result_empty_ = nullptr; |
551 | | }; |
552 | | |
553 | | |
554 | | ////////////////// Implementation details follow //////////////////// |
555 | | |
556 | | |
557 | | inline S2BooleanOperation::SourceId::SourceId() |
558 | | : region_id_(0), shape_id_(0), edge_id_(-1) { |
559 | | } |
560 | | |
561 | | inline S2BooleanOperation::SourceId::SourceId(int region_id, int32_t shape_id, |
562 | | int32_t edge_id) |
563 | 0 | : region_id_(region_id), shape_id_(shape_id), edge_id_(edge_id) {} |
564 | | |
565 | | inline S2BooleanOperation::SourceId::SourceId(int special_edge_id) |
566 | 0 | : region_id_(0), shape_id_(0), edge_id_(special_edge_id) { |
567 | 0 | } |
568 | | |
569 | 0 | inline bool S2BooleanOperation::SourceId::operator==(SourceId other) const { |
570 | 0 | return (region_id_ == other.region_id_ && |
571 | 0 | shape_id_ == other.shape_id_ && |
572 | 0 | edge_id_ == other.edge_id_); |
573 | 0 | } |
574 | | |
575 | 0 | inline bool S2BooleanOperation::SourceId::operator<(SourceId other) const { |
576 | 0 | if (region_id_ < other.region_id_) return true; |
577 | 0 | if (region_id_ > other.region_id_) return false; |
578 | 0 | if (shape_id_ < other.shape_id_) return true; |
579 | 0 | if (shape_id_ > other.shape_id_) return false; |
580 | 0 | return edge_id_ < other.edge_id_; |
581 | 0 | } |
582 | | |
583 | | #endif // S2_S2BOOLEAN_OPERATION_H_ |