1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package s2
16
17 import (
18 "math"
19
20 "github.com/golang/geo/s1"
21 )
22
23
24 type minDistance s1.ChordAngle
25
26 func (m minDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) }
27 func (m minDistance) zero() distance { return minDistance(0) }
28 func (m minDistance) negative() distance { return minDistance(s1.NegativeChordAngle) }
29 func (m minDistance) infinity() distance { return minDistance(s1.InfChordAngle()) }
30 func (m minDistance) less(other distance) bool { return m.chordAngle() < other.chordAngle() }
31 func (m minDistance) sub(other distance) distance {
32 return minDistance(m.chordAngle() - other.chordAngle())
33 }
34 func (m minDistance) chordAngleBound() s1.ChordAngle {
35 return m.chordAngle().Expanded(m.chordAngle().MaxAngleError())
36 }
37
38
39
40 func (m minDistance) updateDistance(dist distance) (distance, bool) {
41 if dist.less(m) {
42 m = minDistance(dist.chordAngle())
43 return m, true
44 }
45 return m, false
46 }
47
48 func (m minDistance) fromChordAngle(o s1.ChordAngle) distance {
49 return minDistance(o)
50 }
51
52
53 type MinDistanceToPointTarget struct {
54 point Point
55 dist distance
56 }
57
58
59 func NewMinDistanceToPointTarget(point Point) *MinDistanceToPointTarget {
60 m := minDistance(0)
61 return &MinDistanceToPointTarget{point: point, dist: &m}
62 }
63
64 func (m *MinDistanceToPointTarget) capBound() Cap {
65 return CapFromCenterChordAngle(m.point, s1.ChordAngle(0))
66 }
67
68 func (m *MinDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
69 var ok bool
70 dist, ok = dist.updateDistance(minDistance(ChordAngleBetweenPoints(p, m.point)))
71 return dist, ok
72 }
73
74 func (m *MinDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
75 if d, ok := UpdateMinDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok {
76 dist, _ = dist.updateDistance(minDistance(d))
77 return dist, true
78 }
79 return dist, false
80 }
81
82 func (m *MinDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
83 var ok bool
84 dist, ok = dist.updateDistance(minDistance(cell.Distance(m.point)))
85 return dist, ok
86 }
87
88 func (m *MinDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
89
90
91
92 q := NewContainsPointQuery(index, VertexModelSemiOpen)
93 return q.visitContainingShapes(m.point, func(shape Shape) bool {
94 return v(shape, m.point)
95 })
96 }
97
98 func (m *MinDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
99 func (m *MinDistanceToPointTarget) maxBruteForceIndexSize() int { return 30 }
100 func (m *MinDistanceToPointTarget) distance() distance { return m.dist }
101
102
103
104
105 type MinDistanceToEdgeTarget struct {
106 e Edge
107 dist distance
108 }
109
110
111 func NewMinDistanceToEdgeTarget(e Edge) *MinDistanceToEdgeTarget {
112 m := minDistance(0)
113 return &MinDistanceToEdgeTarget{e: e, dist: m}
114 }
115
116
117
118 func (m *MinDistanceToEdgeTarget) capBound() Cap {
119
120
121 d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1))
122 r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2))
123 return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}, s1.ChordAngleFromSquaredLength(r2))
124 }
125
126 func (m *MinDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
127 if d, ok := UpdateMinDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok {
128 dist, _ = dist.updateDistance(minDistance(d))
129 return dist, true
130 }
131 return dist, false
132 }
133
134 func (m *MinDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
135 if d, ok := updateEdgePairMinDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok {
136 dist, _ = dist.updateDistance(minDistance(d))
137 return dist, true
138 }
139 return dist, false
140 }
141
142 func (m *MinDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
143 return dist.updateDistance(minDistance(cell.DistanceToEdge(m.e.V0, m.e.V1)))
144 }
145
146 func (m *MinDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
147
148
149
150
151 target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
152 return target.visitContainingShapes(index, v)
153 }
154
155 func (m *MinDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
156 func (m *MinDistanceToEdgeTarget) maxBruteForceIndexSize() int { return 30 }
157 func (m *MinDistanceToEdgeTarget) distance() distance { return m.dist }
158
159
160
161
162 type MinDistanceToCellTarget struct {
163 cell Cell
164 dist distance
165 }
166
167
168 func NewMinDistanceToCellTarget(cell Cell) *MinDistanceToCellTarget {
169 m := minDistance(0)
170 return &MinDistanceToCellTarget{cell: cell, dist: m}
171 }
172
173 func (m *MinDistanceToCellTarget) capBound() Cap {
174 return m.cell.CapBound()
175 }
176
177 func (m *MinDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
178 return dist.updateDistance(minDistance(m.cell.Distance(p)))
179 }
180
181 func (m *MinDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
182 return dist.updateDistance(minDistance(m.cell.DistanceToEdge(edge.V0, edge.V1)))
183 }
184
185 func (m *MinDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
186 return dist.updateDistance(minDistance(m.cell.DistanceToCell(cell)))
187 }
188
189 func (m *MinDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
190
191
192
193
194
195
196
197
198 target := NewMinDistanceToPointTarget(m.cell.Center())
199 return target.visitContainingShapes(index, v)
200 }
201 func (m *MinDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
202 func (m *MinDistanceToCellTarget) maxBruteForceIndexSize() int { return 30 }
203 func (m *MinDistanceToCellTarget) distance() distance { return m.dist }
204
205
206
207
250
251
252
253
254 type MinDistanceToShapeIndexTarget struct {
255 index *ShapeIndex
256 query *EdgeQuery
257 dist distance
258 }
259
260
261 func NewMinDistanceToShapeIndexTarget(index *ShapeIndex) *MinDistanceToShapeIndexTarget {
262 m := minDistance(0)
263 return &MinDistanceToShapeIndexTarget{
264 index: index,
265 dist: m,
266 query: NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions()),
267 }
268 }
269
270 func (m *MinDistanceToShapeIndexTarget) capBound() Cap {
271 c := m.index.Region().CapBound()
272 return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius())
273 }
274
275 func (m *MinDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
276 m.query.opts.distanceLimit = dist.chordAngle()
277 target := NewMinDistanceToPointTarget(p)
278 r := m.query.findEdge(target, m.query.opts)
279 if r.shapeID < 0 {
280 return dist, false
281 }
282 return r.distance, true
283 }
284
285 func (m *MinDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
286 m.query.opts.distanceLimit = dist.chordAngle()
287 target := NewMinDistanceToEdgeTarget(edge)
288 r := m.query.findEdge(target, m.query.opts)
289 if r.shapeID < 0 {
290 return dist, false
291 }
292 return r.distance, true
293 }
294
295 func (m *MinDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
296 m.query.opts.distanceLimit = dist.chordAngle()
297 target := NewMinDistanceToCellTarget(cell)
298 r := m.query.findEdge(target, m.query.opts)
299 if r.shapeID < 0 {
300 return dist, false
301 }
302 return r.distance, true
303 }
304
305
306
307
308
309
310 func (m *MinDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
311
312
313
314
315
316 for _, shape := range m.index.shapes {
317 numChains := shape.NumChains()
318
319 testedPoint := false
320 for c := 0; c < numChains; c++ {
321 chain := shape.Chain(c)
322 if chain.Length == 0 {
323 continue
324 }
325 testedPoint = true
326 target := NewMinDistanceToPointTarget(shape.ChainEdge(c, 0).V0)
327 if !target.visitContainingShapes(index, v) {
328 return false
329 }
330 }
331 if !testedPoint {
332
333 ref := shape.ReferencePoint()
334 if !ref.Contained {
335 continue
336 }
337 target := NewMinDistanceToPointTarget(ref.Point)
338 if !target.visitContainingShapes(index, v) {
339 return false
340 }
341 }
342 }
343 return true
344 }
345
346 func (m *MinDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool {
347 m.query.opts.maxError = maxErr
348 return true
349 }
350 func (m *MinDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 25 }
351 func (m *MinDistanceToShapeIndexTarget) distance() distance { return m.dist }
352 func (m *MinDistanceToShapeIndexTarget) setIncludeInteriors(b bool) {
353 m.query.opts.includeInteriors = b
354 }
355 func (m *MinDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b }
356
357
358
359
360
View as plain text