-
Notifications
You must be signed in to change notification settings - Fork 0
/
coords.go
108 lines (83 loc) · 2.39 KB
/
coords.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package coords
import (
"fmt"
"sync"
"github.com/paulmach/orb"
"github.com/paulmach/orb/quadtree"
)
type ICoords[V orb.Pointer] interface {
Has(orb.Pointer, quadtree.FilterFunc) bool
Get(orb.Pointer, quadtree.FilterFunc) V
Add(orb.Pointer) error
Remove(orb.Pointer, quadtree.FilterFunc) bool
Replace(orb.Pointer, quadtree.FilterFunc) error
Closest(float64, float64) V
KNearest(orb.Pointer, int, quadtree.FilterFunc, float64) []orb.Pointer
}
type Coords[V orb.Pointer] struct {
ICoords[V]
mutex sync.Mutex
tree *quadtree.Quadtree
}
// CoordsEqualFn must return true if both points are equal
type CoordsEqualFn = func(orb.Pointer, orb.Pointer) bool
func New[V orb.Pointer]() *Coords[V] {
return NewWithBounds[V](orb.Bound{Min: orb.Point{-9_000, -9_000}, Max: orb.Point{11_000, 11_000}})
}
func NewWithBounds[V orb.Pointer](bounds orb.Bound) *Coords[V] {
tree := quadtree.New(bounds)
return &Coords[V]{
mutex: sync.Mutex{},
tree: tree,
}
}
func (p *Coords[V]) Has(point orb.Pointer, fn quadtree.FilterFunc) bool {
p.mutex.Lock()
defer p.mutex.Unlock()
found := p.tree.Matching(point.Point(), fn)
return found != nil
}
func (p *Coords[V]) Get(point orb.Pointer, fn quadtree.FilterFunc) V {
p.mutex.Lock()
defer p.mutex.Unlock()
found := p.tree.Matching(point.Point(), fn)
return found.(V)
}
func (p *Coords[V]) Add(point orb.Pointer) error {
p.mutex.Lock()
defer p.mutex.Unlock()
err := p.tree.Add(point)
return err
}
func (p *Coords[V]) Remove(point orb.Pointer, fn quadtree.FilterFunc) bool {
p.mutex.Lock()
defer p.mutex.Unlock()
ok := p.tree.Remove(point, fn)
return ok
}
func (p *Coords[V]) Replace(point orb.Pointer, fn quadtree.FilterFunc, equalFn CoordsEqualFn) error {
p.mutex.Lock()
defer p.mutex.Unlock()
found := p.tree.Matching(point.Point(), fn)
if found != nil {
if equalFn == nil || !equalFn(point, found) {
p.tree.Remove(point, fn)
}
}
if err := p.tree.Add(point); err != nil {
return fmt.Errorf("failed to replace point in coords. %w", err)
}
return nil
}
func (p *Coords[V]) Closest(x, y float64) V {
p.mutex.Lock()
defer p.mutex.Unlock()
point := p.tree.Find(orb.Point{x, y})
return point.(V)
}
func (p *Coords[V]) KNearest(point orb.Pointer, max int, fn quadtree.FilterFunc, maxDistance float64) []orb.Pointer {
p.mutex.Lock()
defer p.mutex.Unlock()
points := p.tree.KNearestMatching(nil, point.Point(), max, fn, maxDistance)
return points
}