1 | // Copyright 2006 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2POLYGONBUILDER_H__ |
4 | #define UTIL_GEOMETRY_S2POLYGONBUILDER_H__ |
5 | |
6 | #include <hash_map> |
7 | using __gnu_cxx::hash_map; |
8 | |
9 | #include <set> |
10 | using std::set; |
11 | using std::multiset; |
12 | |
13 | #include <utility> |
14 | using std::pair; |
15 | using std::make_pair; |
16 | |
17 | #include <vector> |
18 | using std::vector; |
19 | |
20 | #include "base/basictypes.h" |
21 | #include "base/scoped_ptr.h" |
22 | #include "s2.h" |
23 | #include "s1angle.h" |
24 | #include "util/math/matrix3x3.h" |
25 | |
26 | class S2Loop; |
27 | class S2Polygon; |
28 | |
29 | // This is a simple class for assembling polygons out of edges. It requires |
30 | // that no two edges cross. It can handle both directed and undirected edges, |
31 | // and optionally it can also remove duplicate edge pairs (consisting of two |
32 | // identical edges or an edge and its reverse edge). This is useful for |
33 | // computing seamless unions of polygons that have been cut into pieces. |
34 | // |
35 | // Here are some of the situations this class was designed to handle: |
36 | // |
37 | // 1. Computing the union of disjoint polygons that may share part of their |
38 | // boundaries. For example, reassembling a lake that has been split into |
39 | // two loops by a state boundary. |
40 | // |
41 | // 2. Constructing polygons from input data that does not follow S2 |
42 | // conventions, i.e. where loops may have repeated vertices, or distinct |
43 | // loops may share edges, or shells and holes have opposite or unspecified |
44 | // orientations. |
45 | // |
46 | // 3. Computing the symmetric difference of a set of polygons whose edges |
47 | // intersect only at vertices. This can be used to implement a limited |
48 | // form of polygon intersection or subtraction as well as unions. |
49 | // |
50 | // 4. As a tool for implementing other polygon operations by generating a |
51 | // collection of directed edges and then assembling them into loops. |
52 | class S2PolygonBuilderOptions { |
53 | public: |
54 | S2PolygonBuilderOptions() : |
55 | undirected_edges_(false), xor_edges_(true), validate_(false), |
56 | vertex_merge_radius_(S1Angle::Radians(0)), |
57 | edge_splice_fraction_(0.866) {} |
58 | |
59 | // These are the options that should be used for assembling well-behaved |
60 | // input data into polygons. All edges should be directed such that |
61 | // "shells" and "holes" have opposite orientations (typically CCW shells and |
62 | // clockwise holes), unless it is known that shells and holes do not share |
63 | // any edges. |
64 | inline static S2PolygonBuilderOptions DIRECTED_XOR(); |
65 | |
66 | // These are the options that should be used for assembling polygons that do |
67 | // not follow the conventions above, e.g. where edge directions may vary |
68 | // within a single loop, or shells and holes are not oppositely oriented and |
69 | // may share edges. |
70 | inline static S2PolygonBuilderOptions UNDIRECTED_XOR(); |
71 | |
72 | // These are the options that should be used for assembling edges where the |
73 | // desired output is a collection of loops rather than a polygon, and edges |
74 | // may occur more than once. Edges are treated as undirected and are not |
75 | // XORed together. |
76 | inline static S2PolygonBuilderOptions UNDIRECTED_UNION(); |
77 | |
78 | // Default value: false. |
79 | // |
80 | // If "undirected_edges" is false, then the input is assumed to consist of |
81 | // edges that can be assembled into oriented loops without reversing any of |
82 | // the edges. Otherwise, "undirected_edges" should be set to true. |
83 | bool undirected_edges() const { return undirected_edges_; } |
84 | void set_undirected_edges(bool undirected_edges); |
85 | |
86 | // Default value: true. |
87 | // |
88 | // If "xor_edges" is true, then any duplicate edge pairs are removed. This |
89 | // is useful for computing the union of a collection of polygons whose |
90 | // interiors are disjoint but whose boundaries may share some common edges |
91 | // (e.g. computing the union of South Africa, Lesotho, and Swaziland). |
92 | // |
93 | // Note that for directed edges, a "duplicate edge pair" consists of an edge |
94 | // and its corresponding reverse edge. This means that either (a) "shells" |
95 | // and "holes" must have opposite orientations, or (b) shells and holes do |
96 | // not share edges. Otherwise undirected_edges() should be specified. |
97 | // |
98 | // There are only two reasons to turn off xor_edges(): |
99 | // |
100 | // (1) AssemblePolygon() will be called, and you want to assert that there |
101 | // are no duplicate edge pairs in the input. |
102 | // |
103 | // (2) AssembleLoops() will be called, and you want to keep abutting loops |
104 | // separate in the output rather than merging their regions together |
105 | // (e.g. assembling loops for Kansas City, KS and Kansas City, MO |
106 | // simultaneously). |
107 | bool xor_edges() const { return xor_edges_; } |
108 | void set_xor_edges(bool xor_edges); |
109 | |
110 | // Default value: false. |
111 | // |
112 | // If true, IsValid() is called on all loops and polygons before |
113 | // constructing them. If any loop is invalid (e.g. self-intersecting), it |
114 | // is rejected and returned as a set of "unused edges". Any remaining valid |
115 | // loops are kept. If the entire polygon is invalid (e.g. two loops |
116 | // intersect), then all loops are rejected and returned as unused edges. |
117 | bool validate() const { return validate_; } |
118 | void set_validate(bool validate); |
119 | |
120 | // Default value: 0. |
121 | // |
122 | // If set to a positive value, all vertex pairs that are separated by less |
123 | // than this distance will be merged together. Note that vertices can move |
124 | // arbitrarily far if there is a long chain of vertices separated by less |
125 | // than this distance. |
126 | // |
127 | // This method is useful for assembling polygons out of input data where |
128 | // vertices and/or edges may not be perfectly aligned. |
129 | S1Angle vertex_merge_radius() const { return vertex_merge_radius_; } |
130 | void set_vertex_merge_radius(S1Angle const& vertex_merge_radius); |
131 | |
132 | // Default value: 0.866 (approximately sqrt(3)/2). |
133 | // |
134 | // The edge splice radius is automatically set to this fraction of the vertex |
135 | // merge radius. If the edge splice radius is positive, then all vertices |
136 | // that are closer than this distance to an edge are spliced into that edge. |
137 | // Note that edges can move arbitrarily far if there is a long chain of |
138 | // vertices in just the right places. |
139 | // |
140 | // You can turn off edge splicing by setting this value to zero. This will |
141 | // save some time if you don't need this feature, or you don't want vertices |
142 | // to be spliced into nearby edges for some reason. |
143 | // |
144 | // Note that the edge splice fraction must be less than sqrt(3)/2 in order to |
145 | // avoid infinite loops in the merge algorithm. The default value is very |
146 | // close to this maximum and therefore results in the maximum amount of edge |
147 | // splicing for a given vertex merge radius. |
148 | // |
149 | // The only reason to reduce the edge splice fraction is if you want to limit |
150 | // changes in edge direction due to splicing. The direction of an edge can |
151 | // change by up to asin(edge_splice_fraction) due to each splice. Thus by |
152 | // default, edges are allowed to change direction by up to 60 degrees per |
153 | // splice. However, note that most direction changes are much smaller than |
154 | // this: the worst case occurs only if the vertex being spliced is just |
155 | // outside the vertex merge radius from one of the edge endpoints. |
156 | double edge_splice_fraction() const { return edge_splice_fraction_; } |
157 | void set_edge_splice_fraction(double edge_splice_fraction); |
158 | |
159 | private: |
160 | bool undirected_edges_; |
161 | bool xor_edges_; |
162 | bool validate_; |
163 | S1Angle vertex_merge_radius_; |
164 | double edge_splice_fraction_; |
165 | }; |
166 | |
167 | class S2PolygonBuilder { |
168 | public: |
169 | explicit S2PolygonBuilder(S2PolygonBuilderOptions const& options); |
170 | ~S2PolygonBuilder(); |
171 | |
172 | S2PolygonBuilderOptions const& options() const { return options_; } |
173 | |
174 | // Add the given edge to the polygon builder. This method should be used |
175 | // for input data that may not follow S2 polygon conventions. Note that |
176 | // edges are not allowed to cross each other. Also note that as a |
177 | // convenience, edges where v0 == v1 are ignored. |
178 | // |
179 | // Returns true if an edge was added, and false if an edge was erased |
180 | // (due to XORing) or not added (if both endpoints were the same). |
181 | bool AddEdge(S2Point const& v0, S2Point const& v1); |
182 | |
183 | // Add all edges in the given loop. If the sign() of the loop is negative |
184 | // (i.e. this loop represents a hole), the reverse edges are added instead. |
185 | // This implies that "shells" are CCW and "holes" are CW, as required for |
186 | // the directed edges convention described above. |
187 | // |
188 | // This method does not take ownership of the loop. |
189 | void AddLoop(S2Loop const* loop); |
190 | |
191 | // Add all loops in the given polygon. Shells and holes are added with |
192 | // opposite orientations as described for AddLoop(). |
193 | // |
194 | // This method does not take ownership of the polygon. |
195 | void AddPolygon(S2Polygon const* polygon); |
196 | |
197 | // This type is used to return any edges that could not be assembled. |
198 | typedef vector<pair<S2Point, S2Point> > EdgeList; |
199 | |
200 | // Assembles the given edges into as many non-crossing loops as possible. |
201 | // When there is a choice about how to assemble the loops, then CCW loops |
202 | // are preferred. Returns true if all edges were assembled. If |
203 | // "unused_edges" is not NULL, it is initialized to the set of edges that |
204 | // could not be assembled into loops. |
205 | // |
206 | // Note that if xor_edges() is false and duplicate edge pairs may be |
207 | // present, then undirected_edges() should be specified unless all loops can |
208 | // be assembled in a counter-clockwise direction. Otherwise this method may |
209 | // not be able to assemble all loops due to its preference for CCW loops. |
210 | // |
211 | // This method resets the S2PolygonBuilder state so that it can be reused. |
212 | bool AssembleLoops(vector<S2Loop*>* loops, EdgeList* unused_edges); |
213 | |
214 | // Like AssembleLoops, but normalizes all the loops so that they enclose |
215 | // less than half the sphere, and then assembles the loops into a polygon. |
216 | // |
217 | // For this method to succeed, there should be no duplicate edges in the |
218 | // input. If this is not known to be true, then the "xor_edges" option |
219 | // should be set (which is true by default). |
220 | // |
221 | // Note that S2Polygons cannot represent arbitrary regions on the sphere, |
222 | // because of the limitation that no loop encloses more than half of the |
223 | // sphere. For example, an S2Polygon cannot represent a 100km wide band |
224 | // around the equator. In such cases, this method will return the |
225 | // *complement* of the expected region. So for example if all the world's |
226 | // coastlines were assembled, the output S2Polygon would represent the land |
227 | // area (irrespective of the input edge or loop orientations). |
228 | bool AssemblePolygon(S2Polygon* polygon, EdgeList* unused_edges); |
229 | |
230 | // This function is only for debugging. If it is called, then points will |
231 | // be transformed by the inverse of the given matrix before being printed as |
232 | // lat-lng coordinates in degrees. "m" should be orthonormal. |
233 | void set_debug_matrix(Matrix3x3_d const& m); |
234 | |
235 | protected: |
236 | // These functions print either a single vertex, all edges from a single |
237 | // vertex, or all edges in the builder. |
238 | void DumpVertex(S2Point const& v) const; |
239 | void DumpEdges(S2Point const& v0) const; |
240 | void Dump() const; |
241 | |
242 | private: |
243 | |
244 | // Return true if the given edge exists. |
245 | bool HasEdge(S2Point const& v0, S2Point const& v1); |
246 | |
247 | // Erase an edge or an entire loop. The edge/loop must exist. |
248 | void EraseEdge(S2Point const& v0, S2Point const& v1); |
249 | void EraseLoop(S2Point const* v, int n); |
250 | |
251 | // Assembles and returns a single loop starting with the given edge. |
252 | // If a loop cannot be assembled starting from this edge, returns NULL |
253 | // and updates "unused_edges". |
254 | S2Loop* AssembleLoop(S2Point const& v0, S2Point const& v1, |
255 | EdgeList* unused_edges); |
256 | |
257 | // Adds all the given edges to "unused_edges". |
258 | void RejectLoop(S2Point const* v, int n, EdgeList* unused_edges); |
259 | |
260 | // Builds a map indicating which vertices need to be moved from their |
261 | // current position to a new position, and also returns a spatial index |
262 | // containing all of the vertices that do not need to be moved. |
263 | class PointIndex; |
264 | typedef hash_map<S2Point, S2Point> MergeMap; |
265 | void BuildMergeMap(PointIndex* index, MergeMap* merge_map); |
266 | |
267 | // Moves a set of vertices from old to new positions. |
268 | void MoveVertices(MergeMap const& merge_map); |
269 | |
270 | // Modifies each edge by splicing in any vertices whose distance to the edge |
271 | // is at most (edge_splice_fraction() * vertex_merge_radius()). |
272 | void SpliceEdges(PointIndex* index); |
273 | |
274 | S2PolygonBuilderOptions options_; |
275 | |
276 | // This is only used for debugging purposes. |
277 | scoped_ptr<Matrix3x3_d> debug_matrix_; |
278 | |
279 | // The current set of edges, grouped by origin. The set of destination |
280 | // vertices is a multiset so that the same edge can be present more than |
281 | // once. We could have also used a multiset<pair<S2Point, S2Point> >, |
282 | // but this representation is a bit more convenient. |
283 | typedef multiset<S2Point> VertexSet; |
284 | typedef hash_map<S2Point, VertexSet> EdgeSet; |
285 | scoped_ptr<EdgeSet> edges_; |
286 | |
287 | // Unique collection of the starting (first) vertex of all edges, |
288 | // in the order they are added to edges_. |
289 | vector<S2Point> starting_vertices_; |
290 | }; |
291 | |
292 | inline S2PolygonBuilderOptions S2PolygonBuilderOptions::DIRECTED_XOR() { |
293 | return S2PolygonBuilderOptions(); |
294 | } |
295 | |
296 | inline S2PolygonBuilderOptions S2PolygonBuilderOptions::UNDIRECTED_XOR() { |
297 | S2PolygonBuilderOptions options; |
298 | options.set_undirected_edges(true); |
299 | return options; |
300 | } |
301 | |
302 | inline S2PolygonBuilderOptions S2PolygonBuilderOptions::UNDIRECTED_UNION() { |
303 | S2PolygonBuilderOptions options; |
304 | options.set_undirected_edges(true); |
305 | options.set_xor_edges(false); |
306 | return options; |
307 | } |
308 | |
309 | #endif // UTIL_GEOMETRY_S2POLYGONBUILDER_H__ |
310 | |