tile38/pkg/index/index.go

96 lines
2.1 KiB
Go

package index
import (
"github.com/tidwall/boxtree/d2"
)
// Index is a geospatial index
type Index struct {
r d2.BoxTree
}
// New create a new index
func New() *Index {
return &Index{}
}
// Item represents an index item.
type Item interface {
Point() (x, y float64)
Rect() (minX, minY, maxX, maxY float64)
}
// FlexItem can represent a point or a rectangle
type FlexItem struct {
MinX, MinY, MaxX, MaxY float64
}
// Rect returns the rectangle
func (item *FlexItem) Rect() (minX, minY, maxX, maxY float64) {
return item.MinX, item.MinY, item.MaxX, item.MaxY
}
// Point returns the point
func (item *FlexItem) Point() (x, y float64) {
return item.MinX, item.MinY
}
// Insert inserts an item into the index
func (ix *Index) Insert(item Item) {
minX, minY, maxX, maxY := item.Rect()
ix.r.Insert([]float64{minX, minY}, []float64{maxX, maxY}, item)
}
// Remove removed an item from the index
func (ix *Index) Remove(item Item) {
minX, minY, maxX, maxY := item.Rect()
ix.r.Delete([]float64{minX, minY}, []float64{maxX, maxY}, item)
}
// Count counts all items in the index.
func (ix *Index) Count() int {
return ix.r.Count()
}
// Bounds returns the minimum bounding rectangle of all items in the index.
func (ix *Index) Bounds() (MinX, MinY, MaxX, MaxY float64) {
min, max := ix.r.Bounds()
return min[0], min[1], max[0], max[1]
}
// RemoveAll removes all items from the index.
func (ix *Index) RemoveAll() {
ix.r = d2.BoxTree{}
}
// KNN returns the nearsest neighbors
func (ix *Index) KNN(x, y float64, iterator func(item interface{}) bool) bool {
res := true
ix.r.Nearby([]float64{x, y}, []float64{x, y},
func(_, _ []float64, item interface{}) bool {
if !iterator(item) {
res = false
return false
}
return true
})
return res
}
// Search returns all items that intersect the bounding box.
func (ix *Index) Search(minX, minY, maxX, maxY float64,
iterator func(item interface{}) bool,
) bool {
res := true
ix.r.Search([]float64{minX, minY}, []float64{maxX, maxY},
func(_, _ []float64, item interface{}) bool {
if !iterator(item) {
res = false
return false
}
return true
})
return res
}