github.com/richardwilkes/toolbox@v1.121.0/collection/quadtree/node.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 11 12 import ( 13 "github.com/richardwilkes/toolbox/xmath" 14 "github.com/richardwilkes/toolbox/xmath/geom" 15 ) 16 17 type node[T xmath.Numeric, N Node[T]] struct { 18 rect geom.Rect[T] 19 children [4]*node[T, N] 20 contents []N 21 threshold int 22 } 23 24 func (n *node[T, N]) Bounds() geom.Rect[T] { 25 return n.rect 26 } 27 28 func (n *node[T, N]) all(result []N) []N { 29 result = append(result, n.contents...) 30 if !n.isLeaf() { 31 for _, child := range n.children { 32 result = child.all(result) 33 } 34 } 35 return result 36 } 37 38 func (n *node[T, N]) isLeaf() bool { 39 return n.children[0] == nil 40 } 41 42 func (n *node[T, N]) insert(obj N) { 43 n.splitIfNeeded() 44 if !n.isLeaf() { 45 rect := obj.Bounds() 46 for _, child := range n.children { 47 if child.rect.Contains(rect) { 48 child.insert(obj) 49 return 50 } 51 } 52 } 53 n.contents = append(n.contents, obj) 54 } 55 56 func (n *node[T, N]) remove(obj N) bool { 57 for i, one := range n.contents { 58 if one != obj { 59 continue 60 } 61 n.contents[i] = n.contents[len(n.contents)-1] 62 var zero N 63 n.contents[len(n.contents)-1] = zero 64 n.contents = n.contents[:len(n.contents)-1] 65 return true 66 } 67 if !n.isLeaf() && n.rect.Contains(obj.Bounds()) { 68 for _, child := range n.children { 69 if child.remove(obj) { 70 return true 71 } 72 } 73 } 74 return false 75 } 76 77 func (n *node[T, N]) splitIfNeeded() { 78 if n.isLeaf() { 79 if len(n.contents) >= n.threshold { 80 hw := n.rect.Width / 2 81 hh := n.rect.Height / 2 82 n.children[0] = &node[T, N]{ 83 rect: geom.Rect[T]{ 84 Point: n.rect.Point, 85 Size: geom.NewSize[T](hw, hw), 86 }, 87 threshold: n.threshold, 88 } 89 n.children[1] = &node[T, N]{ 90 rect: geom.NewRect[T](n.rect.X+hw, n.rect.Y, n.rect.Width-hw, hh), 91 threshold: n.threshold, 92 } 93 n.children[2] = &node[T, N]{ 94 rect: geom.NewRect[T](n.rect.X, n.rect.Y+hh, hw, n.rect.Height-hh), 95 threshold: n.threshold, 96 } 97 n.children[3] = &node[T, N]{ 98 rect: geom.NewRect[T](n.rect.X+hw, n.rect.Y+hh, n.rect.Width-hw, n.rect.Height-hh), 99 threshold: n.threshold, 100 } 101 contents := n.contents 102 n.contents = nil 103 for _, one := range contents { 104 n.insert(one) 105 } 106 } 107 } 108 } 109 110 func (n *node[T, N]) containsPoint(pt geom.Point[T]) bool { 111 if pt.In(n.rect) { 112 for _, one := range n.contents { 113 if pt.In(one.Bounds()) { 114 return true 115 } 116 } 117 if !n.isLeaf() { 118 for _, one := range n.children { 119 if one.containsPoint(pt) { 120 return true 121 } 122 } 123 } 124 } 125 return false 126 } 127 128 func (n *node[T, N]) findContainsPoint(pt geom.Point[T], result []N) []N { 129 if pt.In(n.rect) { 130 for _, one := range n.contents { 131 if pt.In(one.Bounds()) { 132 result = append(result, one) 133 } 134 } 135 if !n.isLeaf() { 136 for _, one := range n.children { 137 result = one.findContainsPoint(pt, result) 138 } 139 } 140 } 141 return result 142 } 143 144 func (n *node[T, N]) matchedContainsPoint(matcher Matcher[T, N], pt geom.Point[T]) bool { 145 if pt.In(n.rect) { 146 for _, one := range n.contents { 147 if pt.In(one.Bounds()) && matcher.Matches(one) { 148 return true 149 } 150 } 151 if !n.isLeaf() { 152 for _, one := range n.children { 153 if one.matchedContainsPoint(matcher, pt) { 154 return true 155 } 156 } 157 } 158 } 159 return false 160 } 161 162 func (n *node[T, N]) findMatchedContainsPoint(matcher Matcher[T, N], pt geom.Point[T], result []N) []N { 163 if pt.In(n.rect) { 164 for _, one := range n.contents { 165 if pt.In(one.Bounds()) && matcher.Matches(one) { 166 result = append(result, one) 167 } 168 } 169 if !n.isLeaf() { 170 for _, one := range n.children { 171 result = one.findMatchedContainsPoint(matcher, pt, result) 172 } 173 } 174 } 175 return result 176 } 177 178 func (n *node[T, N]) intersects(rect geom.Rect[T]) bool { 179 if n.rect.Intersects(rect) { 180 for _, one := range n.contents { 181 if one.Bounds().Intersects(rect) { 182 return true 183 } 184 } 185 if !n.isLeaf() { 186 for _, one := range n.children { 187 if one.intersects(rect) { 188 return true 189 } 190 } 191 } 192 } 193 return false 194 } 195 196 func (n *node[T, N]) findIntersects(rect geom.Rect[T], result []N) []N { 197 if n.rect.Intersects(rect) { 198 for _, one := range n.contents { 199 if one.Bounds().Intersects(rect) { 200 result = append(result, one) 201 } 202 } 203 if !n.isLeaf() { 204 for _, one := range n.children { 205 result = one.findIntersects(rect, result) 206 } 207 } 208 } 209 return result 210 } 211 212 func (n *node[T, N]) matchedIntersects(matcher Matcher[T, N], rect geom.Rect[T]) bool { 213 if n.rect.Intersects(rect) { 214 for _, one := range n.contents { 215 if one.Bounds().Intersects(rect) && matcher.Matches(one) { 216 return true 217 } 218 } 219 if !n.isLeaf() { 220 for _, one := range n.children { 221 if one.matchedIntersects(matcher, rect) { 222 return true 223 } 224 } 225 } 226 } 227 return false 228 } 229 230 func (n *node[T, N]) findMatchedIntersects(matcher Matcher[T, N], rect geom.Rect[T], result []N) []N { 231 if n.rect.Intersects(rect) { 232 for _, one := range n.contents { 233 if one.Bounds().Intersects(rect) && matcher.Matches(one) { 234 result = append(result, one) 235 } 236 } 237 if !n.isLeaf() { 238 for _, one := range n.children { 239 result = one.findMatchedIntersects(matcher, rect, result) 240 } 241 } 242 } 243 return result 244 } 245 246 func (n *node[T, N]) containsRect(rect geom.Rect[T]) bool { 247 if n.rect.Intersects(rect) { 248 for _, one := range n.contents { 249 if one.Bounds().Contains(rect) { 250 return true 251 } 252 } 253 if !n.isLeaf() { 254 for _, one := range n.children { 255 if one.containsRect(rect) { 256 return true 257 } 258 } 259 } 260 } 261 return false 262 } 263 264 func (n *node[T, N]) findContainsRect(rect geom.Rect[T], result []N) []N { 265 if n.rect.Intersects(rect) { 266 for _, one := range n.contents { 267 if one.Bounds().Contains(rect) { 268 result = append(result, one) 269 } 270 } 271 if !n.isLeaf() { 272 for _, one := range n.children { 273 result = one.findContainsRect(rect, result) 274 } 275 } 276 } 277 return result 278 } 279 280 func (n *node[T, N]) matchedContainsRect(matcher Matcher[T, N], rect geom.Rect[T]) bool { 281 if n.rect.Intersects(rect) { 282 for _, one := range n.contents { 283 if one.Bounds().Contains(rect) && matcher.Matches(one) { 284 return true 285 } 286 } 287 if !n.isLeaf() { 288 for _, one := range n.children { 289 if one.matchedContainsRect(matcher, rect) { 290 return true 291 } 292 } 293 } 294 } 295 return false 296 } 297 298 func (n *node[T, N]) findMatchedContainsRect(matcher Matcher[T, N], rect geom.Rect[T], result []N) []N { 299 if n.rect.Intersects(rect) { 300 for _, one := range n.contents { 301 if one.Bounds().Contains(rect) && matcher.Matches(one) { 302 result = append(result, one) 303 } 304 } 305 if !n.isLeaf() { 306 for _, one := range n.children { 307 result = one.findMatchedContainsRect(matcher, rect, result) 308 } 309 } 310 } 311 return result 312 } 313 314 func (n *node[T, N]) containedByRect(rect geom.Rect[T]) bool { 315 if n.rect.Intersects(rect) { 316 for _, one := range n.contents { 317 if rect.Contains(one.Bounds()) { 318 return true 319 } 320 } 321 if !n.isLeaf() { 322 for _, one := range n.children { 323 if one.containedByRect(rect) { 324 return true 325 } 326 } 327 } 328 } 329 return false 330 } 331 332 func (n *node[T, N]) findContainedByRect(rect geom.Rect[T], result []N) []N { 333 if n.rect.Intersects(rect) { 334 for _, one := range n.contents { 335 if rect.Contains(one.Bounds()) { 336 result = append(result, one) 337 } 338 } 339 if !n.isLeaf() { 340 for _, one := range n.children { 341 result = one.findContainedByRect(rect, result) 342 } 343 } 344 } 345 return result 346 } 347 348 func (n *node[T, N]) matchedContainedByRect(matcher Matcher[T, N], rect geom.Rect[T]) bool { 349 if n.rect.Intersects(rect) { 350 for _, one := range n.contents { 351 if rect.Contains(one.Bounds()) && matcher.Matches(one) { 352 return true 353 } 354 } 355 if !n.isLeaf() { 356 for _, one := range n.children { 357 if one.matchedContainedByRect(matcher, rect) { 358 return true 359 } 360 } 361 } 362 } 363 return false 364 } 365 366 func (n *node[T, N]) findMatchedContainedByRect(matcher Matcher[T, N], rect geom.Rect[T], result []N) []N { 367 if n.rect.Intersects(rect) { 368 for _, one := range n.contents { 369 if rect.Contains(one.Bounds()) && matcher.Matches(one) { 370 result = append(result, one) 371 } 372 } 373 if !n.isLeaf() { 374 for _, one := range n.children { 375 result = one.findMatchedContainedByRect(matcher, rect, result) 376 } 377 } 378 } 379 return result 380 }