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 }