Cafu Engine
OrthoBspTree.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_ORTHO_BSP_TREE_HPP_INCLUDED
8 #define CAFU_ORTHO_BSP_TREE_HPP_INCLUDED
9 
10 #include "Math3D/BoundingBox.hpp"
11 
12 
13 class MapElementT;
14 
15 
16 /// This class represents an orthogonal BSP tree (axis-aligned split planes) that spatially organizes MapElementT instances.
17 ///
18 /// A map element is generally linked in each leaf that it intersects, or instead whenever possible in the node closest to the
19 /// root where the element intersects *all* children.
20 /// Note that the latter is an optional feature that yields a tree that is logically equivalent to the pure "store all contents
21 /// in leaves" strategy (where nodes generally remain empty and store no contents at all), but in comparison saves some storage.
22 /// Also note the subtle difference to storing some contents in nodes (the elements that intersect a split plane) and some (the
23 /// rest) in leaves, like ancient version of our CaBSP: Keeping some contents in nodes like this would make it impossible to
24 /// determine the contents (the set of all map elements) that are inside a given node, because the set would be grossly oversized.
25 /// Our "extended leaves-only" approach saves both storage and is able to produce for each node the exact set of map elements
26 /// (required e.g. for view frustum tests).
27 ///
28 /// Another feature of this implementation is that the bounding-box of a node is usually *not* the tight bounding-box over its
29 /// contents, but typically larger:
30 /// The bounding-box of the root node is the maximum bounds of the world, the bounding-box of its children is determined by
31 /// subdividing it along the split plane, etc. As such, the bounding-boxes in the tree only depend on the split planes, but not
32 /// directly on the contents of the nodes (and thus the BB member of the NodeT class is const).
33 ///
34 /// Finally, note how these larger bounding-boxes affect the tree structure and size. There are two important differences:
35 /// 1. Where we would not have node planes at the outmost brush faces with a "tight" starting box, our approach definitively
36 /// comes up with these outmost walls as split planes sooner or later. This enlarges the tree, but these extra nodes are
37 /// fortunately not completely useless: When the user extends the map spatially, the extra nodes come in just handy.
38 /// 2. The center of our larger boxes is often different from the center of the tight bounding-boxes, as the tight boxes are
39 /// usually not symmetric to the origin. This causes different split planes to be chosen when the tree is built.
40 /// As with issue 1. though, this difference is not a principal or serious problem.
42 {
43  public:
44 
45  class NodeT
46  {
47  public:
48 
49  /// As the nodes of the tree are not subdivided by arbitrary planes, but only by planes that are parallel
50  /// to the major axes, we do not store a full Plane3T<> member with the nodes, but only a "compacted" representation:
51  /// The type expresses which axes the plane is parallel to, the distance is the offset from the origin.
53  {
54  NONE=-1, ///< No plane at all. Used for nodes that are actually leaves.
55  ALONG_X, ///< A plane with normal vector (1, 0, 0), parallel to the y- and z-axis.
56  ALONG_Y, ///< A plane with normal vector (0, 1, 0), parallel to the x- and z-axis.
57  ALONG_Z ///< A plane with normal vector (0, 0, 1), parallel to the x- and y-axis.
58  };
59 
60 
61  /// The constructor.
62  /// @param BB The bounding box of this node (one "half" of the box of the parent).
63  NodeT(const BoundingBox3fT& BB);
64 
65  /// The destructor.
66  ~NodeT();
67 
68  PlaneTypeE GetPlaneType() const { return m_PlaneType; }
69  float GetPlaneDist() const { return m_PlaneDist; }
70  const NodeT* GetChild(unsigned int ChildNr) const { return m_Children[ChildNr]; }
71  const ArrayT<MapElementT*>& GetElems() const { return m_Elems; }
72  const BoundingBox3fT& GetBB() const { return m_BB; }
73 
74  /// Returns the number of nodes in the (sub-)tree at and below this node.
75  unsigned long GetNumNodes() const;
76 
77  /// Determines an axis-aligned split plane for further BSP partitioning of the contents of this node.
78  /// For choosing the split plane, the method considers the bounding-box planes of all objects (polygons, brushes, terrains)
79  /// of this node and all its ancestors, provided that they are wholly or partially in BB.
80  /// When a split plane was found, the m_PlaneType and m_PlaneDist members are appropriately set and true is returned,
81  /// otherwise they are initialized with NONE and 0, respectively, and the return value is false.
82  /// @returns whether a split plane has successfully been determined.
83  bool DetermineSplitPlane();
84 
85  /// Determines whether the given BB intersects (is partly inside) each child of this node.
86  /// @param BB The bounding box that is tested for intersection.
87  bool IntersectsAllChildren(const BoundingBox3fT& BB) const;
88 
89  /// Finds any map elements in the (sub-)tree whose spatial position disagrees with their position in the tree.
90  void FindMismatches(ArrayT<MapElementT*>& Mismatches) const;
91 
92  /// Recursively inserts the given element into the (sub-)tree at and below this node.
93  void Insert(MapElementT* Elem);
94 
95  /// Removes the given element from the (sub-)tree at and below this node (the structure of the tree remains unchanged).
96  void Remove(MapElementT* Elem);
97 
98 
99  private:
100 
101  friend class OrthoBspTreeT;
102 
103  NodeT(const NodeT&); ///< Use of the Copy Constructor is not allowed.
104  void operator = (const NodeT&); ///< Use of the Assignment Operator is not allowed.
105 
106  PlaneTypeE m_PlaneType; ///< The type of the plane that subdivides this node (no plane at all, normal vector along the x-, y- or z-axis).
107  float m_PlaneDist; ///< The distance of the plane to the origin. Corresponds to the Plane3fT::Dist member in a full plane.
108  NodeT* m_Parent; ///< The parent of this node, NULL if this is the root node.
109  NodeT* m_Children[2]; ///< The children of this node at each side of the plane (NULL if there is no plane / the node is a leaf).
110  ArrayT<MapElementT*> m_Elems; ///< The list of map elements in this node.
111  const BoundingBox3fT m_BB; ///< The bounding-box of this node.
112  };
113 
114 
115  /// The constructor.
116  OrthoBspTreeT(const ArrayT<MapElementT*>& Elems, const BoundingBox3fT& BB);
117 
118  /// The destructor.
119  ~OrthoBspTreeT();
120 
121  /// Returns the BSP trees root node.
122  const NodeT* GetRootNode() const { return m_RootNode; }
123 
124  /// Inserts the given element into the tree (the structure of the tree remains unchanged).
125  void Insert(MapElementT* Elem) { m_RootNode->Insert(Elem); }
126 
127  /// Removes the given element from the tree (the structure of the tree remains unchanged).
128  void Remove(MapElementT* Elem) { m_RootNode->Remove(Elem); }
129 
130  /// Removes and re-inserts map elements from and into the tree whose bounding-box changed so that it disagrees with the tree structure.
131  /// This method is called once per "document frame" in ChildFrameT::OnIdle().
132  /// @returns the number of map elements that have been updated.
133  unsigned long Update();
134 
135 
136  private:
137 
138  OrthoBspTreeT(const OrthoBspTreeT&); ///< Use of the Copy Constructor is not allowed.
139  void operator = (const OrthoBspTreeT&); ///< Use of the Assignment Operator is not allowed.
140 
141  void BuildTree(NodeT* node);
142 
143  NodeT* m_RootNode;
144 };
145 
146 #endif
PlaneTypeE
As the nodes of the tree are not subdivided by arbitrary planes, but only by planes that are parallel...
Definition: OrthoBspTree.hpp:52
~NodeT()
The destructor.
Definition: OrthoBspTree.cpp:26
void Remove(MapElementT *Elem)
Removes the given element from the tree (the structure of the tree remains unchanged).
Definition: OrthoBspTree.hpp:128
unsigned long Update()
Removes and re-inserts map elements from and into the tree whose bounding-box changed so that it disa...
Definition: OrthoBspTree.cpp:244
A plane with normal vector (0, 0, 1), parallel to the x- and y-axis.
Definition: OrthoBspTree.hpp:57
bool DetermineSplitPlane()
Determines an axis-aligned split plane for further BSP partitioning of the contents of this node...
Definition: OrthoBspTree.cpp:51
const NodeT * GetRootNode() const
Returns the BSP trees root node.
Definition: OrthoBspTree.hpp:122
No plane at all. Used for nodes that are actually leaves.
Definition: OrthoBspTree.hpp:54
OrthoBspTreeT(const ArrayT< MapElementT * > &Elems, const BoundingBox3fT &BB)
The constructor.
Definition: OrthoBspTree.cpp:227
void Insert(MapElementT *Elem)
Recursively inserts the given element into the (sub-)tree at and below this node. ...
Definition: OrthoBspTree.cpp:176
NodeT(const BoundingBox3fT &BB)
The constructor.
Definition: OrthoBspTree.cpp:13
void Remove(MapElementT *Elem)
Removes the given element from the (sub-)tree at and below this node (the structure of the tree remai...
Definition: OrthoBspTree.cpp:203
Definition: OrthoBspTree.hpp:45
void FindMismatches(ArrayT< MapElementT * > &Mismatches) const
Finds any map elements in the (sub-)tree whose spatial position disagrees with their position in the ...
Definition: OrthoBspTree.cpp:146
bool IntersectsAllChildren(const BoundingBox3fT &BB) const
Determines whether the given BB intersects (is partly inside) each child of this node.
Definition: OrthoBspTree.cpp:131
~OrthoBspTreeT()
The destructor.
Definition: OrthoBspTree.cpp:238
A plane with normal vector (0, 1, 0), parallel to the x- and z-axis.
Definition: OrthoBspTree.hpp:56
A plane with normal vector (1, 0, 0), parallel to the y- and z-axis.
Definition: OrthoBspTree.hpp:55
This class represents an orthogonal BSP tree (axis-aligned split planes) that spatially organizes Map...
Definition: OrthoBspTree.hpp:41
unsigned long GetNumNodes() const
Returns the number of nodes in the (sub-)tree at and below this node.
Definition: OrthoBspTree.cpp:33
This is the base class for all elements ("objects") that can exist in a map.
Definition: MapElement.hpp:57
void Insert(MapElementT *Elem)
Inserts the given element into the tree (the structure of the tree remains unchanged).
Definition: OrthoBspTree.hpp:125