edge_crosser.go (8551B)
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 package s2 16 17 import ( 18 "math" 19 ) 20 21 // EdgeCrosser allows edges to be efficiently tested for intersection with a 22 // given fixed edge AB. It is especially efficient when testing for 23 // intersection with an edge chain connecting vertices v0, v1, v2, ... 24 // 25 // Example usage: 26 // 27 // func CountIntersections(a, b Point, edges []Edge) int { 28 // count := 0 29 // crosser := NewEdgeCrosser(a, b) 30 // for _, edge := range edges { 31 // if crosser.CrossingSign(&edge.First, &edge.Second) != DoNotCross { 32 // count++ 33 // } 34 // } 35 // return count 36 // } 37 // 38 type EdgeCrosser struct { 39 a Point 40 b Point 41 aXb Point 42 43 // To reduce the number of calls to expensiveSign, we compute an 44 // outward-facing tangent at A and B if necessary. If the plane 45 // perpendicular to one of these tangents separates AB from CD (i.e., one 46 // edge on each side) then there is no intersection. 47 aTangent Point // Outward-facing tangent at A. 48 bTangent Point // Outward-facing tangent at B. 49 50 // The fields below are updated for each vertex in the chain. 51 c Point // Previous vertex in the vertex chain. 52 acb Direction // The orientation of triangle ACB. 53 } 54 55 // NewEdgeCrosser returns an EdgeCrosser with the fixed edge AB. 56 func NewEdgeCrosser(a, b Point) *EdgeCrosser { 57 norm := a.PointCross(b) 58 return &EdgeCrosser{ 59 a: a, 60 b: b, 61 aXb: Point{a.Cross(b.Vector)}, 62 aTangent: Point{a.Cross(norm.Vector)}, 63 bTangent: Point{norm.Cross(b.Vector)}, 64 } 65 } 66 67 // CrossingSign reports whether the edge AB intersects the edge CD. If any two 68 // vertices from different edges are the same, returns MaybeCross. If either edge 69 // is degenerate (A == B or C == D), returns either DoNotCross or MaybeCross. 70 // 71 // Properties of CrossingSign: 72 // 73 // (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d) 74 // (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d) 75 // (3) CrossingSign(a,b,c,d) == MaybeCross if a==c, a==d, b==c, b==d 76 // (3) CrossingSign(a,b,c,d) == DoNotCross or MaybeCross if a==b or c==d 77 // 78 // Note that if you want to check an edge against a chain of other edges, 79 // it is slightly more efficient to use the single-argument version 80 // ChainCrossingSign below. 81 func (e *EdgeCrosser) CrossingSign(c, d Point) Crossing { 82 if c != e.c { 83 e.RestartAt(c) 84 } 85 return e.ChainCrossingSign(d) 86 } 87 88 // EdgeOrVertexCrossing reports whether if CrossingSign(c, d) > 0, or AB and 89 // CD share a vertex and VertexCrossing(a, b, c, d) is true. 90 // 91 // This method extends the concept of a "crossing" to the case where AB 92 // and CD have a vertex in common. The two edges may or may not cross, 93 // according to the rules defined in VertexCrossing above. The rules 94 // are designed so that point containment tests can be implemented simply 95 // by counting edge crossings. Similarly, determining whether one edge 96 // chain crosses another edge chain can be implemented by counting. 97 func (e *EdgeCrosser) EdgeOrVertexCrossing(c, d Point) bool { 98 if c != e.c { 99 e.RestartAt(c) 100 } 101 return e.EdgeOrVertexChainCrossing(d) 102 } 103 104 // NewChainEdgeCrosser is a convenience constructor that uses AB as the fixed edge, 105 // and C as the first vertex of the vertex chain (equivalent to calling RestartAt(c)). 106 // 107 // You don't need to use this or any of the chain functions unless you're trying to 108 // squeeze out every last drop of performance. Essentially all you are saving is a test 109 // whether the first vertex of the current edge is the same as the second vertex of the 110 // previous edge. 111 func NewChainEdgeCrosser(a, b, c Point) *EdgeCrosser { 112 e := NewEdgeCrosser(a, b) 113 e.RestartAt(c) 114 return e 115 } 116 117 // RestartAt sets the current point of the edge crosser to be c. 118 // Call this method when your chain 'jumps' to a new place. 119 // The argument must point to a value that persists until the next call. 120 func (e *EdgeCrosser) RestartAt(c Point) { 121 e.c = c 122 e.acb = -triageSign(e.a, e.b, e.c) 123 } 124 125 // ChainCrossingSign is like CrossingSign, but uses the last vertex passed to one of 126 // the crossing methods (or RestartAt) as the first vertex of the current edge. 127 func (e *EdgeCrosser) ChainCrossingSign(d Point) Crossing { 128 // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must 129 // all be oriented the same way (CW or CCW). We keep the orientation of ACB 130 // as part of our state. When each new point D arrives, we compute the 131 // orientation of BDA and check whether it matches ACB. This checks whether 132 // the points C and D are on opposite sides of the great circle through AB. 133 134 // Recall that triageSign is invariant with respect to rotating its 135 // arguments, i.e. ABD has the same orientation as BDA. 136 bda := triageSign(e.a, e.b, d) 137 if e.acb == -bda && bda != Indeterminate { 138 // The most common case -- triangles have opposite orientations. Save the 139 // current vertex D as the next vertex C, and also save the orientation of 140 // the new triangle ACB (which is opposite to the current triangle BDA). 141 e.c = d 142 e.acb = -bda 143 return DoNotCross 144 } 145 return e.crossingSign(d, bda) 146 } 147 148 // EdgeOrVertexChainCrossing is like EdgeOrVertexCrossing, but uses the last vertex 149 // passed to one of the crossing methods (or RestartAt) as the first vertex of the current edge. 150 func (e *EdgeCrosser) EdgeOrVertexChainCrossing(d Point) bool { 151 // We need to copy e.c since it is clobbered by ChainCrossingSign. 152 c := e.c 153 switch e.ChainCrossingSign(d) { 154 case DoNotCross: 155 return false 156 case Cross: 157 return true 158 } 159 return VertexCrossing(e.a, e.b, c, d) 160 } 161 162 // crossingSign handle the slow path of CrossingSign. 163 func (e *EdgeCrosser) crossingSign(d Point, bda Direction) Crossing { 164 // Compute the actual result, and then save the current vertex D as the next 165 // vertex C, and save the orientation of the next triangle ACB (which is 166 // opposite to the current triangle BDA). 167 defer func() { 168 e.c = d 169 e.acb = -bda 170 }() 171 172 // At this point, a very common situation is that A,B,C,D are four points on 173 // a line such that AB does not overlap CD. (For example, this happens when 174 // a line or curve is sampled finely, or when geometry is constructed by 175 // computing the union of S2CellIds.) Most of the time, we can determine 176 // that AB and CD do not intersect using the two outward-facing 177 // tangents at A and B (parallel to AB) and testing whether AB and CD are on 178 // opposite sides of the plane perpendicular to one of these tangents. This 179 // is moderately expensive but still much cheaper than expensiveSign. 180 181 // The error in RobustCrossProd is insignificant. The maximum error in 182 // the call to CrossProd (i.e., the maximum norm of the error vector) is 183 // (0.5 + 1/sqrt(3)) * dblEpsilon. The maximum error in each call to 184 // DotProd below is dblEpsilon. (There is also a small relative error 185 // term that is insignificant because we are comparing the result against a 186 // constant that is very close to zero.) 187 maxError := (1.5 + 1/math.Sqrt(3)) * dblEpsilon 188 if (e.c.Dot(e.aTangent.Vector) > maxError && d.Dot(e.aTangent.Vector) > maxError) || (e.c.Dot(e.bTangent.Vector) > maxError && d.Dot(e.bTangent.Vector) > maxError) { 189 return DoNotCross 190 } 191 192 // Otherwise, eliminate the cases where two vertices from different edges are 193 // equal. (These cases could be handled in the code below, but we would rather 194 // avoid calling ExpensiveSign if possible.) 195 if e.a == e.c || e.a == d || e.b == e.c || e.b == d { 196 return MaybeCross 197 } 198 199 // Eliminate the cases where an input edge is degenerate. (Note that in 200 // most cases, if CD is degenerate then this method is not even called 201 // because acb and bda have different signs.) 202 if e.a == e.b || e.c == d { 203 return DoNotCross 204 } 205 206 // Otherwise it's time to break out the big guns. 207 if e.acb == Indeterminate { 208 e.acb = -expensiveSign(e.a, e.b, e.c) 209 } 210 if bda == Indeterminate { 211 bda = expensiveSign(e.a, e.b, d) 212 } 213 214 if bda != e.acb { 215 return DoNotCross 216 } 217 218 cbd := -RobustSign(e.c, d, e.b) 219 if cbd != e.acb { 220 return DoNotCross 221 } 222 dac := RobustSign(e.c, d, e.a) 223 if dac != e.acb { 224 return DoNotCross 225 } 226 return Cross 227 }