Box2D  2.4.1
A 2D physics engine for games
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 
33 struct 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 
68 class B2_API b2DynamicTree
69 {
70 public:
72  b2DynamicTree();
73 
75  ~b2DynamicTree();
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 
129  void RebuildBottomUp();
130 
134  void ShiftOrigin(const b2Vec2& newOrigin);
135 
136 private:
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 
163 inline void* b2DynamicTree::GetUserData(int32 proxyId) const
164 {
165  b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
166  return m_nodes[proxyId].userData;
167 }
168 
169 inline bool b2DynamicTree::WasMoved(int32 proxyId) const
170 {
171  b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
172  return m_nodes[proxyId].moved;
173 }
174 
175 inline void b2DynamicTree::ClearMoved(int32 proxyId)
176 {
177  b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
178  m_nodes[proxyId].moved = false;
179 }
180 
181 inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
182 {
183  b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
184  return m_nodes[proxyId].aabb;
185 }
186 
187 template <typename T>
188 inline 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 
222 template <typename T>
223 inline 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
b2Vec2
A 2D column vector.
Definition: b2_math.h:41
b2DynamicTree
Definition: b2_dynamic_tree.h:68
b2AABB::GetExtents
b2Vec2 GetExtents() const
Get the extents of the AABB (half-widths).
Definition: b2_collision.h:180
b2DynamicTree::GetFatAABB
const b2AABB & GetFatAABB(int32 proxyId) const
Get the fat AABB for a proxy.
Definition: b2_dynamic_tree.h:181
b2TreeNode
A node in the dynamic tree. The client does not interact with this directly.
Definition: b2_dynamic_tree.h:33
b2AABB::lowerBound
b2Vec2 lowerBound
the lower vertex
Definition: b2_collision.h:220
b2RayCastInput
Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
Definition: b2_collision.h:153
b2GrowableStack
Definition: b2_growable_stack.h:34
b2AABB::GetCenter
b2Vec2 GetCenter() const
Get the center of the AABB.
Definition: b2_collision.h:174
b2DynamicTree::GetUserData
void * GetUserData(int32 proxyId) const
Definition: b2_dynamic_tree.h:163
b2Vec2::Normalize
float Normalize()
Convert this vector into a unit vector. Returns the length.
Definition: b2_math.h:102
b2DynamicTree::RayCast
void RayCast(T *callback, const b2RayCastInput &input) const
Definition: b2_dynamic_tree.h:223
b2AABB
An axis aligned bounding box.
Definition: b2_collision.h:168
b2TestOverlap
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.
b2_collision.h
b2AABB::upperBound
b2Vec2 upperBound
the upper vertex
Definition: b2_collision.h:221
b2TreeNode::aabb
b2AABB aabb
Enlarged AABB.
Definition: b2_dynamic_tree.h:41
b2Vec2::LengthSquared
float LengthSquared() const
Definition: b2_math.h:96
b2DynamicTree::Query
void Query(T *callback, const b2AABB &aabb) const
Definition: b2_dynamic_tree.h:188