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  }