1 module Engine.Tree.BBTreeCache; 2 3 import Engine.math; 4 alias ulong TimeStamp; 5 alias ulong Hash; 6 import std.stdio; 7 import Engine.Allocator; 8 9 alias ulong delegate(Indexable a,Indexable b, ulong collisionID) SpatialIndexQueryFunc; 10 alias void delegate(Node* node) HashSetIterator; 11 12 13 class BBTree : Tree 14 { 15 ChunkAllocator!(Pair, 100) pairAllocator; 16 ChunkAllocator!(Node, 100) nodeAllocator; 17 int allocatedNodes = 0; 18 int allocatedPair = 0; 19 int freedNodes = 0; 20 int freedPair = 0; 21 22 23 Node*[Indexable] leaves; 24 Node* root; 25 26 27 @property ref TimeStamp stamp() { 28 return stamp_; 29 } 30 TimeStamp stamp_; 31 32 Tree staticTree; 33 Tree dynamicTree; 34 35 this(Tree staticTree) 36 { 37 if (staticTree !is null) { 38 this.staticTree = staticTree; 39 } 40 stamp_ = 0; 41 } 42 43 @property size_t length() const { 44 return leaves.length; 45 } 46 47 void Each(HashSetIterator func) { 48 foreach (Node* node; leaves) { 49 func(node); 50 } 51 } 52 53 void Insert(Indexable obj ) { 54 auto leaf = NewLeaf(obj); 55 leaves[obj] = leaf; 56 this.root = this.SubtreeInsert(this.root, leaf); 57 leaf.stamp = GetMasterTree().stamp; 58 LeafAddPairs(leaf); 59 IncrementStamp(); 60 } 61 62 void LeafAddPairs(Node *leaf) 63 { 64 if (dynamicTree !is null) { 65 auto dTree = cast(BBTree)dynamicTree; 66 if(dTree !is null && dTree.root !is null){ 67 MarkContext context = MarkContext(dTree, null, null); 68 context.MarkLeafQuery(dTree.root, leaf, true); 69 } 70 } else { 71 auto sTree = cast(BBTree)staticTree; 72 Node *staticRoot = sTree !is null ? sTree.root : null; 73 MarkContext context = MarkContext(this, staticRoot, null); 74 context.MarkLeaf(leaf); 75 } 76 } 77 78 void Query(Indexable obj, rect bb, SpatialIndexQueryFunc func) { 79 if(root) 80 SubtreeQuery(root, obj, bb, func); 81 } 82 83 void SubtreeQuery(Node *subtree, Indexable obj, rect bb, SpatialIndexQueryFunc func) 84 { 85 if(rect.Intersects(subtree.bb, bb)){ 86 if(subtree.NodeIsLeaf()){ 87 func(obj, subtree.obj, 0); 88 } else { 89 SubtreeQuery(subtree.a, obj, bb, func); 90 SubtreeQuery(subtree.b, obj, bb, func); 91 } 92 } 93 } 94 95 bool LeafUpdate(Node *leaf) 96 { 97 auto rt = root; 98 if(!rect.Contains(leaf.bb, leaf.obj.BB())){ 99 leaf.bb = BB(leaf.obj); 100 101 rt = SubtreeRemove(rt, leaf); 102 root = SubtreeInsert(rt, leaf); 103 104 PairsClear(leaf); 105 leaf.stamp = GetMasterTree.stamp; 106 107 return true; 108 } else { 109 return false; 110 } 111 } 112 113 void PairsClear(Node *leaf) 114 { 115 Pair *pair = leaf.pairs; 116 leaf.pairs = null; 117 118 while(pair !is null){ 119 if(pair.a.leaf == leaf){ 120 Pair *next = pair.a.next; 121 ThreadUnlink(pair.b); 122 PairRecycle(pair); 123 pair = next; 124 } else { 125 Pair *next = pair.b.next; 126 ThreadUnlink(pair.a); 127 PairRecycle(pair); 128 pair = next; 129 } 130 } 131 } 132 133 void ThreadUnlink()(auto ref Thread thread) 134 { 135 auto next = thread.next; 136 auto prev = thread.prev; 137 138 if(next){ 139 if(next.a.leaf == thread.leaf) next.a.prev = prev; else next.b.prev = prev; 140 } 141 142 if(prev){ 143 if(prev.a.leaf == thread.leaf) prev.a.next = next; else prev.b.next = next; 144 } else { 145 thread.leaf.pairs = next; 146 } 147 } 148 149 Pair* PairFromPool() { 150 allocatedPair++; 151 return pairAllocator.allocate(); 152 } 153 154 void PairRecycle(Pair *pair) 155 { 156 freedPair++; 157 pair.a.next = null; 158 pairAllocator.free(pair); 159 } 160 161 Node* NodeFromPool() { 162 allocatedNodes++; 163 return nodeAllocator.allocate(); 164 } 165 166 void NodeRecycle(Node *node) 167 { 168 freedNodes++; 169 node.parent = null; 170 nodeAllocator.free(node); 171 } 172 173 Node* SubtreeRemove(Node *subtree, Node *leaf) 174 { 175 if(leaf == subtree){ 176 return null; 177 } else { 178 Node *parent = leaf.parent; 179 if(parent == subtree){ 180 Node *other = subtree.NodeOther(leaf); 181 other.parent = subtree.parent; 182 NodeRecycle(subtree); 183 return other; 184 } else { 185 NodeReplaceChild(parent.parent, parent, parent.NodeOther(leaf)); 186 return subtree; 187 } 188 } 189 } 190 191 void NodeReplaceChild(Node *parent, Node *child, Node *value) 192 { 193 assert(!parent.NodeIsLeaf(), "Internal Error: Cannot replace child of a leaf."); 194 assert(child == parent.a || child == parent.b, "Internal Error: Node is not a child of parent."); 195 196 if(parent.a == child){ 197 NodeRecycle(parent.a); 198 parent.NodeSetA(value); 199 } else { 200 NodeRecycle(parent.b); 201 parent.NodeSetB(value); 202 } 203 204 for(Node *node=parent; node; node = node.parent){ 205 node.bb = rect.Merge(node.a.bb, node.b.bb); 206 } 207 } 208 209 void ReindexQuery(SpatialIndexQueryFunc func) 210 { 211 if(root is null) return; 212 213 // LeafUpdate() may modify tree->root. Don't cache it. 214 foreach (ref leaf ; leaves) { 215 LeafUpdate(leaf); 216 } 217 218 auto staticIndex = cast(BBTree)staticTree; 219 Node *staticRoot = staticIndex !is null ? staticIndex.root : null; 220 221 MarkContext context = MarkContext(this, staticRoot, func); 222 context.MarkSubtree(root); 223 if(staticIndex && !staticRoot) 224 SpatialIndexCollideStatic(this, staticIndex, func); 225 226 IncrementStamp(); 227 } 228 229 static void SpatialIndexCollideStatic(Tree tree, Tree staticIndex, SpatialIndexQueryFunc func) { 230 if (staticIndex.length > 0) { 231 tree.Each((Node* node) { 232 staticIndex.Query(node.obj, node.obj.BB(), func); 233 }); 234 } 235 } 236 237 void IncrementStamp()() 238 { 239 if (dynamicTree !is null) { 240 dynamicTree.stamp++; 241 } else { 242 stamp++; 243 } 244 } 245 246 Tree GetMasterTree()() { 247 if (dynamicTree !is null) { 248 return dynamicTree; 249 } 250 return this; 251 } 252 253 Node * SubtreeInsert(Node *subtree, Node *leaf) 254 { 255 if(subtree is null){ 256 return leaf; 257 } else if(subtree.NodeIsLeaf()){ 258 return NodeNew(leaf, subtree); 259 } else { 260 auto cost_a = subtree.b.bb.Area() + rect.MergedArea(subtree.a.bb, leaf.bb); 261 auto cost_b = subtree.a.bb.Area() + rect.MergedArea(subtree.b.bb, leaf.bb); 262 263 if(cost_a == cost_b){ 264 cost_a = rect.Proximity(subtree.a.bb, leaf.bb); 265 cost_b = rect.Proximity(subtree.b.bb, leaf.bb); 266 } 267 268 if(cost_b < cost_a){ 269 subtree.NodeSetB(SubtreeInsert(subtree.b, leaf)); 270 } else { 271 subtree.NodeSetA(SubtreeInsert(subtree.a, leaf)); 272 } 273 subtree.bb = rect.Merge(subtree.bb, leaf.bb); 274 275 return subtree; 276 } 277 } 278 279 Node* NodeNew(Node* a, Node* b) 280 { 281 Node *node = NodeFromPool(); 282 283 node.obj = null; 284 node.bb = rect.Merge(a.bb, b.bb); 285 node.parent = null; 286 287 node.NodeSetA(a); 288 node.NodeSetB(b); 289 290 return node; 291 } 292 293 rect BB(Indexable obj ) 294 { 295 auto bb = obj.BB(); 296 297 /* 298 cpBBTreeVelocityFunc velocityFunc = tree->velocityFunc; 299 if(velocityFunc){ 300 cpFloat coef = 0.1f; 301 cpFloat x = (bb.r - bb.l)*coef; 302 cpFloat y = (bb.t - bb.b)*coef; 303 304 cpVect v = cpvmult(velocityFunc(obj), 0.1f); 305 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)); 306 } else { 307 return bb; 308 } 309 */ 310 return bb; 311 } 312 313 Node* NewLeaf(Indexable obj ){ 314 auto node = NodeFromPool(); 315 node.obj = obj; 316 node.bb = BB(obj); 317 318 node.parent = null; 319 node.stamp = 0; 320 node.pairs = null; 321 322 return node; 323 } 324 325 void PairInsert(Node *a, Node *b) 326 { 327 Pair* nextA = a.pairs, nextB = b.pairs; 328 Pair *pair = PairFromPool(); 329 *pair = Pair(Thread(null, a, nextA),Thread(null, b, nextB), 0); 330 331 a.pairs = b.pairs = pair; 332 333 if(nextA !is null){ 334 if(nextA.a.leaf == a) nextA.a.prev = pair; else nextA.b.prev = pair; 335 } 336 337 if(nextB !is null){ 338 if(nextB.a.leaf == b) nextB.a.prev = pair; else nextB.b.prev = pair; 339 } 340 } 341 } 342 343 interface Tree { 344 345 @property ref TimeStamp stamp(); 346 @property size_t length() const; 347 348 void Each(HashSetIterator fnc); 349 350 //Contains(obj Indexable) bool 351 void Insert(Indexable obj); 352 //Remove(obj Indexable) 353 354 //Reindex() 355 //ReindexObject(obj Indexable) 356 //ReindexQuery(fnc SpatialIndexQueryFunc) 357 358 //TimeStamp Stamp(); 359 360 void Query(Indexable obj, rect aabb, SpatialIndexQueryFunc fnc); 361 //SegmentQuery(obj Indexable, a, b vect.Vect, t_exit vect.Float, fnc func()) 362 } 363 364 struct MarkContext { 365 BBTree tree; 366 Node* staticRoot; 367 SpatialIndexQueryFunc func; 368 369 370 void MarkLeafQuery()(Node *subtree, Node *leaf, bool left) 371 { 372 if(rect.Intersects(leaf.bb, subtree.bb)){ 373 if(subtree.NodeIsLeaf()) { 374 if(left){ 375 tree.PairInsert(leaf, subtree); 376 } else { 377 if(subtree.stamp < leaf.stamp) 378 tree.PairInsert(subtree, leaf); 379 if (func !is null) 380 func(leaf.obj, subtree.obj, 0); 381 } 382 } else { 383 MarkLeafQuery(subtree.a, leaf, left); 384 MarkLeafQuery(subtree.b, leaf, left); 385 } 386 } 387 } 388 389 void MarkLeaf()(Node *leaf) 390 { 391 if(leaf.stamp == tree.GetMasterTree().stamp) { 392 Node *staticRoot = staticRoot; 393 if(staticRoot !is null) 394 MarkLeafQuery(staticRoot, leaf, false); 395 396 for(Node *node = leaf; node.parent !is null; node = node.parent){ 397 if(node == node.parent.a){ 398 MarkLeafQuery(node.parent.b, leaf, true); 399 } else { 400 MarkLeafQuery(node.parent.a, leaf, false); 401 } 402 } 403 } else { 404 Pair *pair = leaf.pairs; 405 while(pair !is null){ 406 if(leaf == pair.b.leaf){ 407 if (func !is null) 408 pair.id = func(pair.a.leaf.obj, leaf.obj, pair.id); 409 pair = pair.b.next; 410 } else { 411 pair = pair.a.next; 412 } 413 } 414 } 415 } 416 417 void MarkSubtree()(Node *subtree) 418 { 419 if(subtree.NodeIsLeaf()){ 420 MarkLeaf(subtree); 421 } else { 422 MarkSubtree(subtree.a); 423 MarkSubtree(subtree.b); // TODO: Force TCO here? 424 } 425 } 426 427 }; 428 429 interface Indexable { 430 //Hash GetHash(); 431 rect BB(); 432 } 433 434 struct Thread { 435 Pair* prev; 436 Node* leaf; 437 Pair* next; 438 } 439 440 struct Pair { 441 Thread a, b; 442 ulong id; 443 } 444 445 struct Node { 446 Indexable obj; 447 rect bb; 448 Node *parent; 449 450 bool NodeIsLeaf() 451 { 452 return obj !is null; 453 } 454 455 Node* NodeOther(Node *child) 456 { 457 return (a == child ? b : a); 458 } 459 460 void NodeSetA()(Node *value) 461 { 462 a = value; 463 value.parent = &this; 464 } 465 466 void NodeSetB()(Node *value) 467 { 468 b = value; 469 value.parent = &this; 470 } 471 472 //children 473 Node* a, b; 474 475 //leaf 476 TimeStamp stamp; 477 Pair* pairs; 478 };