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
25 type maxDistance s1.ChordAngle
26
27 func (m maxDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) }
28 func (m maxDistance) zero() distance { return maxDistance(s1.StraightChordAngle) }
29 func (m maxDistance) negative() distance { return maxDistance(s1.InfChordAngle()) }
30 func (m maxDistance) infinity() distance { return maxDistance(s1.NegativeChordAngle) }
31 func (m maxDistance) less(other distance) bool { return m.chordAngle() > other.chordAngle() }
32 func (m maxDistance) sub(other distance) distance {
33 return maxDistance(m.chordAngle() + other.chordAngle())
34 }
35 func (m maxDistance) chordAngleBound() s1.ChordAngle {
36 return s1.StraightChordAngle - m.chordAngle()
37 }
38 func (m maxDistance) updateDistance(dist distance) (distance, bool) {
39 if dist.less(m) {
40 m = maxDistance(dist.chordAngle())
41 return m, true
42 }
43 return m, false
44 }
45
46 func (m maxDistance) fromChordAngle(o s1.ChordAngle) distance {
47 return maxDistance(o)
48 }
49
50
51 type MaxDistanceToPointTarget struct {
52 point Point
53 dist distance
54 }
55
56
57 func NewMaxDistanceToPointTarget(point Point) *MaxDistanceToPointTarget {
58 m := maxDistance(0)
59 return &MaxDistanceToPointTarget{point: point, dist: &m}
60 }
61
62 func (m *MaxDistanceToPointTarget) capBound() Cap {
63 return CapFromCenterChordAngle(Point{m.point.Mul(-1)}, (s1.ChordAngle(0)))
64 }
65
66 func (m *MaxDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
67 return dist.updateDistance(maxDistance(ChordAngleBetweenPoints(p, m.point)))
68 }
69
70 func (m *MaxDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
71 if d, ok := UpdateMaxDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok {
72 dist, _ = dist.updateDistance(maxDistance(d))
73 return dist, true
74 }
75 return dist, false
76 }
77
78 func (m *MaxDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
79 return dist.updateDistance(maxDistance(cell.MaxDistance(m.point)))
80 }
81
82 func (m *MaxDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
83
84
85
86 q := NewContainsPointQuery(index, VertexModelSemiOpen)
87 return q.visitContainingShapes(Point{m.point.Mul(-1)}, func(shape Shape) bool {
88 return v(shape, m.point)
89 })
90 }
91
92 func (m *MaxDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
93 func (m *MaxDistanceToPointTarget) maxBruteForceIndexSize() int { return 30 }
94 func (m *MaxDistanceToPointTarget) distance() distance { return m.dist }
95
96
97 type MaxDistanceToEdgeTarget struct {
98 e Edge
99 dist distance
100 }
101
102
103 func NewMaxDistanceToEdgeTarget(e Edge) *MaxDistanceToEdgeTarget {
104 m := maxDistance(0)
105 return &MaxDistanceToEdgeTarget{e: e, dist: m}
106 }
107
108
109
110 func (m *MaxDistanceToEdgeTarget) capBound() Cap {
111
112
113 d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1))
114 r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2))
115 return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Mul(-1).Normalize()}, s1.ChordAngleFromSquaredLength(r2))
116 }
117
118 func (m *MaxDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
119 if d, ok := UpdateMaxDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok {
120 dist, _ = dist.updateDistance(maxDistance(d))
121 return dist, true
122 }
123 return dist, false
124 }
125
126 func (m *MaxDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
127 if d, ok := updateEdgePairMaxDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok {
128 dist, _ = dist.updateDistance(maxDistance(d))
129 return dist, true
130 }
131 return dist, false
132 }
133
134 func (m *MaxDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
135 return dist.updateDistance(maxDistance(cell.MaxDistanceToEdge(m.e.V0, m.e.V1)))
136 }
137
138 func (m *MaxDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
139
140
141
142
143
144
145
146 target := NewMaxDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
147 return target.visitContainingShapes(index, v)
148 }
149
150 func (m *MaxDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
151 func (m *MaxDistanceToEdgeTarget) maxBruteForceIndexSize() int { return 30 }
152 func (m *MaxDistanceToEdgeTarget) distance() distance { return m.dist }
153
154
155 type MaxDistanceToCellTarget struct {
156 cell Cell
157 dist distance
158 }
159
160
161 func NewMaxDistanceToCellTarget(cell Cell) *MaxDistanceToCellTarget {
162 m := maxDistance(0)
163 return &MaxDistanceToCellTarget{cell: cell, dist: m}
164 }
165
166 func (m *MaxDistanceToCellTarget) capBound() Cap {
167 c := m.cell.CapBound()
168 return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius())
169 }
170
171 func (m *MaxDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
172 return dist.updateDistance(maxDistance(m.cell.MaxDistance(p)))
173 }
174
175 func (m *MaxDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
176 return dist.updateDistance(maxDistance(m.cell.MaxDistanceToEdge(edge.V0, edge.V1)))
177 }
178
179 func (m *MaxDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
180 return dist.updateDistance(maxDistance(m.cell.MaxDistanceToCell(cell)))
181 }
182
183 func (m *MaxDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
184
185
186 target := NewMaxDistanceToPointTarget(m.cell.Center())
187 return target.visitContainingShapes(index, v)
188 }
189
190 func (m *MaxDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
191 func (m *MaxDistanceToCellTarget) maxBruteForceIndexSize() int { return 30 }
192 func (m *MaxDistanceToCellTarget) distance() distance { return m.dist }
193
194
195 type MaxDistanceToShapeIndexTarget struct {
196 index *ShapeIndex
197 query *EdgeQuery
198 dist distance
199 }
200
201
202 func NewMaxDistanceToShapeIndexTarget(index *ShapeIndex) *MaxDistanceToShapeIndexTarget {
203 m := maxDistance(0)
204 return &MaxDistanceToShapeIndexTarget{
205 index: index,
206 dist: m,
207 query: NewFurthestEdgeQuery(index, NewFurthestEdgeQueryOptions()),
208 }
209 }
210
211
212
213 func (m *MaxDistanceToShapeIndexTarget) capBound() Cap {
214 c := m.index.Region().CapBound()
215 return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius())
216 }
217
218 func (m *MaxDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
219 m.query.opts.distanceLimit = dist.chordAngle()
220 target := NewMaxDistanceToPointTarget(p)
221 r := m.query.findEdge(target, m.query.opts)
222 if r.shapeID < 0 {
223 return dist, false
224 }
225 return r.distance, true
226 }
227
228 func (m *MaxDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
229 m.query.opts.distanceLimit = dist.chordAngle()
230 target := NewMaxDistanceToEdgeTarget(edge)
231 r := m.query.findEdge(target, m.query.opts)
232 if r.shapeID < 0 {
233 return dist, false
234 }
235 return r.distance, true
236 }
237
238 func (m *MaxDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
239 m.query.opts.distanceLimit = dist.chordAngle()
240 target := NewMaxDistanceToCellTarget(cell)
241 r := m.query.findEdge(target, m.query.opts)
242 if r.shapeID < 0 {
243 return dist, false
244 }
245 return r.distance, true
246 }
247
248
249
250
251
252
253 func (m *MaxDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
254
255
256
257
258
259
260 for _, shape := range m.index.shapes {
261 numChains := shape.NumChains()
262
263 testedPoint := false
264 for c := 0; c < numChains; c++ {
265 chain := shape.Chain(c)
266 if chain.Length == 0 {
267 continue
268 }
269 testedPoint = true
270 target := NewMaxDistanceToPointTarget(shape.ChainEdge(c, 0).V0)
271 if !target.visitContainingShapes(index, v) {
272 return false
273 }
274 }
275 if !testedPoint {
276
277 ref := shape.ReferencePoint()
278 if !ref.Contained {
279 continue
280 }
281 target := NewMaxDistanceToPointTarget(ref.Point)
282 if !target.visitContainingShapes(index, v) {
283 return false
284 }
285 }
286 }
287 return true
288 }
289
290 func (m *MaxDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool {
291 m.query.opts.maxError = maxErr
292 return true
293 }
294 func (m *MaxDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 30 }
295 func (m *MaxDistanceToShapeIndexTarget) distance() distance { return m.dist }
296 func (m *MaxDistanceToShapeIndexTarget) setIncludeInteriors(b bool) {
297 m.query.opts.includeInteriors = b
298 }
299 func (m *MaxDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b }
300
301
302
303
304
View as plain text