github.com/coyove/common@v0.0.0-20240403014525-f70e643f9de8/quadtree/tree_test.go (about)

     1  package quadtree
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"strconv"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func TestQuadTree(t *testing.T) {
    13  	rand.Seed(time.Now().Unix())
    14  	_tr, _ := NewQuadTree(NewMemoryDatabase(), Pt(-180, 90), Pt(180, -90), func(t *QuadTree) {
    15  		t.MinBox = 3
    16  	})
    17  	tr := func() QuadTree {
    18  		tr, _ := _tr.LoadTree(_tr.ID)
    19  		return tr
    20  	}
    21  
    22  	fmt.Print("find null tree neig: ")
    23  	fmt.Println(tr().FindNeig(Point{}, nil))
    24  
    25  	randPoint := func() Point {
    26  		x := rand.Float64()*360 - 180
    27  		y := rand.Float64()*180 - 90
    28  		if rand.Intn(4) == 0 {
    29  			x = float64(int64(x))
    30  			y = float64(int64(y))
    31  		}
    32  		if rand.Intn(10) == 0 {
    33  			x, y = 0, 0
    34  		}
    35  		return Pt(x, y)
    36  	}
    37  
    38  	start := time.Now()
    39  	m := map[Point]interface{}{}
    40  	allpoints := []Point{}
    41  	for i := 0; i < 1e5; i++ {
    42  		p := randPoint()
    43  		m[p] = i
    44  		tr().Put(p, itob(i))
    45  		allpoints = append(allpoints, p)
    46  	}
    47  
    48  	length := float64(len(m))
    49  	fmt.Println("size:", len(m), time.Since(start).Seconds()/length)
    50  
    51  	start = time.Now()
    52  	idx := 0
    53  	for p, v := range m {
    54  		v2, err := tr().Get(p)
    55  		if err != nil {
    56  			t.Fatal(p, "idx=", idx, "expect=", v, "err=", err)
    57  		}
    58  		if btoi(v2.Data) != v {
    59  			t.Fatal(p, idx, "got:", v2.Data, "expect:", v)
    60  		}
    61  		idx++
    62  	}
    63  	fmt.Println(time.Since(start).Seconds() / length)
    64  	// fmt.Println(tr())
    65  	rp := allpoints[rand.Intn(len(allpoints))]
    66  	fmt.Print("rand point=", rp, " neighbours=")
    67  	nn, _ := tr().FindNeig(rp, nil)
    68  	fmt.Println(len(nn))
    69  }
    70  
    71  func TestQuadTreeConcurrent(t *testing.T) {
    72  	rand.Seed(time.Now().Unix())
    73  	_tr, _ := NewQuadTree(NewMemoryDatabase(), Pt(-10, 10), Pt(10, -10), nil)
    74  	tr := func() QuadTree {
    75  		tr, _ := _tr.LoadTree(_tr.ID)
    76  		return tr
    77  	}
    78  
    79  	randPoint := func() Point {
    80  		x := rand.Float64()*5 - 10
    81  		y := rand.Float64()*5 - 10
    82  		if rand.Intn(4) == 0 {
    83  			x = float64(int64(x))
    84  			y = float64(int64(y))
    85  		}
    86  		if rand.Intn(10) == 0 {
    87  			x, y = 0, 0
    88  		}
    89  		return Pt(x, y)
    90  	}
    91  
    92  	m := map[Point]interface{}{}
    93  	mu := sync.Mutex{}
    94  	allpoints := []Point{}
    95  
    96  	wait := sync.WaitGroup{}
    97  	for i := 0; i < 50; i++ {
    98  		wait.Add(1)
    99  		go func(i int) {
   100  			p := randPoint()
   101  			tr().Put(p, itob(i))
   102  
   103  			mu.Lock()
   104  			m[p] = i
   105  			allpoints = append(allpoints, p)
   106  			mu.Unlock()
   107  			wait.Done()
   108  		}(i)
   109  	}
   110  	wait.Wait()
   111  
   112  	depth, nodes, _ := tr().MaxDepth()
   113  	fmt.Println("size:", len(m), "tree-depth=", depth, "tree-leaves=", nodes)
   114  
   115  	idx := 0
   116  	for p, v := range m {
   117  		v2, err := tr().Get(p)
   118  		if err != nil {
   119  			t.Log(p, "tree=", tr(), "idx=", idx, "expect=", v, "err=", err)
   120  		}
   121  		if btoi(v2.Data) != v {
   122  			t.Log(p, idx, "got:", v2.Data, "expect:", v)
   123  		}
   124  		idx++
   125  	}
   126  	// fmt.Println(tr())
   127  	rp := allpoints[rand.Intn(len(allpoints))]
   128  	fmt.Print("rand point=", rp, " neigbours=")
   129  	fmt.Println(tr().FindNeig(rp, nil))
   130  
   131  	dedup := map[Point]bool{}
   132  	fmt.Println("iterate result:", tr().Iterate(func(e Element) error {
   133  		if dedup[e.Point] {
   134  			t.Fatal("dedup", e.Point)
   135  		}
   136  		dedup[e.Point] = true
   137  		return nil
   138  	}))
   139  }
   140  
   141  func TestQuadTreeNeigSimple(t *testing.T) {
   142  	_tr, _ := NewQuadTree(NewMemoryDatabase(), Pt(-10, 10), Pt(10, -10), func(t *QuadTree) {
   143  		t.MinBox = 0.5
   144  	})
   145  	tr := func() QuadTree {
   146  		tr, _ := _tr.LoadTree(_tr.ID)
   147  		return tr
   148  	}
   149  	tr().Put(Pt(1, 1), itob(1))
   150  	tr().Put(Pt(-1, 1), itob(2))
   151  	fmt.Println(tr().FindNeig(Point{0, 0}, nil))
   152  	tr().Put(Pt(-1, -1), itob(3))
   153  	tr().Put(Pt(1, -1), itob(4))
   154  	fmt.Println(tr().FindNeig(Pt(0.1, 0.1), nil)) // 1 should be the first
   155  	fmt.Println(tr())
   156  
   157  	MaxElems = 4
   158  	for i := 0; i < 100; i++ {
   159  		tr().Put(Pt(10-float64(i)*0.01, 10-float64(i)*0.01), itob(i))
   160  	}
   161  
   162  	// 100 points inside (9,9)-(10,10)
   163  	// root:  (-10,-10)-(10,10)
   164  	// 0:     (0,0)-(10,10)
   165  	// 00:    (5,5)-(10,10)
   166  	// 000:   (7.5,7.5)-(10,10)
   167  	// 0000:  (8.75,8.75)-(10,10)
   168  	// 00000: (>9,>9),(10,10)
   169  	d, _, _ := tr().MaxDepth()
   170  	if d != 6 {
   171  		t.Fatal(d, tr())
   172  	}
   173  }
   174  
   175  func TestPrintQuadFSM(t *testing.T) {
   176  	for _, d := range []string{"u", "d", "l", "r", "ul", "ur", "dl", "dr"} {
   177  		for i := 0; i < 4; i++ {
   178  			o, d := walkFSM(byte(i), d)
   179  			fmt.Printf("% 2s: %d ", d, o)
   180  		}
   181  		fmt.Println()
   182  	}
   183  }
   184  
   185  func itob(i int) []byte { return []byte(strconv.Itoa(i)) }
   186  
   187  func btoi(b []byte) int { i, _ := strconv.Atoi(string(b)); return i }