Box2D 2.4.1
A 2D physics engine for games
Loading...
Searching...
No Matches
b2_dynamic_tree.h
1// MIT License
2
3// Copyright (c) 2019 Erin Catto
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#ifndef B2_DYNAMIC_TREE_H
24#define B2_DYNAMIC_TREE_H
25
26#include "b2_api.h"
27#include "b2_collision.h"
28#include "b2_growable_stack.h"
29
30#define b2_nullNode (-1)
31
33struct B2_API b2TreeNode
34{
35 bool IsLeaf() const
36 {
37 return child1 == b2_nullNode;
38 }
39
42
43 void* userData;
44
45 union
46 {
47 int32 parent;
48 int32 next;
49 };
50
51 int32 child1;
52 int32 child2;
53
54 // leaf = 0, free node = -1
55 int32 height;
56
57 bool moved;
58};
59
68class B2_API b2DynamicTree
69{
70public:
73
76
78 int32 CreateProxy(const b2AABB& aabb, void* userData);
79
81 void DestroyProxy(int32 proxyId);
82
87 bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
88
91 void* GetUserData(int32 proxyId) const;
92
93 bool WasMoved(int32 proxyId) const;
94 void ClearMoved(int32 proxyId);
95
97 const b2AABB& GetFatAABB(int32 proxyId) const;
98
101 template <typename T>
102 void Query(T* callback, const b2AABB& aabb) const;
103
111 template <typename T>
112 void RayCast(T* callback, const b2RayCastInput& input) const;
113
115 void Validate() const;
116
119 int32 GetHeight() const;
120
123 int32 GetMaxBalance() const;
124
126 float GetAreaRatio() const;
127
130
134 void ShiftOrigin(const b2Vec2& newOrigin);
135
136private:
137
138 int32 AllocateNode();
139 void FreeNode(int32 node);
140
141 void InsertLeaf(int32 node);
142 void RemoveLeaf(int32 node);
143
144 int32 Balance(int32 index);
145
146 int32 ComputeHeight() const;
147 int32 ComputeHeight(int32 nodeId) const;
148
149 void ValidateStructure(int32 index) const;
150 void ValidateMetrics(int32 index) const;
151
152 int32 m_root;
153
154 b2TreeNode* m_nodes;
155 int32 m_nodeCount;
156 int32 m_nodeCapacity;
157
158 int32 m_freeList;
159
160 int32 m_insertionCount;
161};
162
163inline void* b2DynamicTree::GetUserData(int32 proxyId) const
164{
165 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
166 return m_nodes[proxyId].userData;
167}
168
169inline bool b2DynamicTree::WasMoved(int32 proxyId) const
170{
171 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
172 return m_nodes[proxyId].moved;
173}
174
175inline void b2DynamicTree::ClearMoved(int32 proxyId)
176{
177 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
178 m_nodes[proxyId].moved = false;
179}
180
181inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
182{
183 b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
184 return m_nodes[proxyId].aabb;
185}
186
187template <typename T>
188inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
189{
191 stack.Push(m_root);
192
193 while (stack.GetCount() > 0)
194 {
195 int32 nodeId = stack.Pop();
196 if (nodeId == b2_nullNode)
197 {
198 continue;
199 }
200
201 const b2TreeNode* node = m_nodes + nodeId;
202
203 if (b2TestOverlap(node->aabb, aabb))
204 {
205 if (node->IsLeaf())
206 {
207 bool proceed = callback->QueryCallback(nodeId);
208 if (proceed == false)
209 {
210 return;
211 }
212 }
213 else
214 {
215 stack.Push(node->child1);
216 stack.Push(node->child2);
217 }
218 }
219 }
220}
221
222template <typename T>
223inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const
224{
225 b2Vec2 p1 = input.p1;
226 b2Vec2 p2 = input.p2;
227 b2Vec2 r = p2 - p1;
228 b2Assert(r.LengthSquared() > 0.0f);
229 r.Normalize();
230
231 // v is perpendicular to the segment.
232 b2Vec2 v = b2Cross(1.0f, r);
233 b2Vec2 abs_v = b2Abs(v);
234
235 // Separating axis for segment (Gino, p80).
236 // |dot(v, p1 - c)| > dot(|v|, h)
237
238 float maxFraction = input.maxFraction;
239
240 // Build a bounding box for the segment.
241 b2AABB segmentAABB;
242 {
243 b2Vec2 t = p1 + maxFraction * (p2 - p1);
244 segmentAABB.lowerBound = b2Min(p1, t);
245 segmentAABB.upperBound = b2Max(p1, t);
246 }
247
249 stack.Push(m_root);
250
251 while (stack.GetCount() > 0)
252 {
253 int32 nodeId = stack.Pop();
254 if (nodeId == b2_nullNode)
255 {
256 continue;
257 }
258
259 const b2TreeNode* node = m_nodes + nodeId;
260
261 if (b2TestOverlap(node->aabb, segmentAABB) == false)
262 {
263 continue;
264 }
265
266 // Separating axis for segment (Gino, p80).
267 // |dot(v, p1 - c)| > dot(|v|, h)
268 b2Vec2 c = node->aabb.GetCenter();
269 b2Vec2 h = node->aabb.GetExtents();
270 float separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
271 if (separation > 0.0f)
272 {
273 continue;
274 }
275
276 if (node->IsLeaf())
277 {
278 b2RayCastInput subInput;
279 subInput.p1 = input.p1;
280 subInput.p2 = input.p2;
281 subInput.maxFraction = maxFraction;
282
283 float value = callback->RayCastCallback(subInput, nodeId);
284
285 if (value == 0.0f)
286 {
287 // The client has terminated the ray cast.
288 return;
289 }
290
291 if (value > 0.0f)
292 {
293 // Update segment bounding box.
294 maxFraction = value;
295 b2Vec2 t = p1 + maxFraction * (p2 - p1);
296 segmentAABB.lowerBound = b2Min(p1, t);
297 segmentAABB.upperBound = b2Max(p1, t);
298 }
299 }
300 else
301 {
302 stack.Push(node->child1);
303 stack.Push(node->child2);
304 }
305 }
306}
307
308#endif
B2_API bool b2TestOverlap(const b2Shape *shapeA, int32 indexA, const b2Shape *shapeB, int32 indexB, const b2Transform &xfA, const b2Transform &xfB)
Determine if two generic shapes overlap.
Definition b2_dynamic_tree.h:69
float GetAreaRatio() const
Get the ratio of the sum of the node areas to the root area.
void Query(T *callback, const b2AABB &aabb) const
Definition b2_dynamic_tree.h:188
int32 GetMaxBalance() const
void DestroyProxy(int32 proxyId)
Destroy a proxy. This asserts if the id is invalid.
const b2AABB & GetFatAABB(int32 proxyId) const
Get the fat AABB for a proxy.
Definition b2_dynamic_tree.h:181
bool MoveProxy(int32 proxyId, const b2AABB &aabb1, const b2Vec2 &displacement)
b2DynamicTree()
Constructing the tree initializes the node pool.
~b2DynamicTree()
Destroy the tree, freeing the node pool.
void * GetUserData(int32 proxyId) const
Definition b2_dynamic_tree.h:163
void RebuildBottomUp()
Build an optimal tree. Very expensive. For testing.
int32 GetHeight() const
int32 CreateProxy(const b2AABB &aabb, void *userData)
Create a proxy. Provide a tight fitting AABB and a userData pointer.
void Validate() const
Validate this tree. For testing.
void RayCast(T *callback, const b2RayCastInput &input) const
Definition b2_dynamic_tree.h:223
void ShiftOrigin(const b2Vec2 &newOrigin)
Definition b2_growable_stack.h:35
An axis aligned bounding box.
Definition b2_collision.h:169
b2Vec2 GetExtents() const
Get the extents of the AABB (half-widths).
Definition b2_collision.h:180
b2Vec2 GetCenter() const
Get the center of the AABB.
Definition b2_collision.h:174
b2Vec2 lowerBound
the lower vertex
Definition b2_collision.h:220
b2Vec2 upperBound
the upper vertex
Definition b2_collision.h:221
Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
Definition b2_collision.h:154
A node in the dynamic tree. The client does not interact with this directly.
Definition b2_dynamic_tree.h:34
b2AABB aabb
Enlarged AABB.
Definition b2_dynamic_tree.h:41
A 2D column vector.
Definition b2_math.h:42
float LengthSquared() const
Definition b2_math.h:96
float Normalize()
Convert this vector into a unit vector. Returns the length.
Definition b2_math.h:102