mirror of https://github.com/tidwall/tile38.git
Updated geoindex
This commit is contained in:
parent
639f6e2deb
commit
5abadd72a3
|
@ -213,15 +213,15 @@
|
|||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4305de55e110aa13ec68a246b12e512041fe92440e78066fcea93ecf2a68320b"
|
||||
digest = "1:eab1a01c55a3428f83e16e92f902ffbeae143e19e080a6a1117532f7908f7579"
|
||||
name = "github.com/tidwall/geoindex"
|
||||
packages = [
|
||||
".",
|
||||
"child",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "e56705dcd2788d8eb431e8cb15295bfd0a298976"
|
||||
version = "v1.0.1"
|
||||
revision = "6fc1984907cad925af47d09fdc0cadc70f875cfe"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ddb305f09be3613fd1bf9fd8d6d0713f2fd28b5af596437b3d7de2366bbee870"
|
||||
|
|
|
@ -73,31 +73,50 @@ func (index *Index) Children(parent interface{}, reuse []child.Child) (
|
|||
return index.tree.Children(parent, reuse)
|
||||
}
|
||||
|
||||
// Nearby performs a kNN-type operation on the index. It's expected that the
|
||||
// caller provides the `dist` function, which is used to calculate the
|
||||
// distance from a node or item to another object. The other object is unknown
|
||||
// this operation, but is expected to be known by the caller. The iter will
|
||||
// return all items from the smallest dist to the largest dist.
|
||||
// Nearby performs a kNN-type operation on the index.
|
||||
// It's expected that the caller provides its own the `algo` function, which
|
||||
// is used to calculate a distance to data. The `add` function should be
|
||||
// called by the caller to "return" the data item along with a distance.
|
||||
// The `iter` function will return all items from the smallest dist to the
|
||||
// largest dist.
|
||||
// Take a look at the SimpleBoxAlgo function for a usage example.
|
||||
func (index *Index) Nearby(
|
||||
algo func(min, max [2]float64, data interface{}, item bool) (dist float64),
|
||||
algo func(
|
||||
min, max [2]float64, data interface{}, item bool,
|
||||
add func(min, max [2]float64, data interface{}, item bool, dist float64),
|
||||
),
|
||||
iter func(min, max [2]float64, data interface{}, dist float64) bool,
|
||||
) {
|
||||
var q queue
|
||||
var parent interface{}
|
||||
var children []child.Child
|
||||
|
||||
var added []qnode
|
||||
add := func(min, max [2]float64, data interface{}, item bool, dist float64) {
|
||||
added = append(added, qnode{
|
||||
dist: dist,
|
||||
child: child.Child{
|
||||
Data: data,
|
||||
Min: min,
|
||||
Max: max,
|
||||
Item: item,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for {
|
||||
// gather all children for parent
|
||||
children = index.tree.Children(parent, children[:0])
|
||||
for _, child := range children {
|
||||
q.push(qnode{
|
||||
dist: algo(child.Min, child.Max, child.Data, child.Item),
|
||||
child: child,
|
||||
filled: true,
|
||||
})
|
||||
added = added[:0]
|
||||
algo(child.Min, child.Max, child.Data, child.Item, add)
|
||||
for _, node := range added {
|
||||
q.push(node)
|
||||
}
|
||||
}
|
||||
for {
|
||||
node := q.pop()
|
||||
if !node.filled {
|
||||
node, ok := q.pop()
|
||||
if !ok {
|
||||
// nothing left in queue
|
||||
return
|
||||
}
|
||||
|
@ -130,7 +149,6 @@ func (index *Index) Bounds() (min, max [2]float64) {
|
|||
type qnode struct {
|
||||
dist float64
|
||||
child child.Child
|
||||
filled bool
|
||||
}
|
||||
|
||||
type queue struct {
|
||||
|
@ -156,9 +174,9 @@ func (q *queue) push(node qnode) {
|
|||
q.len++
|
||||
}
|
||||
|
||||
func (q *queue) pop() qnode {
|
||||
func (q *queue) pop() (qnode, bool) {
|
||||
if q.len == 0 {
|
||||
return qnode{}
|
||||
return qnode{}, false
|
||||
}
|
||||
n := q.nodes[1]
|
||||
q.nodes[1] = q.nodes[q.len]
|
||||
|
@ -177,7 +195,7 @@ func (q *queue) pop() qnode {
|
|||
q.nodes[i] = q.nodes[k]
|
||||
i = k
|
||||
}
|
||||
return n
|
||||
return n, true
|
||||
}
|
||||
|
||||
// Scan iterates through all data in tree in no specified order.
|
||||
|
@ -187,12 +205,18 @@ func (index *Index) Scan(
|
|||
index.tree.Scan(iter)
|
||||
}
|
||||
|
||||
// SimpleBoxAlgo ...
|
||||
// SimpleBoxAlgo performs box-distance algorithm on rectangles.
|
||||
func SimpleBoxAlgo(targetMin, targetMax [2]float64) (
|
||||
dist func(min, max [2]float64, data interface{}, item bool) (dist float64),
|
||||
algo func(
|
||||
min, max [2]float64, data interface{}, item bool,
|
||||
add func(min, max [2]float64, data interface{}, item bool, dist float64),
|
||||
),
|
||||
) {
|
||||
return func(min, max [2]float64, data interface{}, item bool) float64 {
|
||||
return boxDist(targetMin, targetMax, min, max)
|
||||
return func(
|
||||
min, max [2]float64, data interface{}, item bool,
|
||||
add func(min, max [2]float64, data interface{}, item bool, dist float64),
|
||||
) {
|
||||
add(min, max, data, item, boxDist(targetMin, targetMax, min, max))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -314,6 +314,41 @@ func testBoxesVarious(t *testing.T, boxes []tBox, label string) {
|
|||
ldist = dist
|
||||
}
|
||||
|
||||
// test bounds
|
||||
min := boxes3[0].min
|
||||
max := boxes3[0].max
|
||||
for _, box := range boxes3 {
|
||||
if box.min[0] < min[0] {
|
||||
min[0] = box.min[0]
|
||||
}
|
||||
if box.min[1] < min[1] {
|
||||
min[1] = box.min[1]
|
||||
}
|
||||
if box.max[0] > max[0] {
|
||||
max[0] = box.max[0]
|
||||
}
|
||||
if box.max[1] > max[1] {
|
||||
max[1] = box.max[1]
|
||||
}
|
||||
}
|
||||
min2, max2 := tr.Bounds()
|
||||
if min2 != min || max2 != max {
|
||||
t.Fatalf("expected %v,%v, got %v,%v", min, max, min2, max2)
|
||||
}
|
||||
|
||||
// test nearby, but stop after one
|
||||
var one tBox
|
||||
tr.Nearby(
|
||||
SimpleBoxAlgo(centerMin, centerMax),
|
||||
func(min, max [2]float64, value interface{}, dist float64) bool {
|
||||
one = value.(tBox)
|
||||
return false
|
||||
},
|
||||
)
|
||||
if one != boxes3[0] {
|
||||
t.Fatalf("expected %v, got %v", boxes[0], one)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRandomBoxes(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue