1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2LOOP_H__ |
4 | #define UTIL_GEOMETRY_S2LOOP_H__ |
5 | |
6 | #include <map> |
7 | using std::map; |
8 | using std::multimap; |
9 | |
10 | #include <vector> |
11 | using std::vector; |
12 | |
13 | |
14 | #include "base/logging.h" |
15 | #include "base/macros.h" |
16 | #include "s2edgeindex.h" |
17 | #include "s2region.h" |
18 | #include "s2latlngrect.h" |
19 | #include "s2edgeutil.h" |
20 | |
21 | class S2Loop; |
22 | // Defined in the cc file. A helper class for AreBoundariesCrossing. |
23 | class WedgeProcessor; |
24 | |
25 | // Indexing structure to efficiently compute intersections. |
26 | class S2LoopIndex: public S2EdgeIndex { |
27 | public: |
28 | explicit S2LoopIndex(S2Loop const* loop): loop_(loop) {} |
29 | virtual ~S2LoopIndex() {} |
30 | |
31 | // There is no need to overwrite Reset(), as the only data that's |
32 | // used to implement this class is all contained in the loop data. |
33 | // void Reset(); |
34 | |
35 | virtual S2Point const* edge_from(int index) const; |
36 | virtual S2Point const* edge_to(int index) const; |
37 | virtual int num_edges() const; |
38 | |
39 | private: |
40 | S2Loop const* loop_; |
41 | }; |
42 | |
43 | // An S2Loop represents a simple spherical polygon. It consists of a single |
44 | // chain of vertices where the first vertex is implicitly connected to the |
45 | // last. All loops are defined to have a CCW orientation, i.e. the interior |
46 | // of the polygon is on the left side of the edges. This implies that a |
47 | // clockwise loop enclosing a small area is interpreted to be a CCW loop |
48 | // enclosing a very large area. |
49 | // |
50 | // Loops are not allowed to have any duplicate vertices (whether adjacent or |
51 | // not), and non-adjacent edges are not allowed to intersect. Loops must have |
52 | // at least 3 vertices. Although these restrictions are not enforced in |
53 | // optimized code, you may get unexpected results if they are violated. |
54 | // |
55 | // Point containment is defined such that if the sphere is subdivided into |
56 | // faces (loops), every point is contained by exactly one face. This implies |
57 | // that loops do not necessarily contain all (or any) of their vertices. |
58 | // |
59 | // TODO(user): When doing operations on two loops, always create the |
60 | // edgeindex for the bigger of the two. Same for polygons. |
61 | class S2Loop : public S2Region { |
62 | public: |
63 | // Create an empty S2Loop that should be initialized by calling Init() or |
64 | // Decode(). |
65 | S2Loop(); |
66 | |
67 | // Convenience constructor that calls Init() with the given vertices. |
68 | explicit S2Loop(vector<S2Point> const& vertices); |
69 | |
70 | // Initialize a loop connecting the given vertices. The last vertex is |
71 | // implicitly connected to the first. All points should be unit length. |
72 | // Loops must have at least 3 vertices. |
73 | void Init(vector<S2Point> const& vertices); |
74 | |
75 | // This parameter should be removed as soon as people stop using the |
76 | // deprecated version of IsValid. |
77 | static int const kDefaultMaxAdjacent = 0; |
78 | |
79 | // Check whether this loop is valid. Note that in debug mode, validity |
80 | // is checked at loop creation time, so IsValid() |
81 | // should always return true. |
82 | bool IsValid() const; |
83 | |
84 | |
85 | // These two versions are deprecated and ignore max_adjacent. |
86 | // DEPRECATED. |
87 | static bool IsValid(vector<S2Point> const& vertices, int max_adjacent); |
88 | // DEPRECATED. |
89 | bool IsValid(int max_adjacent) const; |
90 | |
91 | // Initialize a loop corresponding to the given cell. |
92 | explicit S2Loop(S2Cell const& cell); |
93 | |
94 | ~S2Loop(); |
95 | |
96 | // The depth of a loop is defined as its nesting level within its containing |
97 | // polygon. "Outer shell" loops have depth 0, holes within those loops have |
98 | // depth 1, shells within those holes have depth 2, etc. This field is only |
99 | // used by the S2Polygon implementation. |
100 | int depth() const { return depth_; } |
101 | void set_depth(int depth) { depth_ = depth; } |
102 | |
103 | // Return true if this loop represents a hole in its containing polygon. |
104 | bool is_hole() const { return (depth_ & 1) != 0; } |
105 | |
106 | // The sign of a loop is -1 if the loop represents a hole in its containing |
107 | // polygon, and +1 otherwise. |
108 | int sign() const { return is_hole() ? -1 : 1; } |
109 | |
110 | int num_vertices() const { return num_vertices_; } |
111 | |
112 | // For convenience, we make two entire copies of the vertex list available: |
113 | // vertex(n..2*n-1) is mapped to vertex(0..n-1), where n == num_vertices(). |
114 | S2Point const& vertex(int i) const { |
115 | DCHECK_GE(i, 0); |
116 | DCHECK_LT(i, (2 * num_vertices_)); |
117 | int j = i - num_vertices(); |
118 | return vertices_[j >= 0 ? j : i]; |
119 | } |
120 | |
121 | // Return true if the loop area is at most 2*Pi. Degenerate loops are |
122 | // handled consistently with S2::RobustCCW(), i.e., if a loop can be |
123 | // expressed as the union of degenerate or nearly-degenerate CCW triangles, |
124 | // then it will always be considered normalized. |
125 | bool IsNormalized() const; |
126 | |
127 | // Invert the loop if necessary so that the area enclosed by the loop is at |
128 | // most 2*Pi. |
129 | void Normalize(); |
130 | |
131 | // Reverse the order of the loop vertices, effectively complementing |
132 | // the region represented by the loop. |
133 | void Invert(); |
134 | |
135 | // Return the area of the loop interior, i.e. the region on the left side of |
136 | // the loop. The return value is between 0 and 4*Pi. (Note that the return |
137 | // value is not affected by whether this loop is a "hole" or a "shell".) |
138 | double GetArea() const; |
139 | |
140 | // Return the true centroid of the loop multiplied by the area of the loop |
141 | // (see s2.h for details on centroids). The result is not unit length, so |
142 | // you may want to normalize it. Also note that in general, the centroid |
143 | // may not be contained by the loop. |
144 | // |
145 | // We prescale by the loop area for two reasons: (1) it is cheaper to |
146 | // compute this way, and (2) it makes it easier to compute the centroid of |
147 | // more complicated shapes (by splitting them into disjoint regions and |
148 | // adding their centroids). |
149 | // |
150 | // Note that the return value is not affected by whether this loop is a |
151 | // "hole" or a "shell". |
152 | S2Point GetCentroid() const; |
153 | |
154 | // Return the sum of the turning angles at each vertex. The return value is |
155 | // positive if the loop is counter-clockwise, negative if the loop is |
156 | // clockwise, and zero if the loop is a great circle. Degenerate and |
157 | // nearly-degenerate loops are handled consistently with S2::RobustCCW(). |
158 | // So for example, if a loop has zero area (i.e., it is a very small CCW |
159 | // loop) then the turning angle will always be negative. |
160 | // |
161 | // This quantity is also called the "geodesic curvature" of the loop. |
162 | double GetTurningAngle() const; |
163 | |
164 | // Return true if the region contained by this loop is a superset of the |
165 | // region contained by the given other loop. |
166 | bool Contains(S2Loop const* b) const; |
167 | |
168 | // Return true if the region contained by this loop intersects the region |
169 | // contained by the given other loop. |
170 | bool Intersects(S2Loop const* b) const; |
171 | |
172 | // Given two loops of a polygon (see s2polygon.h for requirements), return |
173 | // true if A contains B. This version of Contains() is much cheaper since |
174 | // it does not need to check whether the boundaries of the two loops cross. |
175 | bool ContainsNested(S2Loop const* b) const; |
176 | |
177 | // Return +1 if A contains B (i.e. the interior of B is a subset of the |
178 | // interior of A), -1 if the boundaries of A and B cross, and 0 otherwise. |
179 | // Requires that A does not properly contain the complement of B, i.e. |
180 | // A and B do not contain each other's boundaries. This method is used |
181 | // for testing whether multi-loop polygons contain each other. |
182 | // |
183 | // WARNING: there is a bug in this function - it does not detect loop |
184 | // crossings in certain situations involving shared edges. CL 2926852 works |
185 | // around this bug for polygon intersection, but it probably effects other |
186 | // tests. TODO: fix ContainsOrCrosses() and revert CL 2926852. |
187 | int ContainsOrCrosses(S2Loop const* b) const; |
188 | |
189 | // Return true if two loops have the same boundary. This is true if and |
190 | // only if the loops have the same vertices in the same cyclic order. |
191 | // (For testing purposes.) |
192 | bool BoundaryEquals(S2Loop const* b) const; |
193 | |
194 | // Return true if two loops have the same boundary except for vertex |
195 | // perturbations. More precisely, the vertices in the two loops must be in |
196 | // the same cyclic order, and corresponding vertex pairs must be separated |
197 | // by no more than "max_error". (For testing purposes.) |
198 | bool BoundaryApproxEquals(S2Loop const* b, double max_error = 1e-15) const; |
199 | |
200 | // Return true if the two loop boundaries are within "max_error" of each |
201 | // other along their entire lengths. The two loops may have different |
202 | // numbers of vertices. More precisely, this method returns true if the two |
203 | // loops have parameterizations a:[0,1] -> S^2, b:[0,1] -> S^2 such that |
204 | // distance(a(t), b(t)) <= max_error for all t. You can think of this as |
205 | // testing whether it is possible to drive two cars all the way around the |
206 | // two loops such that no car ever goes backward and the cars are always |
207 | // within "max_error" of each other. (For testing purposes.) |
208 | bool BoundaryNear(S2Loop const* b, double max_error = 1e-15) const; |
209 | |
210 | // This method computes the oriented surface integral of some quantity f(x) |
211 | // over the loop interior, given a function f_tri(A,B,C) that returns the |
212 | // corresponding integral over the spherical triangle ABC. Here "oriented |
213 | // surface integral" means: |
214 | // |
215 | // (1) f_tri(A,B,C) must be the integral of f if ABC is counterclockwise, |
216 | // and the integral of -f if ABC is clockwise. |
217 | // |
218 | // (2) The result of this function is *either* the integral of f over the |
219 | // loop interior, or the integral of (-f) over the loop exterior. |
220 | // |
221 | // Note that there are at least two common situations where it easy to work |
222 | // around property (2) above: |
223 | // |
224 | // - If the integral of f over the entire sphere is zero, then it doesn't |
225 | // matter which case is returned because they are always equal. |
226 | // |
227 | // - If f is non-negative, then it is easy to detect when the integral over |
228 | // the loop exterior has been returned, and the integral over the loop |
229 | // interior can be obtained by adding the integral of f over the entire |
230 | // unit sphere (a constant) to the result. |
231 | // |
232 | // Also requires that the default constructor for T must initialize the |
233 | // value to zero. (This is true for built-in types such as "double".) |
234 | template <class T> |
235 | T GetSurfaceIntegral(T f_tri(S2Point const&, S2Point const&, S2Point const&)) |
236 | const; |
237 | |
238 | //////////////////////////////////////////////////////////////////////// |
239 | // S2Region interface (see s2region.h for details): |
240 | |
241 | // GetRectBound() is guaranteed to return exact results, while GetCapBound() |
242 | // is conservative. |
243 | virtual S2Loop* Clone() const; |
244 | virtual S2Cap GetCapBound() const; |
245 | virtual S2LatLngRect GetRectBound() const { return bound_; } |
246 | |
247 | virtual bool Contains(S2Cell const& cell) const; |
248 | virtual bool MayIntersect(S2Cell const& cell) const; |
249 | virtual bool VirtualContainsPoint(S2Point const& p) const { |
250 | return Contains(p); // The same as Contains() below, just virtual. |
251 | } |
252 | |
253 | // The point 'p' does not need to be normalized. |
254 | bool Contains(S2Point const& p) const; |
255 | |
256 | virtual void Encode(Encoder* const encoder) const; |
257 | virtual bool Decode(Decoder* const decoder); |
258 | virtual bool DecodeWithinScope(Decoder* const decoder); |
259 | |
260 | private: |
261 | // Internal constructor used only by Clone() that makes a deep copy of |
262 | // its argument. |
263 | explicit S2Loop(S2Loop const* src); |
264 | |
265 | void InitOrigin(); |
266 | void InitBound(); |
267 | |
268 | // Internal implementation of the Decode and DecodeWithinScope methods above. |
269 | // If within_scope is true, memory is allocated for vertices_ and data |
270 | // is copied from the decoder using memcpy. If it is false, vertices_ |
271 | // will point to the memory area inside the decoder, and the field |
272 | // owns_vertices_ is set to false. |
273 | bool DecodeInternal(Decoder* const decoder, |
274 | bool within_scope); |
275 | |
276 | // Internal implementation of the Intersects() method above. |
277 | bool IntersectsInternal(S2Loop const* b) const; |
278 | |
279 | // Return an index "first" and a direction "dir" (either +1 or -1) such that |
280 | // the vertex sequence (first, first+dir, ..., first+(n-1)*dir) does not |
281 | // change when the loop vertex order is rotated or inverted. This allows |
282 | // the loop vertices to be traversed in a canonical order. The return |
283 | // values are chosen such that (first, ..., first+n*dir) are in the range |
284 | // [0, 2*n-1] as expected by the vertex() method. |
285 | int GetCanonicalFirstVertex(int* dir) const; |
286 | |
287 | // Return the index of a vertex at point "p", or -1 if not found. |
288 | // The return value is in the range 1..num_vertices_ if found. |
289 | int FindVertex(S2Point const& p) const; |
290 | |
291 | // This method checks all edges of this loop (A) for intersection |
292 | // against all edges of B. If there is any shared vertex , the |
293 | // wedges centered at this vertex are sent to wedge_processor. |
294 | // |
295 | // Returns true only when the edges intersect in the sense of |
296 | // S2EdgeUtil::RobustCrossing, returns false immediately when the |
297 | // wedge_processor returns true: this means the wedge processor |
298 | // knows the value of the property that the caller wants to compute, |
299 | // and no further inspection is needed. For instance, if the |
300 | // property is "loops intersect", then a wedge intersection is all |
301 | // it takes to return true. |
302 | // |
303 | // See Contains(), Intersects() and ContainsOrCrosses() for the |
304 | // three uses of this function. |
305 | bool AreBoundariesCrossing( |
306 | S2Loop const* b, WedgeProcessor* wedge_processor) const; |
307 | |
308 | // When the loop is modified (the only cae being Invert() at this time), |
309 | // the indexing structures need to be deleted as they become invalid. |
310 | void ResetMutableFields(); |
311 | |
312 | // We store the vertices in an array rather than a vector because we don't |
313 | // need any STL methods, and computing the number of vertices using size() |
314 | // would be relatively expensive (due to division by sizeof(S2Point) == 24). |
315 | // When DecodeWithinScope is used to initialize the loop, we do not |
316 | // take ownership of the memory for vertices_, and the owns_vertices_ field |
317 | // is used to prevent deallocation and overwriting. |
318 | int num_vertices_; |
319 | S2Point* vertices_; |
320 | bool owns_vertices_; |
321 | |
322 | S2LatLngRect bound_; |
323 | bool origin_inside_; |
324 | int depth_; |
325 | |
326 | // Quadtree index structure of this loop's edges. |
327 | mutable S2LoopIndex index_; |
328 | |
329 | // Map for speeding up FindVertex: We will compute a map from vertex to |
330 | // index in the vertex array as soon as there has been enough calls. |
331 | mutable int num_find_vertex_calls_; |
332 | mutable map<S2Point, int> vertex_to_index_; |
333 | |
334 | DISALLOW_EVIL_CONSTRUCTORS(S2Loop); |
335 | }; |
336 | |
337 | //////////////////// Implementation Details Follow //////////////////////// |
338 | |
339 | // Since this method is templatized and public, the implementation needs to be |
340 | // in the .h file. |
341 | |
342 | template <class T> |
343 | T S2Loop::GetSurfaceIntegral(T f_tri(S2Point const&, S2Point const&, |
344 | S2Point const&)) const { |
345 | // We sum "f_tri" over a collection T of oriented triangles, possibly |
346 | // overlapping. Let the sign of a triangle be +1 if it is CCW and -1 |
347 | // otherwise, and let the sign of a point "x" be the sum of the signs of the |
348 | // triangles containing "x". Then the collection of triangles T is chosen |
349 | // such that either: |
350 | // |
351 | // (1) Each point in the loop interior has sign +1, and sign 0 otherwise; or |
352 | // (2) Each point in the loop exterior has sign -1, and sign 0 otherwise. |
353 | // |
354 | // The triangles basically consist of a "fan" from vertex 0 to every loop |
355 | // edge that does not include vertex 0. These triangles will always satisfy |
356 | // either (1) or (2). However, what makes this a bit tricky is that |
357 | // spherical edges become numerically unstable as their length approaches |
358 | // 180 degrees. Of course there is not much we can do if the loop itself |
359 | // contains such edges, but we would like to make sure that all the triangle |
360 | // edges under our control (i.e., the non-loop edges) are stable. For |
361 | // example, consider a loop around the equator consisting of four equally |
362 | // spaced points. This is a well-defined loop, but we cannot just split it |
363 | // into two triangles by connecting vertex 0 to vertex 2. |
364 | // |
365 | // We handle this type of situation by moving the origin of the triangle fan |
366 | // whenever we are about to create an unstable edge. We choose a new |
367 | // location for the origin such that all relevant edges are stable. We also |
368 | // create extra triangles with the appropriate orientation so that the sum |
369 | // of the triangle signs is still correct at every point. |
370 | |
371 | // The maximum length of an edge for it to be considered numerically stable. |
372 | // The exact value is fairly arbitrary since it depends on the stability of |
373 | // the "f_tri" function. The value below is quite conservative but could be |
374 | // reduced further if desired. |
375 | static double const kMaxLength = M_PI - 1e-5; |
376 | |
377 | // The default constructor for T must initialize the value to zero. |
378 | // (This is true for built-in types such as "double".) |
379 | T sum = T(); |
380 | S2Point origin = vertex(0); |
381 | for (int i = 1; i + 1 < num_vertices(); ++i) { |
382 | // Let V_i be vertex(i), let O be the current origin, and let length(A,B) |
383 | // be the length of edge (A,B). At the start of each loop iteration, the |
384 | // "leading edge" of the triangle fan is (O,V_i), and we want to extend |
385 | // the triangle fan so that the leading edge is (O,V_i+1). |
386 | // |
387 | // Invariants: |
388 | // 1. length(O,V_i) < kMaxLength for all (i > 1). |
389 | // 2. Either O == V_0, or O is approximately perpendicular to V_0. |
390 | // 3. "sum" is the oriented integral of f over the area defined by |
391 | // (O, V_0, V_1, ..., V_i). |
392 | DCHECK(i == 1 || origin.Angle(vertex(i)) < kMaxLength); |
393 | DCHECK(origin == vertex(0) || fabs(origin.DotProd(vertex(0))) < 1e-15); |
394 | |
395 | if (vertex(i+1).Angle(origin) > kMaxLength) { |
396 | // We are about to create an unstable edge, so choose a new origin O' |
397 | // for the triangle fan. |
398 | S2Point old_origin = origin; |
399 | if (origin == vertex(0)) { |
400 | // The following point is well-separated from V_i and V_0 (and |
401 | // therefore V_i+1 as well). |
402 | origin = S2::RobustCrossProd(vertex(0), vertex(i)).Normalize(); |
403 | } else if (vertex(i).Angle(vertex(0)) < kMaxLength) { |
404 | // All edges of the triangle (O, V_0, V_i) are stable, so we can |
405 | // revert to using V_0 as the origin. |
406 | origin = vertex(0); |
407 | } else { |
408 | // (O, V_i+1) and (V_0, V_i) are antipodal pairs, and O and V_0 are |
409 | // perpendicular. Therefore V_0.CrossProd(O) is approximately |
410 | // perpendicular to all of {O, V_0, V_i, V_i+1}, and we can choose |
411 | // this point O' as the new origin. |
412 | origin = vertex(0).CrossProd(old_origin); |
413 | |
414 | // Advance the edge (V_0,O) to (V_0,O'). |
415 | sum += f_tri(vertex(0), old_origin, origin); |
416 | } |
417 | // Advance the edge (O,V_i) to (O',V_i). |
418 | sum += f_tri(old_origin, vertex(i), origin); |
419 | } |
420 | // Advance the edge (O,V_i) to (O,V_i+1). |
421 | sum += f_tri(origin, vertex(i), vertex(i+1)); |
422 | } |
423 | // If the origin is not V_0, we need to sum one more triangle. |
424 | if (origin != vertex(0)) { |
425 | // Advance the edge (O,V_n-1) to (O,V_0). |
426 | sum += f_tri(origin, vertex(num_vertices() - 1), vertex(0)); |
427 | } |
428 | return sum; |
429 | } |
430 | |
431 | #endif // UTIL_GEOMETRY_S2LOOP_H__ |
432 | |