File indexing completed on 2024-05-19 14:56:22
0001 /* 0002 * Copyright (c) 2009 Erin Catto http://www.box2d.org 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #ifndef B2_DYNAMIC_TREE_H 0020 #define B2_DYNAMIC_TREE_H 0021 0022 #include <Box2D/Collision/b2Collision.h> 0023 #include <Box2D/Common/b2GrowableStack.h> 0024 0025 #define b2_nullNode (-1) 0026 0027 /// A node in the dynamic tree. The client does not interact with this directly. 0028 struct b2TreeNode 0029 { 0030 bool IsLeaf() const 0031 { 0032 return child1 == b2_nullNode; 0033 } 0034 0035 /// Enlarged AABB 0036 b2AABB aabb; 0037 0038 void* userData; 0039 0040 union 0041 { 0042 int32 parent; 0043 int32 next; 0044 }; 0045 0046 int32 child1; 0047 int32 child2; 0048 0049 // leaf = 0, free node = -1 0050 int32 height; 0051 }; 0052 0053 /// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. 0054 /// A dynamic tree arranges data in a binary tree to accelerate 0055 /// queries such as volume queries and ray casts. Leafs are proxies 0056 /// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor 0057 /// so that the proxy AABB is bigger than the client object. This allows the client 0058 /// object to move by small amounts without triggering a tree update. 0059 /// 0060 /// Nodes are pooled and relocatable, so we use node indices rather than pointers. 0061 class b2DynamicTree 0062 { 0063 public: 0064 /// Constructing the tree initializes the node pool. 0065 b2DynamicTree(); 0066 0067 /// Destroy the tree, freeing the node pool. 0068 ~b2DynamicTree(); 0069 0070 /// Create a proxy. Provide a tight fitting AABB and a userData pointer. 0071 int32 CreateProxy(const b2AABB& aabb, void* userData); 0072 0073 /// Destroy a proxy. This asserts if the id is invalid. 0074 void DestroyProxy(int32 proxyId); 0075 0076 /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, 0077 /// then the proxy is removed from the tree and re-inserted. Otherwise 0078 /// the function returns immediately. 0079 /// @return true if the proxy was re-inserted. 0080 bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); 0081 0082 /// Get proxy user data. 0083 /// @return the proxy user data or 0 if the id is invalid. 0084 void* GetUserData(int32 proxyId) const; 0085 0086 /// Get the fat AABB for a proxy. 0087 const b2AABB& GetFatAABB(int32 proxyId) const; 0088 0089 /// Query an AABB for overlapping proxies. The callback class 0090 /// is called for each proxy that overlaps the supplied AABB. 0091 template <typename T> 0092 void Query(T* callback, const b2AABB& aabb) const; 0093 0094 /// Ray-cast against the proxies in the tree. This relies on the callback 0095 /// to perform a exact ray-cast in the case were the proxy contains a shape. 0096 /// The callback also performs the any collision filtering. This has performance 0097 /// roughly equal to k * log(n), where k is the number of collisions and n is the 0098 /// number of proxies in the tree. 0099 /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). 0100 /// @param callback a callback class that is called for each proxy that is hit by the ray. 0101 template <typename T> 0102 void RayCast(T* callback, const b2RayCastInput& input) const; 0103 0104 /// Validate this tree. For testing. 0105 void Validate() const; 0106 0107 /// Compute the height of the binary tree in O(N) time. Should not be 0108 /// called often. 0109 int32 GetHeight() const; 0110 0111 /// Get the maximum balance of an node in the tree. The balance is the difference 0112 /// in height of the two children of a node. 0113 int32 GetMaxBalance() const; 0114 0115 /// Get the ratio of the sum of the node areas to the root area. 0116 float32 GetAreaRatio() const; 0117 0118 /// Build an optimal tree. Very expensive. For testing. 0119 void RebuildBottomUp(); 0120 0121 /// Shift the world origin. Useful for large worlds. 0122 /// The shift formula is: position -= newOrigin 0123 /// @param newOrigin the new origin with respect to the old origin 0124 void ShiftOrigin(const b2Vec2& newOrigin); 0125 0126 private: 0127 0128 int32 AllocateNode(); 0129 void FreeNode(int32 node); 0130 0131 void InsertLeaf(int32 node); 0132 void RemoveLeaf(int32 node); 0133 0134 int32 Balance(int32 index); 0135 0136 int32 ComputeHeight() const; 0137 int32 ComputeHeight(int32 nodeId) const; 0138 0139 void ValidateStructure(int32 index) const; 0140 void ValidateMetrics(int32 index) const; 0141 0142 int32 m_root; 0143 0144 b2TreeNode* m_nodes; 0145 int32 m_nodeCount; 0146 int32 m_nodeCapacity; 0147 0148 int32 m_freeList; 0149 0150 /// This is used to incrementally traverse the tree for re-balancing. 0151 uint32 m_path; 0152 0153 int32 m_insertionCount; 0154 }; 0155 0156 inline void* b2DynamicTree::GetUserData(int32 proxyId) const 0157 { 0158 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); 0159 return m_nodes[proxyId].userData; 0160 } 0161 0162 inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const 0163 { 0164 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); 0165 return m_nodes[proxyId].aabb; 0166 } 0167 0168 template <typename T> 0169 inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const 0170 { 0171 b2GrowableStack<int32, 256> stack; 0172 stack.Push(m_root); 0173 0174 while (stack.GetCount() > 0) 0175 { 0176 int32 nodeId = stack.Pop(); 0177 if (nodeId == b2_nullNode) 0178 { 0179 continue; 0180 } 0181 0182 const b2TreeNode* node = m_nodes + nodeId; 0183 0184 if (b2TestOverlap(node->aabb, aabb)) 0185 { 0186 if (node->IsLeaf()) 0187 { 0188 bool proceed = callback->QueryCallback(nodeId); 0189 if (proceed == false) 0190 { 0191 return; 0192 } 0193 } 0194 else 0195 { 0196 stack.Push(node->child1); 0197 stack.Push(node->child2); 0198 } 0199 } 0200 } 0201 } 0202 0203 template <typename T> 0204 inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const 0205 { 0206 b2Vec2 p1 = input.p1; 0207 b2Vec2 p2 = input.p2; 0208 b2Vec2 r = p2 - p1; 0209 b2Assert(r.LengthSquared() > 0.0f); 0210 r.Normalize(); 0211 0212 // v is perpendicular to the segment. 0213 b2Vec2 v = b2Cross(1.0f, r); 0214 b2Vec2 abs_v = b2Abs(v); 0215 0216 // Separating axis for segment (Gino, p80). 0217 // |dot(v, p1 - c)| > dot(|v|, h) 0218 0219 float32 maxFraction = input.maxFraction; 0220 0221 // Build a bounding box for the segment. 0222 b2AABB segmentAABB; 0223 { 0224 b2Vec2 t = p1 + maxFraction * (p2 - p1); 0225 segmentAABB.lowerBound = b2Min(p1, t); 0226 segmentAABB.upperBound = b2Max(p1, t); 0227 } 0228 0229 b2GrowableStack<int32, 256> stack; 0230 stack.Push(m_root); 0231 0232 while (stack.GetCount() > 0) 0233 { 0234 int32 nodeId = stack.Pop(); 0235 if (nodeId == b2_nullNode) 0236 { 0237 continue; 0238 } 0239 0240 const b2TreeNode* node = m_nodes + nodeId; 0241 0242 if (b2TestOverlap(node->aabb, segmentAABB) == false) 0243 { 0244 continue; 0245 } 0246 0247 // Separating axis for segment (Gino, p80). 0248 // |dot(v, p1 - c)| > dot(|v|, h) 0249 b2Vec2 c = node->aabb.GetCenter(); 0250 b2Vec2 h = node->aabb.GetExtents(); 0251 float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); 0252 if (separation > 0.0f) 0253 { 0254 continue; 0255 } 0256 0257 if (node->IsLeaf()) 0258 { 0259 b2RayCastInput subInput; 0260 subInput.p1 = input.p1; 0261 subInput.p2 = input.p2; 0262 subInput.maxFraction = maxFraction; 0263 0264 float32 value = callback->RayCastCallback(subInput, nodeId); 0265 0266 if (value == 0.0f) 0267 { 0268 // The client has terminated the ray cast. 0269 return; 0270 } 0271 0272 if (value > 0.0f) 0273 { 0274 // Update segment bounding box. 0275 maxFraction = value; 0276 b2Vec2 t = p1 + maxFraction * (p2 - p1); 0277 segmentAABB.lowerBound = b2Min(p1, t); 0278 segmentAABB.upperBound = b2Max(p1, t); 0279 } 0280 } 0281 else 0282 { 0283 stack.Push(node->child1); 0284 stack.Push(node->child2); 0285 } 0286 } 0287 } 0288 0289 #endif