1 /* 2 * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 module dchip.cpBBTree; 23 24 import core.stdc.stdlib : qsort; 25 26 import dchip.chipmunk; 27 import dchip.chipmunk_private; 28 import dchip.chipmunk_types; 29 import dchip.cpArray; 30 import dchip.cpBB; 31 import dchip.cpHashSet; 32 import dchip.cpSpatialIndex; 33 import dchip.cpVect; 34 import dchip.util; 35 36 struct cpBBTree 37 { 38 cpSpatialIndex spatialIndex; 39 cpBBTreeVelocityFunc velocityFunc; 40 41 cpHashSet* leaves; 42 Node* root; 43 44 Node* pooledNodes; 45 Pair* pooledPairs; 46 cpArray* allocatedBuffers; 47 48 cpTimestamp stamp; 49 } 50 51 struct Node 52 { 53 void* obj; 54 cpBB bb; 55 Node* parent; 56 57 union UnionNode 58 { 59 // Internal nodes 60 struct Children 61 { 62 Node* a; 63 Node* b; 64 } 65 66 Children children; 67 68 // Leaves 69 struct Leaf 70 { 71 cpTimestamp stamp; 72 Pair* pairs; 73 } 74 75 Leaf leaf; 76 } 77 78 UnionNode node; 79 } 80 81 // Can't use anonymous unions and still get good x-compiler compatability 82 ref A(T)(ref T t) { return t.node.children.a; } 83 ref B(T)(ref T t) { return t.node.children.b; } 84 85 ref STAMP(T)(ref T t) { return t.node.leaf.stamp; } 86 ref PAIRS(T)(ref T t) { return t.node.leaf.pairs; } 87 88 struct Thread 89 { 90 Pair* prev; 91 Node* leaf; 92 Pair* next; 93 } 94 95 struct Pair 96 { 97 Thread a, b; 98 cpCollisionID id; 99 } 100 101 cpBB GetBB(cpBBTree* tree, void* obj) 102 { 103 cpBB bb = tree.spatialIndex.bbfunc(obj); 104 105 cpBBTreeVelocityFunc velocityFunc = tree.velocityFunc; 106 107 if (velocityFunc) 108 { 109 cpFloat coef = 0.1f; 110 cpFloat x = (bb.r - bb.l) * coef; 111 cpFloat y = (bb.t - bb.b) * coef; 112 113 cpVect v = cpvmult(velocityFunc(obj), 0.1f); 114 return cpBBNew(bb.l + cpfmin(-x, v.x), bb.b + cpfmin(-y, v.y), bb.r + cpfmax(x, v.x), bb.t + cpfmax(y, v.y)); 115 } 116 else 117 { 118 return bb; 119 } 120 } 121 122 cpBBTree* GetTree(cpSpatialIndex* index) 123 { 124 return (index && index.klass == Klass() ? cast(cpBBTree*)index : null); 125 } 126 127 Node* GetRootIfTree(cpSpatialIndex* index) 128 { 129 return (index && index.klass == Klass() ? (cast(cpBBTree*)index).root : null); 130 } 131 132 cpBBTree* GetMasterTree(cpBBTree* tree) 133 { 134 cpBBTree* dynamicTree = GetTree(tree.spatialIndex.dynamicIndex); 135 return (dynamicTree ? dynamicTree : tree); 136 } 137 138 void IncrementStamp(cpBBTree* tree) 139 { 140 cpBBTree* dynamicTree = GetTree(tree.spatialIndex.dynamicIndex); 141 142 if (dynamicTree) 143 { 144 dynamicTree.stamp++; 145 } 146 else 147 { 148 tree.stamp++; 149 } 150 } 151 152 //MARK: Pair/Thread Functions 153 154 void PairRecycle(cpBBTree* tree, Pair* pair) 155 { 156 // Share the pool of the master tree. 157 // TODO would be lovely to move the pairs stuff into an external data structure. 158 tree = GetMasterTree(tree); 159 160 pair.a.next = tree.pooledPairs; 161 tree.pooledPairs = pair; 162 } 163 164 Pair* PairFromPool(cpBBTree* tree) 165 { 166 // Share the pool of the master tree. 167 // TODO would be lovely to move the pairs stuff into an external data structure. 168 tree = GetMasterTree(tree); 169 170 Pair* pair = tree.pooledPairs; 171 172 if (pair) 173 { 174 tree.pooledPairs = pair.a.next; 175 return pair; 176 } 177 else 178 { 179 // Pool is exhausted, make more 180 int count = CP_BUFFER_BYTES / Pair.sizeof; 181 cpAssertHard(count, "Internal Error: Buffer size is too small."); 182 183 Pair* buffer = cast(Pair*)cpcalloc(1, CP_BUFFER_BYTES); 184 cpArrayPush(tree.allocatedBuffers, buffer); 185 186 // push all but the first one, return the first instead 187 for (int i = 1; i < count; i++) 188 PairRecycle(tree, buffer + i); 189 190 return buffer; 191 } 192 } 193 194 void ThreadUnlink(Thread thread) 195 { 196 Pair* next = thread.next; 197 Pair* prev = thread.prev; 198 199 if (next) 200 { 201 if (next.a.leaf == thread.leaf) 202 next.a.prev = prev; 203 else 204 next.b.prev = prev; 205 } 206 207 if (prev) 208 { 209 if (prev.a.leaf == thread.leaf) 210 prev.a.next = next; 211 else 212 prev.b.next = next; 213 } 214 else 215 { 216 thread.leaf.PAIRS = next; 217 } 218 } 219 220 void PairsClear(Node* leaf, cpBBTree* tree) 221 { 222 Pair* pair = leaf.PAIRS; 223 leaf.PAIRS = null; 224 225 while (pair) 226 { 227 if (pair.a.leaf == leaf) 228 { 229 Pair* next = pair.a.next; 230 ThreadUnlink(pair.b); 231 PairRecycle(tree, pair); 232 pair = next; 233 } 234 else 235 { 236 Pair* next = pair.b.next; 237 ThreadUnlink(pair.a); 238 PairRecycle(tree, pair); 239 pair = next; 240 } 241 } 242 } 243 244 void PairInsert(Node* a, Node* b, cpBBTree* tree) 245 { 246 Pair* nextA = a.PAIRS; 247 Pair* nextB = b.PAIRS; 248 Pair* pair = PairFromPool(tree); 249 Pair temp = { { null, a, nextA }, { null, b, nextB }, 0 }; 250 251 a.PAIRS = b.PAIRS = pair; 252 *pair = temp; 253 254 if (nextA) 255 { 256 if (nextA.a.leaf == a) 257 nextA.a.prev = pair; 258 else 259 nextA.b.prev = pair; 260 } 261 262 if (nextB) 263 { 264 if (nextB.a.leaf == b) 265 nextB.a.prev = pair; 266 else 267 nextB.b.prev = pair; 268 } 269 } 270 271 //MARK: Node Functions 272 273 void NodeRecycle(cpBBTree* tree, Node* node) 274 { 275 node.parent = tree.pooledNodes; 276 tree.pooledNodes = node; 277 } 278 279 Node* NodeFromPool(cpBBTree* tree) 280 { 281 Node* node = tree.pooledNodes; 282 283 if (node) 284 { 285 tree.pooledNodes = node.parent; 286 return node; 287 } 288 else 289 { 290 // Pool is exhausted, make more 291 int count = CP_BUFFER_BYTES / Node.sizeof; 292 cpAssertHard(count, "Internal Error: Buffer size is too small."); 293 294 Node* buffer = cast(Node*)cpcalloc(1, CP_BUFFER_BYTES); 295 cpArrayPush(tree.allocatedBuffers, buffer); 296 297 // push all but the first one, return the first instead 298 for (int i = 1; i < count; i++) 299 NodeRecycle(tree, buffer + i); 300 301 return buffer; 302 } 303 } 304 305 void NodeSetA(Node* node, Node* value) 306 { 307 node.A = value; 308 value.parent = node; 309 } 310 311 void NodeSetB(Node* node, Node* value) 312 { 313 node.B = value; 314 value.parent = node; 315 } 316 317 Node* NodeNew(cpBBTree* tree, Node* a, Node* b) 318 { 319 Node* node = NodeFromPool(tree); 320 321 node.obj = null; 322 node.bb = cpBBMerge(a.bb, b.bb); 323 node.parent = null; 324 325 NodeSetA(node, a); 326 NodeSetB(node, b); 327 328 return node; 329 } 330 331 cpBool NodeIsLeaf(Node* node) 332 { 333 return (node.obj != null); 334 } 335 336 Node* NodeOther(Node* node, Node* child) 337 { 338 return (node.A == child ? node.B : node.A); 339 } 340 341 void NodeReplaceChild(Node* parent, Node* child, Node* value, cpBBTree* tree) 342 { 343 cpAssertSoft(!NodeIsLeaf(parent), "Internal Error: Cannot replace child of a leaf."); 344 cpAssertSoft(child == parent.A || child == parent.B, "Internal Error: Node is not a child of parent."); 345 346 if (parent.A == child) 347 { 348 NodeRecycle(tree, parent.A); 349 NodeSetA(parent, value); 350 } 351 else 352 { 353 NodeRecycle(tree, parent.B); 354 NodeSetB(parent, value); 355 } 356 357 for (Node* node = parent; node; node = node.parent) 358 { 359 node.bb = cpBBMerge(node.A.bb, node.B.bb); 360 } 361 } 362 363 //MARK: Subtree Functions 364 365 cpFloat cpBBProximity(cpBB a, cpBB b) 366 { 367 return cpfabs(a.l + a.r - b.l - b.r) + cpfabs(a.b + a.t - b.b - b.t); 368 } 369 370 Node* SubtreeInsert(Node* subtree, Node* leaf, cpBBTree* tree) 371 { 372 if (subtree == null) 373 { 374 return leaf; 375 } 376 else if (NodeIsLeaf(subtree)) 377 { 378 return NodeNew(tree, leaf, subtree); 379 } 380 else 381 { 382 cpFloat cost_a = cpBBArea(subtree.B.bb) + cpBBMergedArea(subtree.A.bb, leaf.bb); 383 cpFloat cost_b = cpBBArea(subtree.A.bb) + cpBBMergedArea(subtree.B.bb, leaf.bb); 384 385 if (cost_a == cost_b) 386 { 387 cost_a = cpBBProximity(subtree.A.bb, leaf.bb); 388 cost_b = cpBBProximity(subtree.B.bb, leaf.bb); 389 } 390 391 if (cost_b < cost_a) 392 { 393 NodeSetB(subtree, SubtreeInsert(subtree.B, leaf, tree)); 394 } 395 else 396 { 397 NodeSetA(subtree, SubtreeInsert(subtree.A, leaf, tree)); 398 } 399 400 subtree.bb = cpBBMerge(subtree.bb, leaf.bb); 401 return subtree; 402 } 403 } 404 405 void SubtreeQuery(Node* subtree, void* obj, cpBB bb, cpSpatialIndexQueryFunc func, void* data) 406 { 407 if (cpBBIntersects(subtree.bb, bb)) 408 { 409 if (NodeIsLeaf(subtree)) 410 { 411 func(obj, subtree.obj, 0, data); 412 } 413 else 414 { 415 SubtreeQuery(subtree.A, obj, bb, func, data); 416 SubtreeQuery(subtree.B, obj, bb, func, data); 417 } 418 } 419 } 420 421 cpFloat SubtreeSegmentQuery(Node* subtree, void* obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void* data) 422 { 423 if (NodeIsLeaf(subtree)) 424 { 425 return func(obj, subtree.obj, data); 426 } 427 else 428 { 429 cpFloat t_a = cpBBSegmentQuery(subtree.A.bb, a, b); 430 cpFloat t_b = cpBBSegmentQuery(subtree.B.bb, a, b); 431 432 if (t_a < t_b) 433 { 434 if (t_a < t_exit) 435 t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree.A, obj, a, b, t_exit, func, data)); 436 437 if (t_b < t_exit) 438 t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree.B, obj, a, b, t_exit, func, data)); 439 } 440 else 441 { 442 if (t_b < t_exit) 443 t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree.B, obj, a, b, t_exit, func, data)); 444 445 if (t_a < t_exit) 446 t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree.A, obj, a, b, t_exit, func, data)); 447 } 448 449 return t_exit; 450 } 451 } 452 453 void SubtreeRecycle(cpBBTree* tree, Node* node) 454 { 455 if (!NodeIsLeaf(node)) 456 { 457 SubtreeRecycle(tree, node.A); 458 SubtreeRecycle(tree, node.B); 459 NodeRecycle(tree, node); 460 } 461 } 462 463 Node* SubtreeRemove(Node* subtree, Node* leaf, cpBBTree* tree) 464 { 465 if (leaf == subtree) 466 { 467 return null; 468 } 469 else 470 { 471 Node* parent = leaf.parent; 472 473 if (parent == subtree) 474 { 475 Node* other = NodeOther(subtree, leaf); 476 other.parent = subtree.parent; 477 NodeRecycle(tree, subtree); 478 return other; 479 } 480 else 481 { 482 NodeReplaceChild(parent.parent, parent, NodeOther(parent, leaf), tree); 483 return subtree; 484 } 485 } 486 } 487 488 //MARK: Marking Functions 489 490 struct MarkContext 491 { 492 cpBBTree* tree; 493 Node* staticRoot; 494 cpSpatialIndexQueryFunc func; 495 void* data; 496 } 497 498 void MarkLeafQuery(Node* subtree, Node* leaf, cpBool left, MarkContext* context) 499 { 500 if (cpBBIntersects(leaf.bb, subtree.bb)) 501 { 502 if (NodeIsLeaf(subtree)) 503 { 504 if (left) 505 { 506 PairInsert(leaf, subtree, context.tree); 507 } 508 else 509 { 510 if (subtree.STAMP < leaf.STAMP) 511 PairInsert(subtree, leaf, context.tree); 512 context.func(leaf.obj, subtree.obj, 0, context.data); 513 } 514 } 515 else 516 { 517 MarkLeafQuery(subtree.A, leaf, left, context); 518 MarkLeafQuery(subtree.B, leaf, left, context); 519 } 520 } 521 } 522 523 void MarkLeaf(Node* leaf, MarkContext* context) 524 { 525 cpBBTree* tree = context.tree; 526 527 if (leaf.STAMP == GetMasterTree(tree).stamp) 528 { 529 Node* staticRoot = context.staticRoot; 530 531 if (staticRoot) 532 MarkLeafQuery(staticRoot, leaf, cpFalse, context); 533 534 for (Node* node = leaf; node.parent; node = node.parent) 535 { 536 if (node == node.parent.A) 537 { 538 MarkLeafQuery(node.parent.B, leaf, cpTrue, context); 539 } 540 else 541 { 542 MarkLeafQuery(node.parent.A, leaf, cpFalse, context); 543 } 544 } 545 } 546 else 547 { 548 Pair* pair = leaf.PAIRS; 549 550 while (pair) 551 { 552 if (leaf == pair.b.leaf) 553 { 554 pair.id = context.func(pair.a.leaf.obj, leaf.obj, pair.id, context.data); 555 pair = pair.b.next; 556 } 557 else 558 { 559 pair = pair.a.next; 560 } 561 } 562 } 563 } 564 565 void MarkSubtree(Node* subtree, MarkContext* context) 566 { 567 if (NodeIsLeaf(subtree)) 568 { 569 MarkLeaf(subtree, context); 570 } 571 else 572 { 573 MarkSubtree(subtree.A, context); 574 MarkSubtree(subtree.B, context); // TODO Force TCO here? 575 } 576 } 577 578 //MARK: Leaf Functions 579 580 Node* LeafNew(cpBBTree* tree, void* obj, cpBB bb) 581 { 582 Node* node = NodeFromPool(tree); 583 node.obj = obj; 584 node.bb = GetBB(tree, obj); 585 586 node.parent = null; 587 node.STAMP = 0; 588 node.PAIRS = null; 589 590 return node; 591 } 592 593 cpBool LeafUpdate(Node* leaf, cpBBTree* tree) 594 { 595 Node* root = tree.root; 596 cpBB bb = tree.spatialIndex.bbfunc(leaf.obj); 597 598 if (!cpBBContainsBB(leaf.bb, bb)) 599 { 600 leaf.bb = GetBB(tree, leaf.obj); 601 602 root = SubtreeRemove(root, leaf, tree); 603 tree.root = SubtreeInsert(root, leaf, tree); 604 605 PairsClear(leaf, tree); 606 leaf.STAMP = GetMasterTree(tree).stamp; 607 608 return cpTrue; 609 } 610 else 611 { 612 return cpFalse; 613 } 614 } 615 616 cpCollisionID VoidQueryFunc(void* obj1, void* obj2, cpCollisionID id, void* data) 617 { 618 return id; 619 } 620 621 void LeafAddPairs(Node* leaf, cpBBTree* tree) 622 { 623 cpSpatialIndex* dynamicIndex = tree.spatialIndex.dynamicIndex; 624 625 if (dynamicIndex) 626 { 627 Node* dynamicRoot = GetRootIfTree(dynamicIndex); 628 629 if (dynamicRoot) 630 { 631 cpBBTree* dynamicTree = GetTree(dynamicIndex); 632 MarkContext context = { dynamicTree, null, null, null }; 633 MarkLeafQuery(dynamicRoot, leaf, cpTrue, &context); 634 } 635 } 636 else 637 { 638 Node* staticRoot = GetRootIfTree(tree.spatialIndex.staticIndex); 639 MarkContext context = { tree, staticRoot, &VoidQueryFunc, null }; 640 MarkLeaf(leaf, &context); 641 } 642 } 643 644 cpBBTree* cpBBTreeAlloc() 645 { 646 return cast(cpBBTree*)cpcalloc(1, cpBBTree.sizeof); 647 } 648 649 bool leafSetEql(void* obj, Node* node) 650 { 651 return (obj == node.obj); 652 } 653 654 void* leafSetTrans(void* obj, cpBBTree* tree) 655 { 656 return LeafNew(tree, obj, tree.spatialIndex.bbfunc(obj)); 657 } 658 659 cpSpatialIndex* cpBBTreeInit(cpBBTree* tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex* staticIndex) 660 { 661 cpSpatialIndexInit(cast(cpSpatialIndex*)tree, Klass(), bbfunc, staticIndex); 662 663 tree.velocityFunc = null; 664 665 tree.leaves = cpHashSetNew(0, safeCast!cpHashSetEqlFunc(&leafSetEql)); 666 tree.root = null; 667 668 tree.pooledNodes = null; 669 tree.allocatedBuffers = cpArrayNew(0); 670 671 tree.stamp = 0; 672 673 return cast(cpSpatialIndex*)tree; 674 } 675 676 void cpBBTreeSetVelocityFunc(cpSpatialIndex* index, cpBBTreeVelocityFunc func) 677 { 678 if (index.klass != Klass()) 679 { 680 cpAssertWarn(cpFalse, "Ignoring cpBBTreeSetVelocityFunc() call to non-tree spatial index."); 681 return; 682 } 683 684 (cast(cpBBTree*)index).velocityFunc = func; 685 } 686 687 cpSpatialIndex* cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex* staticIndex) 688 { 689 return cpBBTreeInit(cpBBTreeAlloc(), bbfunc, staticIndex); 690 } 691 692 void cpBBTreeDestroy(cpBBTree* tree) 693 { 694 cpHashSetFree(tree.leaves); 695 696 if (tree.allocatedBuffers) 697 cpArrayFreeEach(tree.allocatedBuffers, &cpfree); 698 cpArrayFree(tree.allocatedBuffers); 699 } 700 701 //MARK: Insert/Remove 702 703 void cpBBTreeInsert(cpBBTree* tree, void* obj, cpHashValue hashid) 704 { 705 Node* leaf = cast(Node*)cpHashSetInsert(tree.leaves, hashid, obj, tree, safeCast!cpHashSetTransFunc(&leafSetTrans)); 706 707 Node* root = tree.root; 708 tree.root = SubtreeInsert(root, leaf, tree); 709 710 leaf.STAMP = GetMasterTree(tree).stamp; 711 LeafAddPairs(leaf, tree); 712 IncrementStamp(tree); 713 } 714 715 void cpBBTreeRemove(cpBBTree* tree, void* obj, cpHashValue hashid) 716 { 717 Node* leaf = cast(Node*)cpHashSetRemove(tree.leaves, hashid, obj); 718 719 tree.root = SubtreeRemove(tree.root, leaf, tree); 720 PairsClear(leaf, tree); 721 NodeRecycle(tree, leaf); 722 } 723 724 cpBool cpBBTreeContains(cpBBTree* tree, void* obj, cpHashValue hashid) 725 { 726 return (cpHashSetFind(tree.leaves, hashid, obj) != null); 727 } 728 729 //MARK: Reindex 730 731 /** Workaround for https://github.com/slembcke/Chipmunk2D/issues/56. */ 732 void LeafUpdateWrap(void* elt, void* data) 733 { 734 LeafUpdate(cast(Node*)elt, cast(cpBBTree*)data); 735 } 736 737 void cpBBTreeReindexQuery(cpBBTree* tree, cpSpatialIndexQueryFunc func, void* data) 738 { 739 if (!tree.root) 740 return; 741 742 // LeafUpdate() may modify tree.root. Don't cache it. 743 cpHashSetEach(tree.leaves, safeCast!cpHashSetIteratorFunc(&LeafUpdateWrap), tree); 744 745 cpSpatialIndex* staticIndex = tree.spatialIndex.staticIndex; 746 Node* staticRoot = (staticIndex && staticIndex.klass == Klass() ? (cast(cpBBTree*)staticIndex).root : null); 747 748 MarkContext context = { tree, staticRoot, func, data }; 749 MarkSubtree(tree.root, &context); 750 751 if (staticIndex && !staticRoot) 752 cpSpatialIndexCollideStatic(cast(cpSpatialIndex*)tree, staticIndex, func, data); 753 754 IncrementStamp(tree); 755 } 756 757 void cpBBTreeReindex(cpBBTree* tree) 758 { 759 cpBBTreeReindexQuery(tree, &VoidQueryFunc, null); 760 } 761 762 void cpBBTreeReindexObject(cpBBTree* tree, void* obj, cpHashValue hashid) 763 { 764 Node* leaf = cast(Node*)cpHashSetFind(tree.leaves, hashid, obj); 765 766 if (leaf) 767 { 768 if (LeafUpdate(leaf, tree)) 769 LeafAddPairs(leaf, tree); 770 IncrementStamp(tree); 771 } 772 } 773 774 //MARK: Query 775 776 void cpBBTreeSegmentQuery(cpBBTree* tree, void* obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void* data) 777 { 778 Node* root = tree.root; 779 780 if (root) 781 SubtreeSegmentQuery(root, obj, a, b, t_exit, func, data); 782 } 783 784 void cpBBTreeQuery(cpBBTree* tree, void* obj, cpBB bb, cpSpatialIndexQueryFunc func, void* data) 785 { 786 if (tree.root) 787 SubtreeQuery(tree.root, obj, bb, func, data); 788 } 789 790 int cpBBTreeCount(cpBBTree* tree) 791 { 792 return cpHashSetCount(tree.leaves); 793 } 794 795 struct eachContext 796 { 797 cpSpatialIndexIteratorFunc func; 798 void* data; 799 } 800 801 void each_helper(Node* node, eachContext* context) 802 { 803 context.func(node.obj, context.data); 804 } 805 806 void cpBBTreeEach(cpBBTree* tree, cpSpatialIndexIteratorFunc func, void* data) 807 { 808 eachContext context = { func, data }; 809 cpHashSetEach(tree.leaves, safeCast!cpHashSetIteratorFunc(&each_helper), &context); 810 } 811 812 __gshared cpSpatialIndexClass klass; 813 814 void _initModuleCtor_cpBBTree() 815 { 816 klass = cpSpatialIndexClass( 817 safeCast!cpSpatialIndexDestroyImpl(&cpBBTreeDestroy), 818 819 safeCast!cpSpatialIndexCountImpl(&cpBBTreeCount), 820 safeCast!cpSpatialIndexEachImpl(&cpBBTreeEach), 821 822 safeCast!cpSpatialIndexContainsImpl(&cpBBTreeContains), 823 safeCast!cpSpatialIndexInsertImpl(&cpBBTreeInsert), 824 safeCast!cpSpatialIndexRemoveImpl(&cpBBTreeRemove), 825 826 safeCast!cpSpatialIndexReindexImpl(&cpBBTreeReindex), 827 safeCast!cpSpatialIndexReindexObjectImpl(&cpBBTreeReindexObject), 828 safeCast!cpSpatialIndexReindexQueryImpl(&cpBBTreeReindexQuery), 829 830 safeCast!cpSpatialIndexQueryImpl(&cpBBTreeQuery), 831 safeCast!cpSpatialIndexSegmentQueryImpl(&cpBBTreeSegmentQuery), 832 ); 833 } 834 835 cpSpatialIndexClass* Klass() 836 { 837 return &klass; 838 } 839 840 //MARK: Tree Optimization 841 842 int cpfcompare(const cpFloat* a, const cpFloat* b) 843 { 844 return (*a < *b ? -1 : (*b < *a ? 1 : 0)); 845 } 846 847 void fillNodeArray(Node* node, Node*** cursor) 848 { 849 (**cursor) = node; 850 (*cursor)++; 851 } 852 853 Node* partitionNodes(cpBBTree* tree, Node** nodes, int count) 854 { 855 if (count == 1) 856 { 857 return nodes[0]; 858 } 859 else if (count == 2) 860 { 861 return NodeNew(tree, nodes[0], nodes[1]); 862 } 863 864 // Find the AABB for these nodes 865 cpBB bb = nodes[0].bb; 866 867 for (int i = 1; i < count; i++) 868 bb = cpBBMerge(bb, nodes[i].bb); 869 870 // Split it on it's longest axis 871 cpBool splitWidth = (bb.r - bb.l > bb.t - bb.b); 872 873 // Sort the bounds and use the median as the splitting point 874 cpFloat* bounds = cast(cpFloat*)cpcalloc(count * 2, cpFloat.sizeof); 875 876 if (splitWidth) 877 { 878 for (int i = 0; i < count; i++) 879 { 880 bounds[2 * i + 0] = nodes[i].bb.l; 881 bounds[2 * i + 1] = nodes[i].bb.r; 882 } 883 } 884 else 885 { 886 for (int i = 0; i < count; i++) 887 { 888 bounds[2 * i + 0] = nodes[i].bb.b; 889 bounds[2 * i + 1] = nodes[i].bb.t; 890 } 891 } 892 893 alias extern(C) int function(scope const void*, scope const void*) CompareFunc; 894 895 qsort(bounds, count * 2, cpFloat.sizeof, safeCast!CompareFunc(&cpfcompare)); 896 cpFloat split = (bounds[count - 1] + bounds[count]) * 0.5f; // use the medain as the split 897 cpfree(bounds); 898 899 // Generate the child BBs 900 cpBB a = bb, b = bb; 901 902 if (splitWidth) 903 a.r = b.l = split; 904 else 905 a.t = b.b = split; 906 907 // Partition the nodes 908 int right = count; 909 910 for (int left = 0; left < right; ) 911 { 912 Node* node = nodes[left]; 913 914 if (cpBBMergedArea(node.bb, b) < cpBBMergedArea(node.bb, a)) 915 { 916 // if(cpBBProximity(node.bb, b) < cpBBProximity(node.bb, a)){ 917 right--; 918 nodes[left] = nodes[right]; 919 nodes[right] = node; 920 } 921 else 922 { 923 left++; 924 } 925 } 926 927 if (right == count) 928 { 929 Node* node = null; 930 931 for (int i = 0; i < count; i++) 932 node = SubtreeInsert(node, nodes[i], tree); 933 934 return node; 935 } 936 937 // Recurse and build the node! 938 return NodeNew(tree, 939 partitionNodes(tree, nodes, right), 940 partitionNodes(tree, nodes + right, count - right) 941 ); 942 } 943 944 //void 945 //cpBBTreeOptimizeIncremental(cpBBTree *tree, int passes) 946 //{ 947 // for(int i=0; i<passes; i++){ 948 // Node *root = tree.root; 949 // Node *node = root; 950 // int bit = 0; 951 // uint path = tree.opath; 952 // 953 // while(!NodeIsLeaf(node)){ 954 // node = (path&(1<<bit) ? node.a : node.b); 955 // bit = (bit + 1)&(sizeof(uint)*8 - 1); 956 // } 957 // 958 // root = subtreeRemove(root, node, tree); 959 // tree.root = subtreeInsert(root, node, tree); 960 // } 961 //} 962 963 void cpBBTreeOptimize(cpSpatialIndex* index) 964 { 965 if (index.klass != &klass) 966 { 967 cpAssertWarn(cpFalse, "Ignoring cpBBTreeOptimize() call to non-tree spatial index."); 968 return; 969 } 970 971 cpBBTree* tree = cast(cpBBTree*)index; 972 Node* root = tree.root; 973 974 if (!root) 975 return; 976 977 int count = cpBBTreeCount(tree); 978 Node** nodes = cast(Node**)cpcalloc(count, (Node*).sizeof); 979 Node** cursor = nodes; 980 981 cpHashSetEach(tree.leaves, safeCast!cpHashSetIteratorFunc(&fillNodeArray), &cursor); 982 983 SubtreeRecycle(tree, root); 984 tree.root = partitionNodes(tree, nodes, count); 985 cpfree(nodes); 986 } 987 988 // drey later todo 989 // version = CHIP_BBTREE_DEBUG_DRAW; 990 version (CHIP_BBTREE_DEBUG_DRAW) 991 { 992 /+ #include "OpenGL/gl.h" 993 #include "OpenGL/glu.h" 994 #include <GLUT/glut.h> 995 996 void NodeRender(Node* node, int depth) 997 { 998 if (!NodeIsLeaf(node) && depth <= 10) 999 { 1000 NodeRender(node.a, depth + 1); 1001 NodeRender(node.b, depth + 1); 1002 } 1003 1004 cpBB bb = node.bb; 1005 1006 // GLfloat v = depth/2.0f; 1007 // glColor3f(1.0f - v, v, 0.0f); 1008 glLineWidth(cpfmax(5.0f - depth, 1.0f)); 1009 glBegin(GL_LINES); 1010 { 1011 glVertex2f(bb.l, bb.b); 1012 glVertex2f(bb.l, bb.t); 1013 1014 glVertex2f(bb.l, bb.t); 1015 glVertex2f(bb.r, bb.t); 1016 1017 glVertex2f(bb.r, bb.t); 1018 glVertex2f(bb.r, bb.b); 1019 1020 glVertex2f(bb.r, bb.b); 1021 glVertex2f(bb.l, bb.b); 1022 }; 1023 glEnd(); 1024 } 1025 1026 void cpBBTreeRenderDebug(cpSpatialIndex* index) 1027 { 1028 if (index.klass != &klass) 1029 { 1030 cpAssertWarn(cpFalse, "Ignoring cpBBTreeRenderDebug() call to non-tree spatial index."); 1031 return; 1032 } 1033 1034 cpBBTree* tree = (cpBBTree*)index; 1035 1036 if (tree.root) 1037 NodeRender(tree.root, 0); 1038 } +/ 1039 }