Skip to content

Commit

Permalink
fix minMaxDist floating point rounding errors
Browse files Browse the repository at this point in the history
This manifests itsef in

#29
  • Loading branch information
fumin committed Feb 17, 2024
1 parent b0f9edc commit c5756f7
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
15 changes: 10 additions & 5 deletions rtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,21 @@ type Rtree struct {
// deleted is a temporary buffer to avoid memory allocations in Delete.
// It is just an optimization and not part of the data structure.
deleted []*node

// FloatingPointTolerance is the tolerance to guard against floating point rounding errors during minMaxDist calculations.
FloatingPointTolerance float64
}

// NewTree returns an Rtree. If the number of objects given on initialization
// is larger than max, the Rtree will be initialized using the Overlap
// Minimizing Top-down bulk-loading algorithm.
func NewTree(dim, min, max int, objs ...Spatial) *Rtree {
rt := &Rtree{
Dim: dim,
MinChildren: min,
MaxChildren: max,
height: 1,
Dim: dim,
MinChildren: min,
MaxChildren: max,
height: 1,
FloatingPointTolerance: 1e-6,
root: &node{
entries: []entry{},
leaf: true,
Expand Down Expand Up @@ -765,7 +769,8 @@ func (tree *Rtree) nearestNeighbor(p Point, n *node, d float64, nearest Spatial)

for _, e := range n.entries {
minDist := p.minDist(e.bb)
if minDist > minMinMaxDist {
// Add a bit of tolerance to guard against floating point rounding errors.
if minDist > minMinMaxDist+tree.FloatingPointTolerance {
continue
}

Expand Down
18 changes: 18 additions & 0 deletions rtree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,24 @@ func TestNearestNeighborsHalf(t *testing.T) {
}
}

func TestMinMaxDistFloatingPointRoundingError(t *testing.T) {
rects := []Rect{
Point{1134900, 15600}.ToRect(0),
Point{1134900, 25600}.ToRect(0),
Point{1134900, 22805}.ToRect(0),
Point{1134900, 29116}.ToRect(0),
}
things := make([]Spatial, 0, len(rects))
for i := range rects {
things = append(things, &rects[i])
}
rt := NewTree(2, 1, 2, things...)
n := rt.NearestNeighbor(Point{1134851.8, 25570.8})
if n != things[1] {
t.Fatalf("wrong neighbor, expected %v, got %v", things[1], n)
}
}

func ensureOrderedSubset(t *testing.T, actual []Spatial, expected []Spatial) {
for i := range actual {
if len(expected)-1 < i || actual[i] != expected[i] {
Expand Down

0 comments on commit c5756f7

Please sign in to comment.