#include "munga.h" #pragma hdrstop #include "boxlist.h" //############################################################################# //######################### BoundingBoxListNode ######################### //############################################################################# MemoryBlock *BoundingBoxListNode::GetAllocatedMemory() { static MemoryBlock allocatedMemory(sizeof(BoundingBoxListNode), 500, 50, "BoundingBoxList Nodes"); return &allocatedMemory; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoundingBoxListNode::TestInstance() const { return True; } //############################################################################# //########################### BoundingBoxList ########################### //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoundingBoxList::BoundingBoxList() { root = NULL; nodeCount = 0; scoreBoard = NULL; boundingBoxIndex = NULL; isXMajorAxis = True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoundingBoxList::~BoundingBoxList() { if (scoreBoard) { Unregister_Pointer(scoreBoard); delete scoreBoard; } if (boundingBoxIndex) { Unregister_Pointer(boundingBoxIndex); delete boundingBoxIndex; } EraseList(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoundingBoxList::Add( BoundingBox* volume, const ExtentBox &slice ) { Check(this); Check(volume); ++nodeCount; BoundingBoxListNode *node = new BoundingBoxListNode(volume, slice); Register_Object(node); node->previousNode = root; root = node; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoundingBoxList::Remove(BoundingBox* volume) { Check(this); Check(volume); // //-------------------------------------------------------------------------- // Spin through all the boxes until we find the one we are after or until we // run off the list //-------------------------------------------------------------------------- // BoundingBoxListNode *p = NULL, *c = root; while (c) { Check(c); if (c->boundingBox == volume) { break; } p = c; c = c->previousNode; } // //---------------------------------------------- // Unlink the node from the list if it was found //---------------------------------------------- // if (!c) { return; } Check(c); if (p) { Check(p); p->previousNode = c->previousNode; } else { root = c->previousNode; } // //----------------- // Delete this node //----------------- // --nodeCount; Unregister_Object(c); delete c; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoundingBoxList::EraseList() { Check(this); // //----------------------------- // Delete each node in the list //----------------------------- // BoundingBoxListNode *p = root; while (p) { Check(p); BoundingBoxListNode *q = p; p = p->previousNode; Unregister_Object(q); delete q; } root = NULL; nodeCount = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoundingBox* BoundingBoxList::FindBoundingBoxContaining(const Point3D &point) { Check(this); Check(&point); // //-------------------------------------------------------------------------- // Spin through each of the boxes in reverse order until we find a box which // contains the specified point. It will be default have priority over any // boxes put in before it //-------------------------------------------------------------------------- // for (BoundingBoxListNode *p=root; p; p = p->previousNode) { Check(p); BoundingBox *box = p->boundingBox; Check(box); if (box->Contains(point)) { return box; } } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoundingBoxList::FindBoundingBoxesContaining( BoundingBox *volume, BoundingBoxCollisionList &list ) { Check(this); Check(volume); Check(&list); // //------------------------------------------------------------- // Spin through each of the boxes in reverse order, looking for // intesections between the test volume and the box list //------------------------------------------------------------- // for (BoundingBoxListNode *p=root; p; p = p->previousNode) { Check(p); BoundingBox *box = p->boundingBox; Check(box); if (box->ExtentBox::Intersects(*volume)) { // //---------------------------------------------------------------- // Build the intersection slice, and make sure that it really does // intersect the list box //---------------------------------------------------------------- // ExtentBox slice; slice.Intersect(*volume, *box); if (box->IntersectsBounded(slice)) { // //------------------------------------------------------------ // It intersects, so add this to the list. If we are out of // collisions in the list, we are finished detecting, and just // return //------------------------------------------------------------ // Verify(list.collisionsLeft); list.AddCollisionToList(box, slice); if (!list.collisionsLeft) { return; } } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoundingBox* BoundingBoxList::FindBoundingBoxUnder( const Point3D &point, Scalar *height ) { Check(this); Check(&point); Check_Pointer(height); // //----------------------------------------------------------------------- // Spin through each of the bounding boxes, keeping track of which box is // hit after the shortest distance //----------------------------------------------------------------------- // BoundingBox *best_box = NULL; *height = -1.0f; for (BoundingBoxListNode *p=root; p; p = p->previousNode) { Check(p); BoundingBox *box = p->boundingBox; Check(box); Scalar h = box->FindDistanceBelow(point); if (h != -1.0f) { if (!best_box || *height > h) { best_box = box; *height = h; } } } return best_box; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoundingBox* BoundingBoxList::FindBoundingBoxHitBy(Line *line) { // //----------------------------------------------------------------------- // Spin through each of the boxes, letting each box in turn clip the line // lengths //----------------------------------------------------------------------- // BoundingBox *best_box = NULL; for (BoundingBoxListNode *p=root; p; p = p->previousNode) { Check(p); BoundingBox *box = p->boundingBox; Check(box); Logical h = box->HitBy(line); if (h) { best_box = box; } } return best_box; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoundingBoxList::TestInstance() const { return True; }