1 //============================================================================
2 // File : SkyBVTreeSplitter.hpp
4 // Author : Wesley Hunt
6 // Content : NodeSplitter classes for SkyBVTrees using SkyBoundingBox or
7 // SkyBoundingSphere (not implemented).
9 //============================================================================
10 #ifndef __SKYBVTREESPLITTER_HPP__
11 #define __SKYBVTREESPLITTER_HPP__
13 //----------------------------------------------------------------------------
14 //-- Includes ----------------------------------------------------------------
15 //----------------------------------------------------------------------------
16 #include "SkyBVTree.hpp"
17 #include "SkyMinMaxBox.hpp"
18 //#include <Mlx/MlxBoundingSphere.hpp>
19 //#if _MSC_VER == 1200
20 //#include <Auxlib/AuxCompileTimeChecker.hpp>
22 //----------------------------------------------------------------------------
23 //-- Forward Declarations ----------------------------------------------------
24 //----------------------------------------------------------------------------
25 // A strategy for splitting nodes compatible with bounding boxes and spheres.
26 template<class Object> class SkyBoundingBoxSplitter;
27 // SkyBVTree compatible node splitters implemented using the above strategy.
28 template<class Object> class SkyAABBTreeSplitter;
29 //template<class Object> class SkySphereTreeSplitter;
31 //----------------------------------------------------------------------------
32 //-- Defines, Constants, Enumerated Types ------------------------------------
33 //----------------------------------------------------------------------------
34 const float rLongObjectPercentageTolerance = 0.75f;
36 //----------------------------------------------------------------------------
37 // SkyBoundingBoxSplitter
38 //----------------------------------------------------------------------------
39 // This class defines a NodeSplitter strategy that has the functionality
40 // required by SkyBVTree's NodeSplitter template class. Can be used with
41 // SkyMinMaxBox and SkyBoundingSphere.
43 // It defines a two-tiered split strategy:
45 // * First it tries to separate large objects from any smaller objects.
46 // * If there are no large objects, it splits along the midpoint of the longest
47 // axis defined by the objects.
48 // * Finally, if all else fails, it defines a total ordering along the longest
49 // axis based on the center of each node.
50 //----------------------------------------------------------------------------
51 template<class Object>
52 class SkyBoundingBoxSplitter
55 typedef SkyBaseBVTree<Object, SkyMinMaxBox>::NodeObject NodeObjectBox;
56 //typedef SkyBaseBVTree<Object, SkyBoundingSphere>::NodeObject NodeObjectSphere;
59 // !!! WRH HACK MSVC++6 SP5 Workaround.
60 // VC6 can't disambiguate this constructor because it doesn't consider the two
61 // NodeObject templates to be different classes for the purposes of
62 // overloading. It won't recognize that the second template parameters are
63 // different. Forcing them to be explicit template specializations fixes
66 SkyBoundingBoxSplitter(const SkyBaseBVTree<Object, BV>::NodeObject*, unsigned int)
68 //AUX_STATIC_CHECK(false, VisualC_6_WorkAround); ???
72 SkyBoundingBoxSplitter(const NodeObjectBox* pObjs, unsigned int iNumObjs)
74 for (unsigned int i = 0; i < iNumObjs; ++i)
76 _nodeBBox.Union(pObjs[i].GetBV());
78 Init(pObjs, iNumObjs);
80 /*#if _MSC_VER == 1200
83 SkyBoundingBoxSplitter(const NodeObjectSphere* objs,
91 for (int i=0; i<numObjs; ++i)
94 box.AddPoint(objs[i].GetBV().GetCenter());
95 box.Bloat(objs[i].GetBV().GetRadius());
101 template<class nodeObj>
102 bool SplitLeft(const nodeObj& obj) const
104 if (_bIsolateLongObjects)
105 return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength;
107 return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue;
110 template<class nodeObj>
111 bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const
113 return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV());
116 const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; }
119 template<class nodeObj>
120 void Init(const nodeObj* pObjs, unsigned int iNumObjs)
122 _iSplitAxis = FindSplitAxis(_nodeBBox);
123 _rSplitValue = FindSplitValue(_nodeBBox, _iSplitAxis);
124 _rMaxObjectLength = GetSplitAxisLength(_nodeBBox) * rLongObjectPercentageTolerance;
126 _bIsolateLongObjects = false;
127 for (unsigned int i = 0; i < iNumObjs; ++i)
129 if (GetSplitAxisLength(pObjs[i].GetBV()) > _rMaxObjectLength)
131 _bIsolateLongObjects = true;
137 int FindSplitAxis(const SkyMinMaxBox& bbox)
140 Vec3f vecExt = bbox.GetMax() - bbox.GetMin();
141 for (i = 1; i < 3; ++i) if (vecExt[i] > vecExt[iAxis]) iAxis = i;
144 float FindSplitValue(const SkyMinMaxBox& bbox, int iSplitAxis)
146 return (bbox.GetMin()[iSplitAxis] + bbox.GetMax()[iSplitAxis])*0.5f;
149 /*float GetSplitAxisLength(const SkyBoundingSphere& sphere) const
151 return 2.f*sphere.GetRadius();
153 float GetSplitAxisLength(const SkyMinMaxBox& bbox) const
155 return bbox.GetMax()[_iSplitAxis] - bbox.GetMin()[_iSplitAxis];
158 float GetSplitAxisCenter(const SkyMinMaxBox& bbox) const
160 return (bbox.GetMin()[_iSplitAxis] + bbox.GetMax()[_iSplitAxis]) * 0.5f;
162 /*float GetSplitAxisCenter(const SkyBoundingSphere& sphere) const
164 return sphere.GetCenter()[SplitAxis];
169 bool _bIsolateLongObjects;
170 float _rMaxObjectLength;
172 SkyMinMaxBox _nodeBBox;
175 //----------------------------------------------------------------------------
176 // SkyAABBTreeSplitter
177 //----------------------------------------------------------------------------
178 // A NodeSplitter that is compatible with SkyBVTree for SkyMinMaxBox.
179 // Implemented using the SkyBoundingBoxSplitter strategy.
180 //----------------------------------------------------------------------------
181 template<class Object>
182 class SkyAABBTreeSplitter
185 typedef SkyMinMaxBox BV;
186 typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
188 SkyAABBTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) {}
190 const BV& GetNodeBV() const { return _splitter.GetNodeBBox(); }
192 bool operator()(const NodeObject& obj) const
194 return _splitter.SplitLeft(obj);
197 bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
199 return _splitter.LessThan(obj1, obj2);
203 SkyBoundingBoxSplitter<Object> _splitter;
206 //----------------------------------------------------------------------------
207 // SkySphereTreeSplitter
208 //----------------------------------------------------------------------------
209 // A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere.
210 // Implemented using the SkyBoundingBoxSplitter strategy.
211 //----------------------------------------------------------------------------
212 /*template<class Object>
213 class SkySphereTreeSplitter
216 typedef SkyBoundingSphere BV;
217 typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
219 MlxSphereTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs)
221 _nodeBV = pObjs[0].GetBV();
222 for (unsigned int i = 1; i < iNumObjs; ++i) _nodeBV.Union(pObjs[i].GetBV());
225 const BV& GetNodeBV() const { return _nodeBV; }
227 bool operator()(const NodeObject& obj) const
229 return _splitter.SplitLeft(obj);
232 bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
234 return _splitter.LessThan(obj1, obj2);
239 SkyBoundingBoxSplitter<Object> _splitter;
242 #endif //__SKYBVTREESPLITTER_HPP__