1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S2EDGEUTIL_H__ |
4 | #define UTIL_GEOMETRY_S2EDGEUTIL_H__ |
5 | |
6 | #include "base/logging.h" |
7 | #include "base/macros.h" |
8 | #include "s2.h" |
9 | #include "s2latlngrect.h" |
10 | |
11 | class S2LatLngRect; |
12 | |
13 | // This class contains various utility functions related to edges. It |
14 | // collects together common code that is needed to implement polygonal |
15 | // geometry such as polylines, loops, and general polygons. |
16 | class S2EdgeUtil { |
17 | public: |
18 | // This class allows a vertex chain v0, v1, v2, ... to be efficiently |
19 | // tested for intersection with a given fixed edge AB. |
20 | class EdgeCrosser { |
21 | public: |
22 | // AB is the given fixed edge, and C is the first vertex of the vertex |
23 | // chain. All parameters must point to fixed storage that persists for |
24 | // the lifetime of the EdgeCrosser object. |
25 | inline EdgeCrosser(S2Point const* a, S2Point const* b, S2Point const* c); |
26 | |
27 | // Call this function when your chain 'jumps' to a new place. |
28 | inline void RestartAt(S2Point const* c); |
29 | |
30 | // This method is equivalent to calling the S2EdgeUtil::RobustCrossing() |
31 | // function (defined below) on the edges AB and CD. It returns +1 if |
32 | // there is a crossing, -1 if there is no crossing, and 0 if two points |
33 | // from different edges are the same. Returns 0 or -1 if either edge is |
34 | // degenerate. As a side effect, it saves vertex D to be used as the next |
35 | // vertex C. |
36 | inline int RobustCrossing(S2Point const* d); |
37 | |
38 | // This method is equivalent to the S2EdgeUtil::EdgeOrVertexCrossing() |
39 | // method defined below. It is similar to RobustCrossing, but handles |
40 | // cases where two vertices are identical in a way that makes it easy to |
41 | // implement point-in-polygon containment tests. |
42 | inline bool EdgeOrVertexCrossing(S2Point const* d); |
43 | |
44 | private: |
45 | // This function handles the "slow path" of RobustCrossing(), which does |
46 | // not need to be inlined. |
47 | int RobustCrossingInternal(S2Point const* d); |
48 | |
49 | // The fields below are all constant. |
50 | S2Point const* const a_; |
51 | S2Point const* const b_; |
52 | S2Point const a_cross_b_; |
53 | |
54 | // The fields below are updated for each vertex in the chain. |
55 | S2Point const* c_; // Previous vertex in the vertex chain. |
56 | int acb_; // The orientation of the triangle ACB. |
57 | }; |
58 | |
59 | // This class computes a bounding rectangle that contains all edges |
60 | // defined by a vertex chain v0, v1, v2, ... All vertices must be unit |
61 | // length. Note that the bounding rectangle of an edge can be larger than |
62 | // the bounding rectangle of its endpoints, e.g. consider an edge that |
63 | // passes through the north pole. |
64 | class RectBounder { |
65 | public: |
66 | RectBounder() : bound_(S2LatLngRect::Empty()) {} |
67 | |
68 | // This method is called to add each vertex to the chain. 'b' |
69 | // must point to fixed storage that persists through the next call |
70 | // to AddPoint. This means that if you don't store all of your |
71 | // points for the lifetime of the bounder, you must at least store |
72 | // the last two points and alternate which one you use for the |
73 | // next point. |
74 | void AddPoint(S2Point const* b); |
75 | |
76 | // Return the bounding rectangle of the edge chain that connects the |
77 | // vertices defined so far. |
78 | S2LatLngRect GetBound() const { return bound_; } |
79 | |
80 | private: |
81 | S2Point const* a_; // The previous vertex in the chain. |
82 | S2LatLng a_latlng_; // The corresponding latitude-longitude. |
83 | S2LatLngRect bound_; // The current bounding rectangle. |
84 | }; |
85 | |
86 | // The purpose of this class is to find edges that intersect a given |
87 | // longitude interval. It can be used as an efficient rejection test when |
88 | // attempting to find edges that intersect a given region. It accepts a |
89 | // vertex chain v0, v1, v2, ... and returns a boolean value indicating |
90 | // whether each edge intersects the specified longitude interval. |
91 | class LongitudePruner { |
92 | public: |
93 | // 'interval' is the longitude interval to be tested against, and |
94 | // 'v0' is the first vertex of edge chain. |
95 | LongitudePruner(S1Interval const& interval, S2Point const& v0); |
96 | |
97 | // Returns true if the edge (v0, v1) intersects the given longitude |
98 | // interval, and then saves 'v1' to be used as the next 'v0'. |
99 | inline bool Intersects(S2Point const& v1); |
100 | |
101 | private: |
102 | S1Interval interval_; // The interval to be tested against. |
103 | double lng0_; // The longitude of the next v0. |
104 | }; |
105 | |
106 | // Return true if edge AB crosses CD at a point that is interior |
107 | // to both edges. Properties: |
108 | // |
109 | // (1) SimpleCrossing(b,a,c,d) == SimpleCrossing(a,b,c,d) |
110 | // (2) SimpleCrossing(c,d,a,b) == SimpleCrossing(a,b,c,d) |
111 | static bool SimpleCrossing(S2Point const& a, S2Point const& b, |
112 | S2Point const& c, S2Point const& d); |
113 | |
114 | // Like SimpleCrossing, except that points that lie exactly on a line are |
115 | // arbitrarily classified as being on one side or the other (according to |
116 | // the rules of S2::RobustCCW). It returns +1 if there is a crossing, -1 |
117 | // if there is no crossing, and 0 if any two vertices from different edges |
118 | // are the same. Returns 0 or -1 if either edge is degenerate. |
119 | // Properties of RobustCrossing: |
120 | // |
121 | // (1) RobustCrossing(b,a,c,d) == RobustCrossing(a,b,c,d) |
122 | // (2) RobustCrossing(c,d,a,b) == RobustCrossing(a,b,c,d) |
123 | // (3) RobustCrossing(a,b,c,d) == 0 if a==c, a==d, b==c, b==d |
124 | // (3) RobustCrossing(a,b,c,d) <= 0 if a==b or c==d |
125 | // |
126 | // Note that if you want to check an edge against a *chain* of other |
127 | // edges, it is much more efficient to use an EdgeCrosser (above). |
128 | static int RobustCrossing(S2Point const& a, S2Point const& b, |
129 | S2Point const& c, S2Point const& d); |
130 | |
131 | // Given two edges AB and CD where at least two vertices are identical |
132 | // (i.e. RobustCrossing(a,b,c,d) == 0), this function defines whether the |
133 | // two edges "cross" in a such a way that point-in-polygon containment tests |
134 | // can be implemented by counting the number of edge crossings. The basic |
135 | // rule is that a "crossing" occurs if AB is encountered after CD during a |
136 | // CCW sweep around the shared vertex starting from a fixed reference point. |
137 | // |
138 | // Note that according to this rule, if AB crosses CD then in general CD |
139 | // does not cross AB. However, this leads to the correct result when |
140 | // counting polygon edge crossings. For example, suppose that A,B,C are |
141 | // three consecutive vertices of a CCW polygon. If we now consider the edge |
142 | // crossings of a segment BP as P sweeps around B, the crossing number |
143 | // changes parity exactly when BP crosses BA or BC. |
144 | // |
145 | // Useful properties of VertexCrossing (VC): |
146 | // |
147 | // (1) VC(a,a,c,d) == VC(a,b,c,c) == false |
148 | // (2) VC(a,b,a,b) == VC(a,b,b,a) == true |
149 | // (3) VC(a,b,c,d) == VC(a,b,d,c) == VC(b,a,c,d) == VC(b,a,d,c) |
150 | // (3) If exactly one of a,b equals one of c,d, then exactly one of |
151 | // VC(a,b,c,d) and VC(c,d,a,b) is true |
152 | // |
153 | // It is an error to call this method with 4 distinct vertices. |
154 | static bool VertexCrossing(S2Point const& a, S2Point const& b, |
155 | S2Point const& c, S2Point const& d); |
156 | |
157 | // A convenience function that calls RobustCrossing() to handle cases |
158 | // where all four vertices are distinct, and VertexCrossing() to handle |
159 | // cases where two or more vertices are the same. This defines a crossing |
160 | // function such that point-in-polygon containment tests can be implemented |
161 | // by simply counting edge crossings. |
162 | static bool EdgeOrVertexCrossing(S2Point const& a, S2Point const& b, |
163 | S2Point const& c, S2Point const& d); |
164 | |
165 | // Given two edges AB and CD such that RobustCrossing() is true, return |
166 | // their intersection point. Useful properties of GetIntersection (GI): |
167 | // |
168 | // (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d) |
169 | // (2) GI(c,d,a,b) == GI(a,b,c,d) |
170 | // |
171 | // The returned intersection point X is guaranteed to be close to the edges |
172 | // AB and CD, but if the edges intersect at a very small angle then X may |
173 | // not be close to the true mathematical intersection point P. See the |
174 | // description of "kIntersectionTolerance" below for details. |
175 | static S2Point GetIntersection(S2Point const& a, S2Point const& b, |
176 | S2Point const& c, S2Point const& d); |
177 | |
178 | // This distance is an upper bound on the distance from the intersection |
179 | // point returned by GetIntersection() to either of the two edges that were |
180 | // intersected. In particular, if "x" is the intersection point, then |
181 | // GetDistance(x, a, b) and GetDistance(x, c, d) will both be smaller than |
182 | // this value. The intersection tolerance is also large enough such if it |
183 | // is passed as the "vertex_merge_radius" of an S2PolygonBuilder, then the |
184 | // intersection point will be spliced into the edges AB and/or CD if they |
185 | // are also supplied to the S2PolygonBuilder. |
186 | static S1Angle const kIntersectionTolerance; |
187 | |
188 | // Given a point X and an edge AB, return the distance ratio AX / (AX + BX). |
189 | // If X happens to be on the line segment AB, this is the fraction "t" such |
190 | // that X == Interpolate(A, B, t). Requires that A and B are distinct. |
191 | static double GetDistanceFraction(S2Point const& x, |
192 | S2Point const& a, S2Point const& b); |
193 | |
194 | // Return the point X along the line segment AB whose distance from A is the |
195 | // given fraction "t" of the distance AB. Does NOT require that "t" be |
196 | // between 0 and 1. Note that all distances are measured on the surface of |
197 | // the sphere, so this is more complicated than just computing (1-t)*a + t*b |
198 | // and normalizing the result. |
199 | static S2Point Interpolate(double t, S2Point const& a, S2Point const& b); |
200 | |
201 | // Like Interpolate(), except that the parameter "ax" represents the desired |
202 | // distance from A to the result X rather than a fraction between 0 and 1. |
203 | static S2Point InterpolateAtDistance(S1Angle const& ax, |
204 | S2Point const& a, S2Point const& b); |
205 | |
206 | // A slightly more efficient version of InterpolateAtDistance() that can be |
207 | // used when the distance AB is already known. |
208 | static S2Point InterpolateAtDistance(S1Angle const& ax, |
209 | S2Point const& a, S2Point const& b, |
210 | S1Angle const& ab); |
211 | |
212 | // Return the minimum distance from X to any point on the edge AB. All |
213 | // arguments should be unit length. The result is very accurate for small |
214 | // distances but may have some numerical error if the distance is large |
215 | // (approximately Pi/2 or greater). The case A == B is handled correctly. |
216 | static S1Angle GetDistance(S2Point const& x, |
217 | S2Point const& a, S2Point const& b); |
218 | |
219 | // A slightly more efficient version of GetDistance() where the cross |
220 | // product of the two endpoints has been precomputed. The cross product |
221 | // does not need to be normalized, but should be computed using |
222 | // S2::RobustCrossProd() for the most accurate results. |
223 | static S1Angle GetDistance(S2Point const& x, |
224 | S2Point const& a, S2Point const& b, |
225 | S2Point const& a_cross_b); |
226 | |
227 | // Return the point along the edge AB that is closest to the point X. |
228 | // The fractional distance of this point along the edge AB can be obtained |
229 | // using GetDistanceFraction() above. |
230 | static S2Point GetClosestPoint(S2Point const& x, |
231 | S2Point const& a, S2Point const& b); |
232 | |
233 | // A slightly more efficient version of GetClosestPoint() where the cross |
234 | // product of the two endpoints has been precomputed. The cross product |
235 | // does not need to be normalized, but should be computed using |
236 | // S2::RobustCrossProd() for the most accurate results. |
237 | static S2Point GetClosestPoint(S2Point const& x, |
238 | S2Point const& a, S2Point const& b, |
239 | S2Point const& a_cross_b); |
240 | |
241 | // Return true if every point on edge B=b0b1 is no further than "tolerance" |
242 | // from some point on edge A=a0a1. |
243 | // Requires that tolerance is less than 90 degrees. |
244 | static bool IsEdgeBNearEdgeA(S2Point const& a0, S2Point const& a1, |
245 | S2Point const& b0, S2Point const& b1, |
246 | S1Angle const& tolerance); |
247 | |
248 | // For an edge chain (x0, x1, x2), a wedge is the region to the left |
249 | // of the edges. More precisely, it is the union of all the rays |
250 | // from x1x0 to x1x2, clockwise. |
251 | // The following are Wedge comparison functions for two wedges A = |
252 | // (a0, ab1, a2) and B = (b0, a12, b2). These are used in S2Loops. |
253 | |
254 | // Returns true if wedge A fully contains or is equal to wedge B. |
255 | static bool WedgeContains(S2Point const& a0, S2Point const& ab1, |
256 | S2Point const& a2, S2Point const& b0, |
257 | S2Point const& b2); |
258 | |
259 | // Returns true if the intersection of the two wedges is not empty. |
260 | static bool WedgeIntersects(S2Point const& a0, S2Point const& ab1, |
261 | S2Point const& a2, S2Point const& b0, |
262 | S2Point const& b2); |
263 | |
264 | // Detailed relation from wedges A to wedge B. |
265 | enum WedgeRelation { |
266 | WEDGE_EQUALS, |
267 | WEDGE_PROPERLY_CONTAINS, // A is a strict superset of B. |
268 | WEDGE_IS_PROPERLY_CONTAINED, // A is a strict subset of B. |
269 | WEDGE_PROPERLY_OVERLAPS, // All of A intsect B, A-B and B-A are non-empty. |
270 | WEDGE_IS_DISJOINT, // A is disjoint from B |
271 | }; |
272 | |
273 | // Return the relation from wedge A to B. |
274 | static WedgeRelation GetWedgeRelation( |
275 | S2Point const& a0, S2Point const& ab1, S2Point const& a2, |
276 | S2Point const& b0, S2Point const& b2); |
277 | |
278 | DISALLOW_IMPLICIT_CONSTRUCTORS(S2EdgeUtil); // Contains only static methods. |
279 | }; |
280 | |
281 | inline S2EdgeUtil::EdgeCrosser::EdgeCrosser( |
282 | S2Point const* a, S2Point const* b, S2Point const* c) |
283 | : a_(a), b_(b), a_cross_b_(a_->CrossProd(*b_)) { |
284 | RestartAt(c); |
285 | } |
286 | |
287 | inline void S2EdgeUtil::EdgeCrosser::RestartAt(S2Point const* c) { |
288 | c_ = c; |
289 | acb_ = -S2::RobustCCW(*a_, *b_, *c_, a_cross_b_); |
290 | } |
291 | |
292 | inline int S2EdgeUtil::EdgeCrosser::RobustCrossing(S2Point const* d) { |
293 | // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must |
294 | // all be oriented the same way (CW or CCW). We keep the orientation of ACB |
295 | // as part of our state. When each new point D arrives, we compute the |
296 | // orientation of BDA and check whether it matches ACB. This checks whether |
297 | // the points C and D are on opposite sides of the great circle through AB. |
298 | |
299 | // Recall that RobustCCW is invariant with respect to rotating its |
300 | // arguments, i.e. ABC has the same orientation as BDA. |
301 | int bda = S2::RobustCCW(*a_, *b_, *d, a_cross_b_); |
302 | int result; |
303 | if (bda == -acb_ && bda != 0) { |
304 | result = -1; // Most common case -- triangles have opposite orientations. |
305 | } else if ((bda & acb_) == 0) { |
306 | result = 0; // At least one value is zero -- two vertices are identical. |
307 | } else { // Slow path. |
308 | DCHECK_EQ(acb_, bda); |
309 | DCHECK_NE(0, bda); |
310 | result = RobustCrossingInternal(d); |
311 | } |
312 | // Now save the current vertex D as the next vertex C, and also save the |
313 | // orientation of the new triangle ACB (which is opposite to the current |
314 | // triangle BDA). |
315 | c_ = d; |
316 | acb_ = -bda; |
317 | return result; |
318 | } |
319 | |
320 | inline bool S2EdgeUtil::EdgeCrosser::EdgeOrVertexCrossing(S2Point const* d) { |
321 | // We need to copy c_ since it is clobbered by RobustCrossing(). |
322 | S2Point const* c = c_; |
323 | int crossing = RobustCrossing(d); |
324 | if (crossing < 0) return false; |
325 | if (crossing > 0) return true; |
326 | return VertexCrossing(*a_, *b_, *c, *d); |
327 | } |
328 | |
329 | inline bool S2EdgeUtil::LongitudePruner::Intersects(S2Point const& v1) { |
330 | double lng1 = S2LatLng::Longitude(v1).radians(); |
331 | bool result = interval_.Intersects(S1Interval::FromPointPair(lng0_, lng1)); |
332 | lng0_ = lng1; |
333 | return result; |
334 | } |
335 | |
336 | #endif // UTIL_GEOMETRY_S2EDGEUTIL_H__ |
337 | |