diff --git a/Gopkg.lock b/Gopkg.lock index 4ab4f9fc..e80a58d6 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -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" diff --git a/vendor/github.com/tidwall/geoindex/geoindex.go b/vendor/github.com/tidwall/geoindex/geoindex.go index 9dfc67bf..76420954 100644 --- a/vendor/github.com/tidwall/geoindex/geoindex.go +++ b/vendor/github.com/tidwall/geoindex/geoindex.go @@ -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 } @@ -128,9 +147,8 @@ func (index *Index) Bounds() (min, max [2]float64) { // Priority Queue ordered by dist (smallest to largest) type qnode struct { - dist float64 - child child.Child - filled bool + dist float64 + child child.Child } 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)) } } diff --git a/vendor/github.com/tidwall/geoindex/geoindex_test.go b/vendor/github.com/tidwall/geoindex/geoindex_test.go index d67a3b64..939c98c4 100644 --- a/vendor/github.com/tidwall/geoindex/geoindex_test.go +++ b/vendor/github.com/tidwall/geoindex/geoindex_test.go @@ -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) {