From 1cd59749630fe0a040b6767440a30a252344892b Mon Sep 17 00:00:00 2001 From: riquezhang Date: Fri, 20 Dec 2024 09:44:23 +0800 Subject: [PATCH] bugfix: adjust the level of the root when deleting nodes --- rtree.go | 33 ++++++++++++++++++++++++++++++++- rtree_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/rtree.go b/rtree.go index 6db9cfb..069af8b 100644 --- a/rtree.go +++ b/rtree.go @@ -549,7 +549,38 @@ func (tree *Rtree) DeleteWithComparator(obj Spatial, cmp Comparator) bool { tree.condenseTree(n) tree.size-- - if !tree.root.leaf && len(tree.root.entries) == 1 { + /* + when the tree is deep, and deleting nodes, will cause the issue. + the tree could be like this: one obj but 3 levels depth. + { + "size": 1, + "depth": 3, + "root": { + "entries": [ + { + "bb": "[1.00, 2.00]x[1.00, 2.00]", + "child": { + "entries": [ + { + "bb": "[1.00, 2.00]x[1.00, 2.00]", + "child": { + "leaf": true, + "entries": [ + { + "bb": "[1.00, 2.00]x[1.00, 2.00]" + } + ] + } + } + ] + } + } + ] + } + } + so we need to merge the root in loop, instead of once. + */ + for !tree.root.leaf && len(tree.root.entries) == 1 { tree.root = tree.root.entries[0].child } diff --git a/rtree_test.go b/rtree_test.go index cd54d84..2d621de 100644 --- a/rtree_test.go +++ b/rtree_test.go @@ -1371,6 +1371,46 @@ func TestMinMaxDistFloatingPointRoundingError(t *testing.T) { } } +func TestInsertThenDeleteAllInDifferentOrder(t *testing.T) { + rects := []Rect{ + mustRect(Point{1, 1}, []float64{1, 1}), + mustRect(Point{2, 2}, []float64{1, 1}), + mustRect(Point{3, 3}, []float64{1, 1}), + mustRect(Point{4, 4}, []float64{1, 1}), + mustRect(Point{5, 5}, []float64{1, 1}), + } + things := []Spatial{} + for i := range rects { + things = append(things, &rects[i]) + } + + deleteOrders := [][]int{ + {0, 1, 2, 3, 4}, + // in this case, the last delete will cause the issue: no thing but 2 levels depth. + // {"size":0,"depth":2,"root":{"entries":[]}} + {1, 2, 3, 4, 0}, + } + for _, order := range deleteOrders { + rt := NewTree(2, 2, 2) + for _, thing := range things { + rt.Insert(thing) + } + if rt.Size() != 5 { + t.Errorf("Insert failed to insert") + } + + for _, idx := range order { + rt.Delete(things[idx]) + } + if rt.Size() != 0 { + t.Errorf("Delete failed to delete, got size: %d, expected size: 0", rt.Size()) + } + if rt.Depth() != 1 { + t.Errorf("Delete failed to delete, got depth: %d, expected depth: 1", rt.Depth()) + } + } +} + func ensureOrderedSubset(t *testing.T, actual []Spatial, expected []Spatial) { for i := range actual { if len(expected)-1 < i || actual[i] != expected[i] {