github.com/richardwilkes/toolbox@v1.121.0/collection/quadtree/quadtree_test.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package quadtree_test 11 12 import ( 13 "math/rand/v2" 14 "slices" 15 "testing" 16 17 "github.com/richardwilkes/toolbox/check" 18 "github.com/richardwilkes/toolbox/collection/quadtree" 19 "github.com/richardwilkes/toolbox/xmath/geom" 20 "golang.org/x/exp/constraints" 21 ) 22 23 type node[T constraints.Float] struct { 24 geom.Rect[T] 25 } 26 27 func newNode[T constraints.Float](x, y, width, height T) *node[T] { 28 return &node[T]{Rect: geom.NewRect(x, y, width, height)} 29 } 30 31 func (n node[T]) Bounds() geom.Rect[T] { 32 return n.Rect 33 } 34 35 func TestContainsPoint(t *testing.T) { 36 q := &quadtree.QuadTree[float64, *node[float64]]{} 37 check.False(t, q.ContainsPoint(geom.Point[float64]{})) 38 q.Insert(newNode[float64](5, 5, 5, 5)) 39 check.False(t, q.ContainsPoint(geom.NewPoint[float64](6, 4))) 40 check.True(t, q.ContainsPoint(geom.NewPoint[float64](5, 5))) 41 check.True(t, q.ContainsPoint(geom.NewPoint[float64](9.9, 9.9))) 42 check.False(t, q.ContainsPoint(geom.NewPoint[float64](10, 10))) 43 q.Insert(newNode[float64](4, 4, 3, 3)) 44 check.True(t, q.ContainsPoint(geom.NewPoint[float64](6, 4))) 45 for i := 0; i < 2*quadtree.DefaultQuadTreeThreshold; i++ { 46 q.Insert(newNode(float64(i), -5, 10, 10)) 47 } 48 check.True(t, q.ContainsPoint(geom.Point[float64]{})) 49 check.True(t, q.ContainsPoint(geom.NewPoint[float64](0, -5))) 50 check.False(t, q.ContainsPoint(geom.NewPoint[float64](-1, 0))) 51 } 52 53 func TestContainsRect(t *testing.T) { 54 q := &quadtree.QuadTree[float64, *node[float64]]{} 55 check.False(t, q.ContainsRect(geom.NewRect[float64](0, 0, 1, 1))) 56 q.Insert(newNode[float64](5, 5, 5, 5)) 57 check.False(t, q.ContainsRect(geom.NewRect[float64](4, 4, 10, 10))) 58 check.True(t, q.ContainsRect(geom.NewRect[float64](5, 5, 2, 2))) 59 check.True(t, q.ContainsRect(geom.NewRect[float64](9.9, 9.9, .05, .05))) 60 check.False(t, q.ContainsRect(geom.NewRect[float64](10, 10, 5, 5))) 61 q.Insert(newNode[float64](4, 4, 3, 3)) 62 check.True(t, q.ContainsRect(geom.NewRect[float64](6, 4, 1, 2))) 63 for i := 0; i < 2*quadtree.DefaultQuadTreeThreshold; i++ { 64 q.Insert(newNode(float64(i), -5, 10, 10)) 65 } 66 check.True(t, q.ContainsRect(geom.NewRect[float64](0, 0, 1, 1))) 67 check.True(t, q.ContainsRect(geom.NewRect[float64](0, -5, 4, 4))) 68 check.False(t, q.ContainsRect(geom.NewRect[float64](-1, 0, 2, 2))) 69 } 70 71 func TestGeneral(t *testing.T) { 72 q := &quadtree.QuadTree[float64, *node[float64]]{} 73 r := rand.New(rand.NewPCG(22, 1967)) //nolint:gosec // Yes, it is ok to use a weak prng here 74 mine := newNode[float64](22, 22, 22, 22) 75 q.Insert(mine) 76 for i := 0; i < 100*quadtree.DefaultQuadTreeThreshold; i++ { 77 q.Insert(newNode(float64(50000-r.IntN(100000)), float64(50000-r.IntN(100000)), float64(r.IntN(100000)), float64(r.IntN(100000)))) 78 } 79 check.Equal(t, 1+100*quadtree.DefaultQuadTreeThreshold, q.Size()) 80 all := q.All() 81 check.True(t, slices.Contains(all, mine)) 82 count := q.Size() 83 for _, one := range all { 84 if one != mine && r.IntN(10) == 1 { 85 q.Remove(one) 86 count-- 87 check.Equal(t, count, q.Size()) 88 } 89 } 90 check.Equal(t, count, q.Size()) 91 q.Reorganize() 92 check.Equal(t, count, q.Size()) 93 check.True(t, slices.Contains(q.All(), mine)) 94 check.True(t, slices.Contains(q.FindContainedByRect(mine.Rect), mine)) 95 }