1 module rtree; 2 3 /****************************************************************************** 4 * class RTree 5 * 6 * Implementation of $(LINK2 https://en.wikipedia.org/wiki/R-tree, R-Tree), a multidimensional bounding rectangle tree. 7 * 8 * This is ported to D $(LINK2 https://github.com/nushoin/RTree, C++ version by Yariv Barkan). 9 * 10 * Params: 11 * DataType = Referenced data, should be int, void*, obj* etc. no larger than (void*).sizeof and simple type 12 * ElemType = Type of element such as int or float 13 * NumDims = Number of dimensions such as 2 or 3 14 * ElemTypeReal = Type of element that allows fractional and large values such as float or double, for use in volume calcs 15 * 16 * Example: 17 * --- 18 * // a 3-dimensional tree 19 * alias MyTree = RTree!(StructPtr, float, 3); 20 * auto my_tree = new MyTree(); 21 * --- 22 * 23 * Notes: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle. 24 * This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency. 25 * Instead of using a callback function for returned results, I recommend use efficient pre-sized, grow-only memory 26 * array similar to MFC CArray or STL Vector for returning search query result. 27 */ 28 class RTree(DataType, ElemType, alias NumDims, 29 ElemTypeReal, alias int MaxNodes = 8, alias int MinNodes = MaxNodes / 2) 30 { 31 public: 32 33 import std.container.array : Array; 34 35 // Precomputed volumes of the unit spheres for the first few dimensions 36 enum float[] UnitSphereVolume = [ 37 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2 38 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5 39 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8 40 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11 41 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14 42 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17 43 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20 44 ]; 45 46 // Unit sphere constant for required number of dimensions 47 enum unitSphereVolume = cast(ElemTypeReal) UnitSphereVolume[NumDims]; 48 49 static assert(is(ElemTypeReal : float)); 50 static assert(NumDims >= 2 && NumDims <= 3); 51 static assert(DataType.sizeof <= (void*).sizeof, "DataType should be no larger than (void*).sizeof"); 52 53 this() 54 { 55 static assert(MaxNodes > MinNodes); 56 static assert(MinNodes > 0); 57 58 m_root = AllocNode(); 59 m_root.m_level = 0; 60 } 61 62 ~this() 63 { 64 Reset(); // Free, or reset node memory 65 } 66 67 /// Insert entry 68 /// Params: 69 /// a_min = Min of bounding rect 70 /// a_max = Max of bounding rect 71 /// a_dataId = Positive Id of data. Maybe zero, but negative numbers not allowed. 72 void insert()(auto ref const ElemType[NumDims] a_min, auto ref const ElemType[NumDims] a_max, DataType a_dataId) 73 { 74 debug 75 { 76 for(int index=0; index<NumDims; ++index) 77 { 78 assert(a_min[index] <= a_max[index]); 79 } 80 } 81 82 Branch branch; 83 branch.m_data = a_dataId; 84 branch.m_child = null; 85 86 for(int axis=0; axis<NumDims; ++axis) 87 { 88 branch.m_rect.m_min[axis] = a_min[axis]; 89 branch.m_rect.m_max[axis] = a_max[axis]; 90 } 91 92 InsertRect(branch, &m_root, 0); 93 } 94 95 /// Remove entry 96 /// Params: 97 /// a_min = Min of bounding rect 98 /// a_max = Max of bounding rect 99 /// a_dataId = Positive Id of data. Maybe zero, but negative numbers not allowed. 100 void remove(const ElemType[NumDims] a_min, const ElemType[NumDims] a_max, DataType a_dataId) 101 { 102 debug 103 { 104 for(int index=0; index<NumDims; ++index) 105 { 106 assert(a_min[index] <= a_max[index]); 107 } 108 } 109 110 Rect rect; 111 112 for(int axis=0; axis<NumDims; ++axis) 113 { 114 rect.m_min[axis] = a_min[axis]; 115 rect.m_max[axis] = a_max[axis]; 116 } 117 118 RemoveRect(&rect, a_dataId, &m_root); 119 } 120 121 /// Find all within query rectangle 122 /// Params: 123 /// a_min = Min of query bounding rect 124 /// a_max = Max of query bounding rect 125 /// Returns: Returns the array of entries found 126 Array!DataType search(const ElemType[NumDims] a_min, const ElemType[NumDims] a_max) 127 { 128 debug 129 { 130 for(int index=0; index<NumDims; ++index) 131 { 132 assert(a_min[index] <= a_max[index]); 133 } 134 } 135 136 Rect rect; 137 138 for(int axis=0; axis<NumDims; ++axis) 139 { 140 rect.m_min[axis] = a_min[axis]; 141 rect.m_max[axis] = a_max[axis]; 142 } 143 144 // NOTE: May want to return search result another way, perhaps returning the number of found elements here. 145 146 Array!DataType result; 147 Search(m_root, &rect, result); 148 149 return result; 150 } 151 152 153 /// Remove all entries from tree 154 void removeAll() 155 { 156 // Delete all existing nodes 157 Reset(); 158 159 m_root = AllocNode(); 160 m_root.m_level = 0; 161 } 162 163 /// Count the data elements in this container. This is slow as no internal counter is maintained. 164 int count() 165 { 166 int count = 0; 167 CountRec(m_root, count); 168 169 return count; 170 } 171 172 protected: 173 174 // Minimal bounding rectangle (n-dimensional) 175 struct Rect 176 { 177 ElemType[NumDims] m_min; ///< Min dimensions of bounding box 178 ElemType[NumDims] m_max; ///< Max dimensions of bounding box 179 } 180 181 // May be data or may be another subtree 182 // The parents level determines this. 183 // If the parents level is 0, then this is data 184 struct Branch 185 { 186 Rect m_rect; ///< Bounds 187 Node* m_child; ///< Child node 188 DataType m_data; ///< Data Id 189 } 190 191 // Node for each branch level 192 struct Node 193 { 194 bool IsInternalNode() { return (m_level > 0); } // Not a leaf, but a internal node 195 bool IsLeaf() { return (m_level == 0); } // A leaf, contains data 196 197 int m_count; ///< Count 198 int m_level; ///< Leaf is zero, others positive 199 Branch[MaxNodes] m_branch; ///< Branch 200 } 201 202 // A link list of nodes for reinsertion after a delete operation 203 struct ListNode 204 { 205 ListNode* m_next; ///< Next in list 206 Node* m_node; ///< Node 207 } 208 209 // Variables for finding a split partition 210 struct PartitionVars 211 { 212 enum { NOT_TAKEN = -1 } // indicates that position 213 214 int[MaxNodes+1] m_partition; 215 int m_total; 216 int m_minFill; 217 int[2] m_count; 218 Rect[2] m_cover; 219 ElemTypeReal[2] m_area; 220 221 Branch[MaxNodes+1] m_branchBuf; 222 int m_branchCount; 223 Rect m_coverSplit; 224 ElemTypeReal m_coverSplitArea; 225 } 226 227 Node* AllocNode() 228 { 229 auto newNode = new Node; 230 InitNode(newNode); 231 return newNode; 232 } 233 234 void FreeNode(Node* a_node) 235 { 236 assert(a_node); 237 destroy(a_node); 238 a_node = null; 239 } 240 241 void InitNode(Node* a_node) 242 { 243 a_node.m_count = 0; 244 a_node.m_level = -1; 245 } 246 247 void InitRect(Rect* a_rect) 248 { 249 for(int index = 0; index < NumDims; ++index) 250 { 251 a_rect.m_min[index] = cast(ElemType) 0; 252 a_rect.m_max[index] = cast(ElemType) 0; 253 } 254 } 255 256 bool InsertRectRec(ref Branch a_branch, Node* a_node, Node** a_newNode, int a_level) 257 { 258 assert(a_node && a_newNode); 259 assert(a_level >= 0 && a_level <= a_node.m_level); 260 261 // recurse until we reach the correct level for the new record. data records 262 // will always be called with a_level == 0 (leaf) 263 if(a_node.m_level > a_level) 264 { 265 // Still above level for insertion, go down tree recursively 266 Node* otherNode; 267 268 // find the optimal branch for this record 269 int index = PickBranch(&a_branch.m_rect, a_node); 270 271 // recursively insert this record into the picked branch 272 bool childWasSplit = InsertRectRec(a_branch, a_node.m_branch[index].m_child, &otherNode, a_level); 273 274 if (!childWasSplit) 275 { 276 // Child was not split. Merge the bounding box of the new record with the 277 // existing bounding box 278 a_node.m_branch[index].m_rect = CombineRect(&a_branch.m_rect, &(a_node.m_branch[index].m_rect)); 279 return false; 280 } 281 else 282 { 283 // Child was split. The old branches are now re-partitioned to two nodes 284 // so we have to re-calculate the bounding boxes of each node 285 a_node.m_branch[index].m_rect = NodeCover(a_node.m_branch[index].m_child); 286 Branch branch; 287 branch.m_child = otherNode; 288 branch.m_rect = NodeCover(otherNode); 289 290 // The old node is already a child of a_node. Now add the newly-created 291 // node to a_node as well. a_node might be split because of that. 292 return AddBranch(&branch, a_node, a_newNode); 293 } 294 } 295 else if(a_node.m_level == a_level) 296 { 297 // We have reached level for insertion. Add rect, split if necessary 298 return AddBranch(&a_branch, a_node, a_newNode); 299 } 300 else 301 { 302 // Should never occur 303 debug 304 { 305 assert(0); 306 } 307 else 308 { 309 return false; 310 } 311 } 312 } 313 314 bool InsertRect(ref Branch a_branch, Node** a_root, int a_level) 315 { 316 assert(a_root); 317 assert(a_level >= 0 && a_level <= (*a_root).m_level); 318 debug 319 { 320 for(int index=0; index < NumDims; ++index) 321 { 322 assert(a_branch.m_rect.m_min[index] <= a_branch.m_rect.m_max[index]); 323 } 324 } 325 326 Node* newNode; 327 328 if (InsertRectRec(a_branch, *a_root, &newNode, a_level)) // Root split 329 { 330 // Grow tree taller and new root 331 Node* newRoot = AllocNode(); 332 newRoot.m_level = (*a_root).m_level + 1; 333 334 Branch branch; 335 336 // add old root node as a child of the new root 337 branch.m_rect = NodeCover(*a_root); 338 branch.m_child = *a_root; 339 AddBranch(&branch, newRoot, null); 340 341 // add the split node as a child of the new root 342 branch.m_rect = NodeCover(newNode); 343 branch.m_child = newNode; 344 AddBranch(&branch, newRoot, null); 345 346 // set the new root as the root node 347 *a_root = newRoot; 348 349 return true; 350 } 351 352 return false; 353 } 354 355 Rect NodeCover(Node* a_node) 356 { 357 assert(a_node); 358 359 Rect rect = a_node.m_branch[0].m_rect; 360 for(int index = 1; index < a_node.m_count; ++index) 361 { 362 rect = CombineRect(&rect, &(a_node.m_branch[index].m_rect)); 363 } 364 365 return rect; 366 } 367 368 bool AddBranch(Branch* a_branch, Node* a_node, Node** a_newNode) 369 { 370 assert(a_branch); 371 assert(a_node); 372 373 if(a_node.m_count < MaxNodes) // Split won't be necessary 374 { 375 a_node.m_branch[a_node.m_count] = *a_branch; 376 ++a_node.m_count; 377 378 return false; 379 } 380 else 381 { 382 assert(a_newNode); 383 384 SplitNode(a_node, a_branch, a_newNode); 385 return true; 386 } 387 } 388 389 void DisconnectBranch(Node* a_node, int a_index) 390 { 391 assert(a_node && (a_index >= 0) && (a_index < MaxNodes)); 392 assert(a_node.m_count > 0); 393 394 // Remove element by swapping with the last element to prevent gaps in array 395 a_node.m_branch[a_index] = a_node.m_branch[a_node.m_count - 1]; 396 397 --a_node.m_count; 398 } 399 400 int PickBranch(const Rect* a_rect, Node* a_node) 401 { 402 assert(a_rect && a_node); 403 404 bool firstTime = true; 405 ElemTypeReal increase; 406 ElemTypeReal bestIncr = cast(ElemTypeReal) -1; 407 ElemTypeReal area; 408 ElemTypeReal bestArea; 409 int best; 410 Rect tempRect; 411 412 for(int index=0; index < a_node.m_count; ++index) 413 { 414 Rect* curRect = &a_node.m_branch[index].m_rect; 415 area = CalcRectVolume(curRect); 416 tempRect = CombineRect(a_rect, curRect); 417 increase = CalcRectVolume(&tempRect) - area; 418 if((increase < bestIncr) || firstTime) 419 { 420 best = index; 421 bestArea = area; 422 bestIncr = increase; 423 firstTime = false; 424 } 425 else if((increase == bestIncr) && (area < bestArea)) 426 { 427 best = index; 428 bestArea = area; 429 bestIncr = increase; 430 } 431 } 432 return best; 433 } 434 435 Rect CombineRect(const Rect* a_rectA, const Rect* a_rectB) 436 { 437 assert(a_rectA && a_rectB); 438 439 Rect newRect; 440 441 for(int index = 0; index < NumDims; ++index) 442 { 443 import std.algorithm : min, max; 444 newRect.m_min[index] = min(a_rectA.m_min[index], a_rectB.m_min[index]); 445 newRect.m_max[index] = max(a_rectA.m_max[index], a_rectB.m_max[index]); 446 } 447 448 return newRect; 449 } 450 451 void SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode) 452 { 453 assert(a_node); 454 assert(a_branch); 455 456 // Could just use local here, but member or external is faster since it is reused 457 PartitionVars localVars; 458 PartitionVars* parVars = &localVars; 459 460 // Load all the branches into a buffer, initialize old node 461 GetBranches(a_node, a_branch, parVars); 462 463 // Find partition 464 ChoosePartition(parVars, MinNodes); 465 466 // Create a new node to hold (about) half of the branches 467 *a_newNode = AllocNode(); 468 (*a_newNode).m_level = a_node.m_level; 469 470 // Put branches from buffer into 2 nodes according to the chosen partition 471 a_node.m_count = 0; 472 LoadNodes(a_node, *a_newNode, parVars); 473 474 assert((a_node.m_count + (*a_newNode).m_count) == parVars.m_total); 475 } 476 477 ElemTypeReal RectSphericalVolume(Rect* a_rect) 478 { 479 assert(a_rect); 480 481 ElemTypeReal sumOfSquares = cast(ElemTypeReal) 0; 482 ElemTypeReal radius; 483 484 for(int index=0; index < NumDims; ++index) 485 { 486 ElemTypeReal halfExtent = (cast(ElemTypeReal) a_rect.m_max[index] - cast(ElemTypeReal) a_rect.m_min[index]) * 0.5f; 487 sumOfSquares += halfExtent * halfExtent; 488 } 489 490 import std.math : sqrt; 491 radius = cast(ElemTypeReal) sqrt(sumOfSquares); 492 493 // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. 494 static if(NumDims == 3) 495 { 496 return (radius * radius * radius * unitSphereVolume); 497 } 498 else static if(NumDims == 2) 499 { 500 return (radius * radius * unitSphereVolume); 501 } 502 else 503 { 504 return cast(ElemTypeReal) (pow(radius, NumDims) * unitSphereVolume); 505 } 506 } 507 508 ElemTypeReal RectVolume(Rect* a_rect) 509 { 510 assert(a_rect); 511 512 ElemTypeReal volume = cast(ElemTypeReal) 1; 513 514 for(int index=0; index<NumDims; ++index) 515 { 516 volume *= a_rect.m_max[index] - a_rect.m_min[index]; 517 } 518 519 assert(volume >= cast(ElemTypeReal) 0); 520 521 return volume; 522 } 523 524 ElemTypeReal CalcRectVolume(Rect* a_rect) 525 { 526 version(RTREE_USE_SPHERICAL_VOLUME) 527 { 528 return RectSphericalVolume(a_rect); // Slower but helps certain merge cases 529 } 530 else 531 { 532 return RectVolume(a_rect); // Faster but can cause poor merges 533 } 534 } 535 536 void GetBranches(Node* a_node, Branch* a_branch, PartitionVars* a_parVars) 537 { 538 assert(a_node); 539 assert(a_branch); 540 541 assert(a_node.m_count == MaxNodes); 542 543 // Load the branch buffer 544 for(int index=0; index < MaxNodes; ++index) 545 { 546 a_parVars.m_branchBuf[index] = a_node.m_branch[index]; 547 } 548 a_parVars.m_branchBuf[MaxNodes] = *a_branch; 549 a_parVars.m_branchCount = MaxNodes + 1; 550 551 // Calculate rect containing all in the set 552 a_parVars.m_coverSplit = a_parVars.m_branchBuf[0].m_rect; 553 for(int index=1; index < MaxNodes+1; ++index) 554 { 555 a_parVars.m_coverSplit = CombineRect(&a_parVars.m_coverSplit, &a_parVars.m_branchBuf[index].m_rect); 556 } 557 a_parVars.m_coverSplitArea = CalcRectVolume(&a_parVars.m_coverSplit); 558 } 559 560 void ChoosePartition(PartitionVars* a_parVars, int a_minFill) 561 { 562 assert(a_parVars); 563 564 ElemTypeReal biggestDiff; 565 int group, chosen, betterGroup; 566 567 InitParVars(a_parVars, a_parVars.m_branchCount, a_minFill); 568 PickSeeds(a_parVars); 569 570 while (((a_parVars.m_count[0] + a_parVars.m_count[1]) < a_parVars.m_total) 571 && (a_parVars.m_count[0] < (a_parVars.m_total - a_parVars.m_minFill)) 572 && (a_parVars.m_count[1] < (a_parVars.m_total - a_parVars.m_minFill))) 573 { 574 biggestDiff = cast(ElemTypeReal) -1; 575 for(int index=0; index<a_parVars.m_total; ++index) 576 { 577 if(PartitionVars.NOT_TAKEN == a_parVars.m_partition[index]) 578 { 579 Rect* curRect = &a_parVars.m_branchBuf[index].m_rect; 580 Rect rect0 = CombineRect(curRect, &a_parVars.m_cover[0]); 581 Rect rect1 = CombineRect(curRect, &a_parVars.m_cover[1]); 582 ElemTypeReal growth0 = CalcRectVolume(&rect0) - a_parVars.m_area[0]; 583 ElemTypeReal growth1 = CalcRectVolume(&rect1) - a_parVars.m_area[1]; 584 ElemTypeReal diff = growth1 - growth0; 585 if(diff >= 0) 586 { 587 group = 0; 588 } 589 else 590 { 591 group = 1; 592 diff = -diff; 593 } 594 595 if(diff > biggestDiff) 596 { 597 biggestDiff = diff; 598 chosen = index; 599 betterGroup = group; 600 } 601 else if((diff == biggestDiff) && (a_parVars.m_count[group] < a_parVars.m_count[betterGroup])) 602 { 603 chosen = index; 604 betterGroup = group; 605 } 606 } 607 } 608 Classify(chosen, betterGroup, a_parVars); 609 } 610 611 // If one group too full, put remaining rects in the other 612 if((a_parVars.m_count[0] + a_parVars.m_count[1]) < a_parVars.m_total) 613 { 614 if(a_parVars.m_count[0] >= a_parVars.m_total - a_parVars.m_minFill) 615 { 616 group = 1; 617 } 618 else 619 { 620 group = 0; 621 } 622 623 for(int index=0; index<a_parVars.m_total; ++index) 624 { 625 if(PartitionVars.NOT_TAKEN == a_parVars.m_partition[index]) 626 { 627 Classify(index, group, a_parVars); 628 } 629 } 630 } 631 632 assert((a_parVars.m_count[0] + a_parVars.m_count[1]) == a_parVars.m_total); 633 assert((a_parVars.m_count[0] >= a_parVars.m_minFill) && 634 (a_parVars.m_count[1] >= a_parVars.m_minFill)); 635 } 636 637 void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars) 638 { 639 assert(a_nodeA); 640 assert(a_nodeB); 641 assert(a_parVars); 642 643 for(int index=0; index < a_parVars.m_total; ++index) 644 { 645 assert(a_parVars.m_partition[index] == 0 || a_parVars.m_partition[index] == 1); 646 647 int targetNodeIndex = a_parVars.m_partition[index]; 648 Node*[2] targetNodes = [a_nodeA, a_nodeB]; 649 650 // It is assured that AddBranch here will not cause a node split. 651 bool nodeWasSplit = AddBranch(&a_parVars.m_branchBuf[index], targetNodes[targetNodeIndex], null); 652 assert(!nodeWasSplit); 653 } 654 } 655 656 void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill) 657 { 658 assert(a_parVars); 659 660 a_parVars.m_count[0] = a_parVars.m_count[1] = 0; 661 a_parVars.m_area[0] = a_parVars.m_area[1] = cast(ElemTypeReal) 0; 662 a_parVars.m_total = a_maxRects; 663 a_parVars.m_minFill = a_minFill; 664 for(int index=0; index < a_maxRects; ++index) 665 { 666 a_parVars.m_partition[index] = PartitionVars.NOT_TAKEN; 667 } 668 } 669 670 void PickSeeds(PartitionVars* a_parVars) 671 { 672 int seed0 = 0; 673 int seed1 = seed0 + 1; 674 ElemTypeReal worst, waste; 675 ElemTypeReal[MaxNodes+1] area; 676 677 for(int index=0; index<a_parVars.m_total; ++index) 678 { 679 area[index] = CalcRectVolume(&a_parVars.m_branchBuf[index].m_rect); 680 } 681 682 worst = -a_parVars.m_coverSplitArea - 1; 683 for(int indexA = seed0; indexA < a_parVars.m_total-1; ++indexA) 684 { 685 for(int indexB = seed1; indexB < a_parVars.m_total; ++indexB) 686 { 687 Rect oneRect = CombineRect(&a_parVars.m_branchBuf[indexA].m_rect, &a_parVars.m_branchBuf[indexB].m_rect); 688 waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB]; 689 if(waste > worst) 690 { 691 worst = waste; 692 seed0 = indexA; 693 seed1 = indexB; 694 } 695 } 696 } 697 698 Classify(seed0, 0, a_parVars); 699 Classify(seed1, 1, a_parVars); 700 } 701 702 void Classify(int a_index, int a_group, PartitionVars* a_parVars) 703 { 704 assert(a_parVars); 705 assert(PartitionVars.NOT_TAKEN == a_parVars.m_partition[a_index]); 706 707 a_parVars.m_partition[a_index] = a_group; 708 709 // Calculate combined rect 710 if (a_parVars.m_count[a_group] == 0) 711 { 712 a_parVars.m_cover[a_group] = a_parVars.m_branchBuf[a_index].m_rect; 713 } 714 else 715 { 716 a_parVars.m_cover[a_group] = CombineRect(&a_parVars.m_branchBuf[a_index].m_rect, &a_parVars.m_cover[a_group]); 717 } 718 719 // Calculate volume of combined rect 720 a_parVars.m_area[a_group] = CalcRectVolume(&a_parVars.m_cover[a_group]); 721 722 ++a_parVars.m_count[a_group]; 723 } 724 725 bool RemoveRect(Rect* a_rect, ref const DataType a_id, Node** a_root) 726 { 727 assert(a_rect && a_root); 728 assert(*a_root); 729 730 ListNode* reInsertList = null; 731 732 if (!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList)) 733 { 734 // Found and deleted a data item 735 // Reinsert any branches from eliminated nodes 736 while(reInsertList) 737 { 738 Node* tempNode = reInsertList.m_node; 739 740 for(int index = 0; index < tempNode.m_count; ++index) 741 { 742 // TODO go over this code. should I use (tempNode.m_level - 1)? 743 InsertRect(tempNode.m_branch[index], 744 a_root, 745 tempNode.m_level); 746 } 747 748 ListNode* remLNode = reInsertList; 749 reInsertList = reInsertList.m_next; 750 751 FreeNode(remLNode.m_node); 752 FreeListNode(remLNode); 753 } 754 755 // Check for redundant root (not leaf, 1 child) and eliminate TODO replace 756 // if with while? In case there is a whole branch of redundant roots... 757 if((*a_root).m_count == 1 && (*a_root).IsInternalNode()) 758 { 759 Node* tempNode = (*a_root).m_branch[0].m_child; 760 761 assert(tempNode); 762 FreeNode(*a_root); 763 *a_root = tempNode; 764 } 765 return false; 766 } 767 else 768 { 769 return true; 770 } 771 } 772 773 bool RemoveRectRec(Rect* a_rect, ref const DataType a_id, Node* a_node, ListNode** a_listNode) 774 { 775 assert(a_rect && a_node && a_listNode); 776 assert(a_node.m_level >= 0); 777 778 if(a_node.IsInternalNode()) // not a leaf node 779 { 780 for(int index = 0; index < a_node.m_count; ++index) 781 { 782 if(Overlap(a_rect, &(a_node.m_branch[index].m_rect))) 783 { 784 if(!RemoveRectRec(a_rect, a_id, a_node.m_branch[index].m_child, a_listNode)) 785 { 786 if(a_node.m_branch[index].m_child.m_count >= MinNodes) 787 { 788 // child removed, just resize parent rect 789 a_node.m_branch[index].m_rect = NodeCover(a_node.m_branch[index].m_child); 790 } 791 else 792 { 793 // child removed, not enough entries in node, eliminate node 794 ReInsert(a_node.m_branch[index].m_child, a_listNode); 795 DisconnectBranch(a_node, index); // Must return after this call as count has changed 796 } 797 return false; 798 } 799 } 800 } 801 return true; 802 } 803 else // A leaf node 804 { 805 for(int index = 0; index < a_node.m_count; ++index) 806 { 807 if(a_node.m_branch[index].m_data == a_id) 808 { 809 DisconnectBranch(a_node, index); // Must return after this call as count has changed 810 return false; 811 } 812 } 813 return true; 814 } 815 } 816 817 ListNode* AllocListNode() 818 { 819 return new ListNode; 820 } 821 822 void FreeListNode(ListNode* a_listNode) 823 { 824 destroy(a_listNode); 825 } 826 827 bool Overlap(Rect* a_rectA, Rect* a_rectB) 828 { 829 assert(a_rectA && a_rectB); 830 831 for(int index=0; index < NumDims; ++index) 832 { 833 if (a_rectA.m_min[index] > a_rectB.m_max[index] || 834 a_rectB.m_min[index] > a_rectA.m_max[index]) 835 { 836 return false; 837 } 838 } 839 return true; 840 } 841 842 void ReInsert(Node* a_node, ListNode** a_listNode) 843 { 844 ListNode* newListNode; 845 846 newListNode = AllocListNode(); 847 newListNode.m_node = a_node; 848 newListNode.m_next = *a_listNode; 849 *a_listNode = newListNode; 850 } 851 852 bool Search(Node* a_node, Rect* a_rect, ref Array!DataType result) 853 { 854 assert(a_node); 855 assert(a_node.m_level >= 0); 856 assert(a_rect); 857 858 if(a_node.IsInternalNode()) 859 { 860 // This is an internal node in the tree 861 for(int index=0; index < a_node.m_count; ++index) 862 { 863 if(Overlap(a_rect, &a_node.m_branch[index].m_rect)) 864 { 865 Search(a_node.m_branch[index].m_child, a_rect, result); 866 } 867 } 868 } 869 else 870 { 871 // This is a leaf node 872 for(int index=0; index < a_node.m_count; ++index) 873 { 874 if(Overlap(a_rect, &a_node.m_branch[index].m_rect)) 875 { 876 result ~= a_node.m_branch[index].m_data; 877 } 878 } 879 } 880 881 return true; // Continue searching 882 } 883 884 void RemoveAllRec(Node* a_node) 885 { 886 assert(a_node); 887 assert(a_node.m_level >= 0); 888 889 if(a_node.IsInternalNode()) // This is an internal node in the tree 890 { 891 for(int index=0; index < a_node.m_count; ++index) 892 { 893 RemoveAllRec(a_node.m_branch[index].m_child); 894 } 895 } 896 FreeNode(a_node); 897 } 898 899 void Reset() 900 { 901 RemoveAllRec(m_root); 902 } 903 904 void CountRec(Node* a_node, ref int a_count) 905 { 906 if(a_node.IsInternalNode()) // not a leaf node 907 { 908 for(int index = 0; index < a_node.m_count; ++index) 909 { 910 CountRec(a_node.m_branch[index].m_child, a_count); 911 } 912 } 913 else // A leaf node 914 { 915 a_count += a_node.m_count; 916 } 917 } 918 919 // Root of tree 920 Node* m_root; 921 }