1 // Copyright 2005 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.s2edge_crosser;
20 
21 import math = std.math;
22 import s2.logger;
23 import s2.s2edge_crossings;
24 import s2.s2point;
25 import s2.s2pointutil;
26 import s2.s2predicates;
27 import s2.util.math.vector;
28 
29 /**
30  * This class allows edges to be efficiently tested for intersection with a
31  * given fixed edge AB.  It is especially efficient when testing for
32  * intersection with an edge chain connecting vertices v0, v1, v2, ...
33  *
34  * Example usage:
35  *
36  *   void CountIntersections(const S2Point& a, const S2Point& b,
37  *                           const vector<pair<S2Point, S2Point>>& edges) {
38  *     int count = 0;
39  *     S2EdgeCrosser crosser(&a, &b);
40  *     for (const auto& edge : edges) {
41  *       if (crosser.CrossingSign(&edge.first, &edge.second) >= 0) {
42  *         ++count;
43  *       }
44  *     }
45  *     return count;
46  *   }
47  *
48  * This class expects that the client already has all the necessary vertices
49  * stored in memory, so that this class can refer to them with pointers and
50  * does not need to make its own copies.  If this is not the case (e.g., you
51  * want to pass temporary objects as vertices), see S2CopyingEdgeCrosser.
52  */
53 class S2EdgeCrosser {
54 public:
55   // Default constructor; must be followed by a call to Init().
56   this() {}
57 
58   // Convenience constructor that calls Init() with the given fixed edge AB.
59   // The arguments "a" and "b" must point to values that persist for the
60   // lifetime of the S2EdgeCrosser object (or until the next Init() call).
61   this(ref in S2Point a, ref in S2Point b) {
62     if (!isUnitLength(a)) logger.logWarn("Invalid");
63     if (!isUnitLength(b)) logger.logWarn("Invalid");
64 
65     _a = &a;
66     _b = &b;
67     _aCrossB = _a.crossProd(*_b);
68     _haveTangents = false;
69     _c = null;
70   }
71 
72   // Accessors for the constructor arguments.
73   const (S2Point*) a() {
74     return _a;
75   }
76 
77   const (S2Point*) b() {
78     return _b;
79   }
80 
81   // Initialize the S2EdgeCrosser with the given fixed edge AB.  The arguments
82   // "a" and "b" must point to values that persist for the lifetime of the
83   // S2EdgeCrosser object (or until the next Init() call).
84   void initialize(ref in S2Point a, ref in S2Point b) {
85     _a = &a;
86     _b = &b;
87     _aCrossB = a.crossProd(*_b);
88     _haveTangents = false;
89     _c = null;
90   }
91 
92   /**
93    * This function determines whether the edge AB intersects the edge CD.
94    * Returns +1 if AB crosses CD at a point that is interior to both edges.
95    * Returns  0 if any two vertices from different edges are the same.
96    * Returns -1 otherwise.
97    *
98    * Note that if an edge is degenerate (A == B or C == D), the return value
99    * is 0 if two vertices from different edges are the same and -1 otherwise.
100    *
101    * Properties of CrossingSign:
102    *
103    *  (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d)
104    *  (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d)
105    *  (3) CrossingSign(a,b,c,d) == 0 if a==c, a==d, b==c, b==d
106    *  (3) CrossingSign(a,b,c,d) <= 0 if a==b or c==d (see above)
107    *
108    * This function implements an exact, consistent perturbation model such
109    * that no three points are ever considered to be collinear.  This means
110    * that even if you have 4 points A, B, C, D that lie exactly in a line
111    * (say, around the equator), C and D will be treated as being slightly to
112    * one side or the other of AB.  This is done in a way such that the
113    * results are always consistent (see s2pred::Sign).
114    *
115    * Note that if you want to check an edge against a chain of other edges,
116    * it is slightly more efficient to use the single-argument version of
117    * CrossingSign below.
118    *
119    * The arguments must point to values that persist until the next call.
120    */
121   int crossingSign(ref in S2Point c, ref in S2Point d) {
122     if (_c != &c) {
123       restartAt(c);
124     }
125     return crossingSign(d);
126   }
127 
128   /**
129    * This method extends the concept of a "crossing" to the case where AB
130    * and CD have a vertex in common.  The two edges may or may not cross,
131    * according to the rules defined in VertexCrossing() below.  The rules
132    * are designed so that point containment tests can be implemented simply
133    * by counting edge crossings.  Similarly, determining whether one edge
134    * chain crosses another edge chain can be implemented by counting.
135    *
136    * Returns true if CrossingSign(c, d) > 0, or AB and CD share a vertex
137    * and VertexCrossing(a, b, c, d) returns true.
138    *
139    * The arguments must point to values that persist until the next call.
140    */
141   bool edgeOrVertexCrossing(ref in S2Point c, ref in S2Point d) {
142     if (_c != &c) {
143       restartAt(c);
144     }
145     return edgeOrVertexCrossing(d);
146   }
147 
148   ///////////////////////// Edge Chain Methods ///////////////////////////
149   //
150   // You don't need to use these unless you're trying to squeeze out every
151   // last drop of performance.  Essentially all you are saving is a test
152   // whether the first vertex of the current edge is the same as the second
153   // vertex of the previous edge.  Example usage:
154   //
155   //   vector<S2Point> chain;
156   //   crosser.RestartAt(&chain[0]);
157   //   for (int i = 1; i < chain.size(); ++i) {
158   //     if (crosser.EdgeOrVertexCrossing(&chain[i])) { ++count; }
159   //   }
160 
161   /**
162    * Convenience constructor that uses AB as the fixed edge, and C as the
163    * first vertex of the vertex chain (equivalent to calling RestartAt(c)).
164    *
165    * The arguments must point to values that persist until the next call.
166    */
167   this(ref in S2Point a, ref in S2Point b, ref in S2Point c) {
168     if (!isUnitLength(a)) logger.logWarn("Invalid");
169     if (!isUnitLength(b)) logger.logWarn("Invalid");
170 
171     _a = &a;
172     _b = &b;
173     _aCrossB = _a.crossProd(*_b);
174     _haveTangents = false;
175     restartAt(c);
176   }
177 
178 
179   /**
180    * Call this method when your chain 'jumps' to a new place.
181    * The argument must point to a value that persists until the next call.
182    */
183   void restartAt(ref in S2Point c) {
184     if (!isUnitLength(c)) logger.logWarn("Invalid");
185     _c = &c;
186     _acb = -triageSign(*_a, *_b, *_c, _aCrossB);
187   }
188 
189 
190   /**
191    * Like CrossingSign above, but uses the last vertex passed to one of
192    * the crossing methods (or RestartAt) as the first vertex of the current
193    * edge.
194    *
195    * The argument must point to a value that persists until the next call.
196    */
197   int crossingSign(ref in S2Point d) {
198     if (!isUnitLength(d)) logger.logWarn("Invalid");
199     // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must
200     // all be oriented the same way (CW or CCW).  We keep the orientation of ACB
201     // as part of our state.  When each new point D arrives, we compute the
202     // orientation of BDA and check whether it matches ACB.  This checks whether
203     // the points C and D are on opposite sides of the great circle through AB.
204 
205     // Recall that TriageSign is invariant with respect to rotating its
206     // arguments, i.e. ABD has the same orientation as BDA.
207     int bda = triageSign(*_a, *_b, d, _aCrossB);
208     if (_acb == -bda && bda != 0) {
209       // The most common case -- triangles have opposite orientations.  Save the
210       // current vertex D as the next vertex C, and also save the orientation of
211       // the new triangle ACB (which is opposite to the current triangle BDA).
212       _c = &d;
213       _acb = -bda;
214       return -1;
215     }
216     _bda = bda;
217     return crossingSignInternal(d);
218   }
219 
220   /**
221    * Like EdgeOrVertexCrossing above, but uses the last vertex passed to one
222    * of the crossing methods (or RestartAt) as the first vertex of the
223    * current edge.
224    *
225    * The argument must point to a value that persists until the next call.
226    */
227   bool edgeOrVertexCrossing(ref in S2Point d) {
228     // We need to copy c_ since it is clobbered by CrossingSign().
229     const S2Point c = *_c;
230     int crossing = crossingSign(d);
231     if (crossing < 0) {
232       return false;
233     }
234     if (crossing > 0) {
235       return true;
236     }
237     return vertexCrossing(*_a, *_b, c, d);
238   }
239 
240   /**
241    * Returns the last vertex of the current edge chain being tested, i.e. the
242    * C vertex that will be used to construct the edge CD when one of the
243    * methods above is called.
244    */
245   @property
246   const(S2Point)* c() {
247     return _c;
248   }
249 
250 private:
251   /** These functions handle the "slow path" of CrossingSign(). */
252   int crossingSignInternal(ref in S2Point d) {
253     // Compute the actual result, and then save the current vertex D as the next
254     // vertex C, and save the orientation of the next triangle ACB (which is
255     // opposite to the current triangle BDA).
256     int result = crossingSignInternal2(d);
257     _c = &d;
258     _acb = -_bda;
259     return result;
260   }
261 
262   int crossingSignInternal2(ref in S2Point d) {
263     // At this point, a very common situation is that A,B,C,D are four points on
264     // a line such that AB does not overlap CD.  (For example, this happens when
265     // a line or curve is sampled finely, or when geometry is constructed by
266     // computing the union of S2CellIds.)  Most of the time, we can determine
267     // that AB and CD do not intersect by computing the two outward-facing
268     // tangents at A and B (parallel to AB) and testing whether AB and CD are on
269     // opposite sides of the plane perpendicular to one of these tangents.  This
270     // is moderately expensive but still much cheaper than s2pred::ExpensiveSign.
271     if (!_haveTangents) {
272       S2Point norm = robustCrossProd(*_a, *_b).normalize();
273       _aTangent = _a.crossProd(norm);
274       _bTangent = norm.crossProd(*_b);
275       _haveTangents = true;
276     }
277     // The error in robustCrossProd() is insignificant.  The maximum error in
278     // the call to crossProd() (i.e., the maximum norm of the error vector) is
279     // (0.5 + 1/sqrt(3)) * double.epsilon.  The maximum error in each call to
280     // DotProd() below is double.epsilon.  (There is also a small relative error
281     // term that is insignificant because we are comparing the result against a
282     // constant that is very close to zero.)
283     static const double kError = (1.5 + 1 / math.sqrt(3.0)) * double.epsilon;
284     if ((_c.dotProd(_aTangent) > kError && d.dotProd(_aTangent) > kError) ||
285         (_c.dotProd(_bTangent) > kError && d.dotProd(_bTangent) > kError)) {
286       return -1;
287     }
288 
289     // Otherwise, eliminate the cases where two vertices from different edges
290     // are equal.  (These cases could be handled in the code below, but we would
291     // rather avoid calling ExpensiveSign whenever possible.)
292     if (*_a == *_c || *_a == d || *_b == *_c || *_b == d) {
293       return 0;
294     }
295 
296     // Eliminate cases where an input edge is degenerate.  (Note that in most
297     // cases, if CD is degenerate then this method is not even called because
298     // _acb and bda have different signs.)
299     if (*_a == *_b || *_c == d) {
300       return -1;
301     }
302 
303     // Otherwise it's time to break out the big guns.
304     if (_acb == 0) {
305       _acb = -expensiveSign(*_a, *_b, *_c);
306     }
307     assert(_acb != 0);
308     if (_bda == 0) {
309       _bda = expensiveSign(*_a, *_b, d);
310     }
311     assert(_bda != 0);
312     if (_bda != _acb) {
313       return -1;
314     }
315 
316     Vector3_d c_cross_d = _c.crossProd(d);
317     int cbd = -sign(*_c, d, *_b, c_cross_d);
318     assert(cbd != 0);
319     if (cbd != _acb) {
320       return -1;
321     }
322     int dac = sign(*_c, d, *_a, c_cross_d);
323     assert(dac != 0);
324     return (dac != _acb) ? -1 : 1;
325   }
326 
327   /** Used internally by S2CopyingEdgeCrosser.  Updates "_c" only. */
328   void setC(ref S2Point c) {
329     _c = &c;
330   }
331 
332   // The fields below are constant after the call to Init().
333   const(S2Point)* _a;
334   const(S2Point)* _b;
335   Vector3_d _aCrossB;
336 
337   // To reduce the number of calls to s2pred::ExpensiveSign(), we compute an
338   // outward-facing tangent at A and B if necessary.  If the plane
339   // perpendicular to one of these tangents separates AB from CD (i.e., one
340   // edge on each side) then there is no intersection.
341   bool _haveTangents;  // True if the tangents have been computed.
342   S2Point _aTangent;   // Outward-facing tangent at A.
343   S2Point _bTangent;   // Outward-facing tangent at B.
344 
345   // The fields below are updated for each vertex in the chain.
346   const(S2Point)* _c;      // Previous vertex in the vertex chain.
347   int _acb;                // The orientation of triangle ACB.
348 
349   // The field below is a temporary used by CrossingSignInternal().
350   int _bda;                // The orientation of triangle BDA.
351 }
352 
353 /**
354  * S2CopyingEdgeCrosser is exactly like S2EdgeCrosser, except that it makes its
355  * own copy of all arguments so that they do not need to persist between
356  * calls.  This is less efficient, but makes it possible to use points that
357  * are generated on demand and cannot conveniently be stored by the client.
358  */
359 class S2CopyingEdgeCrosser {
360 public:
361   // These methods are all exactly like S2EdgeCrosser, except that the
362   // arguments can be temporaries.
363   this() {
364     _crosser = new S2EdgeCrosser();
365   }
366 
367   this(in S2Point a, in S2Point b) {
368     _a = a;
369     _b = b;
370     _c = S2Point();
371     _crosser = new S2EdgeCrosser(_a, _b);
372   }
373 
374   S2Point a() {
375     return _a;
376   }
377 
378   S2Point b() {
379     return _b;
380   }
381 
382   S2Point c() {
383     return _c;
384   }
385 
386   void initialize(in S2Point a, in S2Point b) {
387     _a = a;
388     _b = b;
389     _c = S2Point();
390     _crosser.initialize(_a, _b);
391   }
392 
393   int crossingSign(in S2Point c, in S2Point d) {
394     if (c != _c || _crosser._c == null) {
395       restartAt(c);
396     }
397     return crossingSign(d);
398   }
399 
400   bool edgeOrVertexCrossing(in S2Point c, in S2Point d) {
401     if (c != _c || _crosser._c == null) {
402       restartAt(c);
403     }
404     return edgeOrVertexCrossing(d);
405   }
406 
407   this(in S2Point a, in S2Point b, in S2Point c) {
408     _a = a;
409     _b = b;
410     _c = c;
411     _crosser = new S2EdgeCrosser(_a, _b, _c);
412   }
413 
414   void restartAt(in S2Point c) {
415     _c = c;
416     _crosser.restartAt(_c);
417   }
418 
419   int crossingSign(in S2Point d) {
420     int result = _crosser.crossingSign(d);
421     _c = d;
422     _crosser.setC(_c);
423     return result;
424   }
425 
426   bool edgeOrVertexCrossing(in S2Point d) {
427     bool result = _crosser.edgeOrVertexCrossing(d);
428     _c = d;
429     _crosser.setC(_c);
430     return result;
431   }
432 
433 private:
434   S2Point _a;
435   S2Point _b;
436   S2Point _c;
437   // TODO(ericv): It would be more efficient to implement S2CopyingEdgeCrosser
438   // directly rather than as a wrapper around S2EdgeCrosser.
439   S2EdgeCrosser _crosser;
440 }