DynamicTree.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2009 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
22 #ifndef PLAYRHO_COLLISION_DYNAMICTREE_HPP
23 #define PLAYRHO_COLLISION_DYNAMICTREE_HPP
24 
27 
30 
31 #include <functional>
32 #include <type_traits>
33 #include <utility>
34 
35 namespace playrho {
36 namespace d2 {
37 
38 class Fixture;
39 class Body;
40 
72 {
73 public:
76 
77  class TreeNode;
78  struct UnusedData;
79  struct BranchData;
80  struct LeafData;
81  union VariantData;
82 
84  static PLAYRHO_CONSTEXPR inline Size GetInvalidSize() noexcept
85  {
86  return static_cast<Size>(-1);
87  }
88 
93 
95  static PLAYRHO_CONSTEXPR const auto InvalidHeight = static_cast<Height>(-1);
96 
98  static PLAYRHO_CONSTEXPR inline Height GetInvalidHeight() noexcept
99  {
100  return InvalidHeight;
101  }
102 
104  static PLAYRHO_CONSTEXPR inline bool IsUnused(Height value) noexcept
105  {
106  return value == GetInvalidHeight();
107  }
108 
110  static PLAYRHO_CONSTEXPR inline bool IsLeaf(Height value) noexcept
111  {
112  return value == 0;
113  }
114 
116  static PLAYRHO_CONSTEXPR inline bool IsBranch(Height value) noexcept
117  {
118  return !IsUnused(value) && !IsLeaf(value);
119  }
120 
122  static PLAYRHO_CONSTEXPR inline Size GetDefaultInitialNodeCapacity() noexcept;
123 
125  DynamicTree() noexcept;
126 
128  explicit DynamicTree(Size nodeCapacity);
129 
131  ~DynamicTree() noexcept;
132 
134  DynamicTree(const DynamicTree& other);
135 
137  DynamicTree(DynamicTree&& other) noexcept;
138 
145  DynamicTree& operator= (DynamicTree other) noexcept;
146 
154  Size CreateLeaf(const AABB& aabb, const LeafData& data);
155 
159  void DestroyLeaf(Size index) noexcept;
160 
165  void UpdateLeaf(Size index, const AABB& aabb);
166 
171  LeafData GetLeafData(Size index) const noexcept;
172 
174  void SetLeafData(Size index, LeafData value) noexcept;
175 
179  AABB GetAABB(Size index) const noexcept;
180 
183  Height GetHeight(Size index) const noexcept;
184 
191  Size GetOther(Size index) const noexcept;
192 
195  BranchData GetBranchData(Size index) const noexcept;
196 
201  Size GetRootIndex() const noexcept;
202 
204  Size GetFreeIndex() const noexcept;
205 
209  void RebuildBottomUp();
210 
215  void ShiftOrigin(Length2 newOrigin);
216 
218  Size GetNodeCapacity() const noexcept;
219 
222  Size GetNodeCount() const noexcept;
223 
226  Size GetLeafCount() const noexcept;
227 
232  Size FindReference(Size index) const noexcept;
233 
237  friend void swap(DynamicTree& lhs, DynamicTree& rhs) noexcept;
238 
239 private:
240 
242  void SetNodeCapacity(Size value) noexcept;
243 
247  Size AllocateNode() noexcept;
248 
251  Size AllocateNode(const LeafData& data, AABB aabb) noexcept;
252 
256  Size AllocateNode(const BranchData& data, AABB aabb, Height height,
257  Size parent = GetInvalidSize()) noexcept;
258 
268  void FreeNode(Size index) noexcept;
269 
270  TreeNode* m_nodes{nullptr};
271  Size m_rootIndex{GetInvalidSize()};
272  Size m_freeIndex{GetInvalidSize()};
273  Size m_nodeCount{0u};
274  Size m_nodeCapacity{0u};
275  Size m_leafCount{0u};
276 };
277 
281 {
282  // Intentionally empty.
283 };
284 
287 {
290 };
291 
299 {
300  // In terms of what needs to be in this structure, it minimally needs to have enough
301  // information in it to identify the child shape for which the node's AABB represents,
302  // and its associated body. A pointer to the fixture and the index of the child in
303  // its shape could suffice for this. Meanwhile, a Contact is defined to be the
304  // recognition of an overlap between two child shapes having different bodies making
305  // the caching of the bodies a potential speed-up opportunity.
306 
316 
324 
327 };
328 
332  const DynamicTree::LeafData& rhs) noexcept
333 {
334  return lhs.fixture == rhs.fixture && lhs.childIndex == rhs.childIndex;
335 }
336 
340  const DynamicTree::LeafData& rhs) noexcept
341 {
342  return !(lhs == rhs);
343 }
344 
348 {
351 
354 
357 
359  VariantData() noexcept = default;
360 
362  PLAYRHO_CONSTEXPR inline VariantData(UnusedData value) noexcept: unused{value} {}
363 
365  PLAYRHO_CONSTEXPR inline VariantData(LeafData value) noexcept: leaf{value} {}
366 
368  PLAYRHO_CONSTEXPR inline VariantData(BranchData value) noexcept: branch{value} {}
369 };
370 
374 PLAYRHO_CONSTEXPR inline bool IsUnused(const DynamicTree::TreeNode& node) noexcept;
375 
380 PLAYRHO_CONSTEXPR inline bool IsLeaf(const DynamicTree::TreeNode& node) noexcept;
381 
386 PLAYRHO_CONSTEXPR inline bool IsBranch(const DynamicTree::TreeNode& node) noexcept;
387 
396 {
397 public:
398  ~TreeNode() = default;
399 
401  PLAYRHO_CONSTEXPR inline TreeNode(const TreeNode& other) = default;
402 
404  PLAYRHO_CONSTEXPR inline TreeNode(TreeNode&& other) = default;
405 
407  PLAYRHO_CONSTEXPR inline explicit TreeNode(Size other = DynamicTree::GetInvalidSize()) noexcept:
408  m_other{other}
409  {
410  assert(IsUnused(m_height));
411  }
412 
414  PLAYRHO_CONSTEXPR inline TreeNode(const LeafData& value, AABB aabb,
415  Size other = DynamicTree::GetInvalidSize()) noexcept:
416  m_height{0}, m_other{other}, m_aabb{aabb}, m_variant{value}
417  {
418  // Intentionally empty.
419  }
420 
422  PLAYRHO_CONSTEXPR inline TreeNode(const BranchData& value, AABB aabb, Height height,
423  Size other = DynamicTree::GetInvalidSize()) noexcept:
424  m_height{height}, m_other{other}, m_aabb{aabb}, m_variant{value}
425  {
426  assert(IsBranch(height));
427  assert(value.child1 != GetInvalidSize());
428  assert(value.child2 != GetInvalidSize());
429  }
430 
432  TreeNode& operator= (const TreeNode& other) = default;
433 
435  PLAYRHO_CONSTEXPR inline Height GetHeight() const noexcept
436  {
437  return m_height;
438  }
439 
441  PLAYRHO_CONSTEXPR inline Size GetOther() const noexcept
442  {
443  return m_other;
444  }
445 
447  PLAYRHO_CONSTEXPR inline void SetOther(Size other) noexcept
448  {
449  m_other = other;
450  }
451 
454  PLAYRHO_CONSTEXPR inline AABB GetAABB() const noexcept
455  {
456  assert(!IsUnused(m_height));
457  return m_aabb;
458  }
459 
462  PLAYRHO_CONSTEXPR inline void SetAABB(AABB value) noexcept
463  {
464  assert(!IsUnused(m_height));
465  m_aabb = value;
466  }
467 
470  PLAYRHO_CONSTEXPR inline UnusedData AsUnused() const noexcept
471  {
472  assert(IsUnused(m_height));
473  return m_variant.unused;
474  }
475 
478  PLAYRHO_CONSTEXPR inline LeafData AsLeaf() const noexcept
479  {
480  assert(IsLeaf(m_height));
481  return m_variant.leaf;
482  }
483 
486  PLAYRHO_CONSTEXPR inline BranchData AsBranch() const noexcept
487  {
488  assert(IsBranch(m_height));
489  return m_variant.branch;
490  }
491 
493  PLAYRHO_CONSTEXPR inline void Assign(const UnusedData& v) noexcept
494  {
495  m_variant.unused = v;
496  m_height = static_cast<Height>(-1);
497  }
498 
500  PLAYRHO_CONSTEXPR inline void Assign(const LeafData& v) noexcept
501  {
502  m_variant.leaf = v;
503  m_height = 0;
504  }
505 
507  PLAYRHO_CONSTEXPR inline void Assign(const BranchData& v, const AABB& bb, Height h) noexcept
508  {
509  assert(v.child1 != GetInvalidSize());
510  assert(v.child2 != GetInvalidSize());
511  assert(IsBranch(h));
512  m_variant.branch = v;
513  m_aabb = bb;
514  m_height = h;
515  }
516 
517 private:
522  Height m_height = GetInvalidHeight();
523 
527  Size m_other = DynamicTree::GetInvalidSize();
528 
532  AABB m_aabb;
533 
535  VariantData m_variant{UnusedData{}};
536 };
537 
539 {
540  return Size{64};
541 }
542 
544 {
545  assert((m_rootIndex == GetInvalidSize() && (m_leafCount == 0)) ||
546  ((m_rootIndex < m_nodeCapacity) && (m_leafCount > 0) && (GetOther(m_rootIndex) == GetInvalidSize())));
547  return m_rootIndex;
548 }
549 
551 {
552  return m_freeIndex;
553 }
554 
556 {
557  return m_nodeCapacity;
558 }
559 
561 {
562  return m_nodeCount;
563 }
564 
566 {
567  assert(((m_leafCount == 0) && (m_rootIndex == GetInvalidSize())) ||
568  ((m_leafCount > 0) && (m_rootIndex != GetInvalidSize()) && (GetOther(m_rootIndex) == GetInvalidSize())));
569  return m_leafCount;
570 }
571 
572 inline DynamicTree::Height DynamicTree::GetHeight(Size index) const noexcept
573 {
574  assert(index != GetInvalidSize());
575  assert(index < m_nodeCapacity);
576  return m_nodes[index].GetHeight();
577 }
578 
579 inline DynamicTree::Size DynamicTree::GetOther(Size index) const noexcept
580 {
581  assert(index != GetInvalidSize());
582  assert(index < m_nodeCapacity);
583  return m_nodes[index].GetOther();
584 }
585 
586 inline AABB DynamicTree::GetAABB(Size index) const noexcept
587 {
588  assert(index != GetInvalidSize());
589  assert(index < m_nodeCapacity);
590  assert(!IsUnused(m_nodes[index].GetHeight()));
591  return m_nodes[index].GetAABB();
592 }
593 
595 {
596  assert(index != GetInvalidSize());
597  assert(index < m_nodeCapacity);
598  assert(IsBranch(m_nodes[index].GetHeight()));
599  return m_nodes[index].AsBranch();
600 }
601 
603 {
604  assert(index != GetInvalidSize());
605  assert(index < m_nodeCapacity);
606  assert(IsLeaf(m_nodes[index].GetHeight()));
607  return m_nodes[index].AsLeaf();
608 }
609 
610 inline void DynamicTree::SetLeafData(Size index, LeafData value) noexcept
611 {
612  assert(index != GetInvalidSize());
613  assert(index < m_nodeCapacity);
614  assert(IsLeaf(m_nodes[index].GetHeight()));
615  m_nodes[index].AsLeaf() = value;
616 }
617 
618 // Free functions...
619 
623 {
624  assert(bd.child1 == oldChild || bd.child2 == oldChild);
625  return (bd.child1 == oldChild)?
626  DynamicTree::BranchData{newChild, bd.child2}: DynamicTree::BranchData{bd.child1, newChild};
627 }
628 
631 PLAYRHO_CONSTEXPR inline bool IsUnused(const DynamicTree::TreeNode& node) noexcept
632 {
633  return DynamicTree::IsUnused(node.GetHeight());
634 }
635 
640 PLAYRHO_CONSTEXPR inline bool IsLeaf(const DynamicTree::TreeNode& node) noexcept
641 {
642  return DynamicTree::IsLeaf(node.GetHeight());
643 }
644 
648 PLAYRHO_CONSTEXPR inline bool IsBranch(const DynamicTree::TreeNode& node) noexcept
649 {
650  return DynamicTree::IsBranch(node.GetHeight());
651 }
652 
656 {
657  assert(!IsUnused(node));
658  return node.GetAABB();
659 }
660 
665 {
666  assert(IsUnused(node));
667  return node.GetOther();
668 }
669 
673 inline DynamicTree::Height GetHeight(const DynamicTree& tree) noexcept
674 {
675  const auto index = tree.GetRootIndex();
676  return (index != DynamicTree::GetInvalidSize())? tree.GetHeight(index): DynamicTree::Height{0};
677 }
678 
684 inline AABB GetAABB(const DynamicTree& tree) noexcept
685 {
686  const auto index = tree.GetRootIndex();
687  return (index != DynamicTree::GetInvalidSize())? tree.GetAABB(index): AABB{};
688 }
689 
692 inline bool TestOverlap(const DynamicTree& tree,
693  DynamicTree::Size leafIdA, DynamicTree::Size leafIdB) noexcept
694 {
695  return TestOverlap(tree.GetAABB(leafIdA), tree.GetAABB(leafIdB));
696 }
697 
701 Length ComputeTotalPerimeter(const DynamicTree& tree) noexcept;
702 
706 Real ComputePerimeterRatio(const DynamicTree& tree) noexcept;
707 
713 DynamicTree::Height ComputeHeight(const DynamicTree& tree, DynamicTree::Size index) noexcept;
714 
716 inline DynamicTree::Height ComputeHeight(const DynamicTree& tree) noexcept
717 {
718  return ComputeHeight(tree, tree.GetRootIndex());
719 }
720 
724 bool ValidateStructure(const DynamicTree& tree, DynamicTree::Size index) noexcept;
725 
729 bool ValidateMetrics(const DynamicTree& tree, DynamicTree::Size index) noexcept;
730 
734 DynamicTree::Height GetMaxImbalance(const DynamicTree& tree) noexcept;
735 
738 {
739  End,
740  Continue,
741 };
742 
745 
748 void Query(const DynamicTree& tree, const AABB& aabb,
749  const DynamicTreeSizeCB& callback);
750 
753 using QueryFixtureCallback = std::function<bool(Fixture* fixture, ChildCounter child)>;
754 
759 void Query(const DynamicTree& tree, const AABB& aabb, QueryFixtureCallback callback);
760 
766 inline std::size_t size(const DynamicTree& tree) noexcept
767 {
768  return tree.GetLeafCount();
769 }
770 
771 } // namespace d2
772 } // namespace playrho
773 
774 #endif // PLAYRHO_COLLISION_DYNAMICTREE_HPP