1 | // ===================================================================
|
---|
2 | // $Id: $
|
---|
3 | //
|
---|
4 | // ktb.h
|
---|
5 | // definition of classes for CKTB tree building up and traversal
|
---|
6 | //
|
---|
7 | // Class: CKTBNodeAbstract, SKTBNode, CKTBAllocMan, CKTBNodeIterator
|
---|
8 | //
|
---|
9 | // REPLACEMENT_STRING
|
---|
10 | //
|
---|
11 | // Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz"
|
---|
12 | // Initial coding by Vlasta Havran, February 2007
|
---|
13 |
|
---|
14 | #ifndef __KTB8B_H__
|
---|
15 | #define __KTB8B_H__
|
---|
16 |
|
---|
17 | // GOLEM headers
|
---|
18 | #include "configh.h"
|
---|
19 | #include "AxisAlignedBox3.h"
|
---|
20 | #include "Intersectable.h"
|
---|
21 | #include "Containers.h"
|
---|
22 | #include "allocgo2.h"
|
---|
23 | #include "ktbconf.h"
|
---|
24 | #include "sbbox.h"
|
---|
25 | #include "Ray.h"
|
---|
26 |
|
---|
27 | // standard headers
|
---|
28 | #include <vector>
|
---|
29 |
|
---|
30 |
|
---|
31 | namespace GtpVisibilityPreprocessor {
|
---|
32 |
|
---|
33 | // Forward declarations
|
---|
34 |
|
---|
35 | // Use 8 Bytes representation
|
---|
36 | #undef SKTBNodeT
|
---|
37 | #define SKTBNodeT CKTB8BNodeAbstract::SKTBNode
|
---|
38 |
|
---|
39 | //===============================================
|
---|
40 | // Representation of one node of CKTB
|
---|
41 | class CKTB8BNodeAbstract
|
---|
42 | {
|
---|
43 | public:
|
---|
44 | // maximal height of the CKTB tree
|
---|
45 | enum { MAX_HEIGHT = 32, MaskForOffset = 0xFFFFFFF8 };
|
---|
46 |
|
---|
47 | // the basic element of CKTB tree .. node of tree
|
---|
48 | // it must be accessible by more classes
|
---|
49 |
|
---|
50 | // but must be declared because of compilation
|
---|
51 | struct SKTBNode {
|
---|
52 | // SKTBNode *left; // pointer to the left child is implict in DFS order
|
---|
53 | union {
|
---|
54 | // here is the compressed version of the axis
|
---|
55 | unsigned char *pointer;
|
---|
56 | unsigned int offset;
|
---|
57 | int depth;
|
---|
58 | };
|
---|
59 | union {
|
---|
60 | float splitPlane; // the position of splitting plane
|
---|
61 | ObjectContainer *objlist; // object list for a leaf or tagged interior node
|
---|
62 | Intersectable *object; // the pointer to the object, if only one object
|
---|
63 | SBBox *encbox; // enclosing bounding box for this node
|
---|
64 | SBBox *minbox; // minimum bounding box for this node
|
---|
65 | SKTBNodeT *linkedNode; // the linked node
|
---|
66 | SKTBNodeT *parentBoxNode; // the pointer to the same node type
|
---|
67 | };
|
---|
68 |
|
---|
69 | bool IsLeaf() const {
|
---|
70 | return ( CKTBAxes::Axes(offset & CKTBAxes::EE_Mask) == CKTBAxes::EE_Leaf);
|
---|
71 | }
|
---|
72 | bool IsEmptyLeaf() const {
|
---|
73 | return (this == 0);
|
---|
74 | }
|
---|
75 | }; // struct SKTBNode
|
---|
76 |
|
---|
77 | public:
|
---|
78 |
|
---|
79 | // It was _KTB_R2
|
---|
80 | // default constructor
|
---|
81 | CKTB8BNodeAbstract() { }
|
---|
82 | // default destructor
|
---|
83 | ~CKTB8BNodeAbstract() {}
|
---|
84 |
|
---|
85 | bool IsEmptyLeaf_(const SKTBNodeT *p) const {
|
---|
86 | assert(( CKTBAxes::Axes(p->offset & CKTBAxes::EE_Mask) == CKTBAxes::EE_Leaf));
|
---|
87 | return (p->objlist == NULL);
|
---|
88 | }
|
---|
89 |
|
---|
90 | bool IsFullLeaf_(const SKTBNodeT *p) const {
|
---|
91 | return (( CKTBAxes::Axes(p->offset & CKTBAxes::EE_Mask) == CKTBAxes::EE_Leaf) &&
|
---|
92 | (p->objlist != NULL));
|
---|
93 | }
|
---|
94 |
|
---|
95 | bool IsLeaf_(const SKTBNodeT *p) const
|
---|
96 | { return ( CKTBAxes::Axes(p->offset & CKTBAxes::EE_Mask) == CKTBAxes::EE_Leaf); }
|
---|
97 |
|
---|
98 | bool HasMinBox_(const SKTBNodeT *p) const
|
---|
99 | { return (CKTBAxes::Axes(p->offset & CKTBAxes::EE_Mask) >= CKTBAxes::EE_X_axisBox); }
|
---|
100 |
|
---|
101 | // ------------------------------------------------------
|
---|
102 | // Common functions for iterator and allocator
|
---|
103 |
|
---|
104 | float GetSplitValue(const SKTBNodeT *nodep) const {
|
---|
105 | return nodep->splitPlane;
|
---|
106 | }
|
---|
107 |
|
---|
108 | CKTBAxes::Axes GetNodeType(const SKTBNodeT *nodep) const {
|
---|
109 | return (CKTBAxes::Axes)(nodep->offset & 0x7);
|
---|
110 | }
|
---|
111 | SKTBNodeT* GetLeft(const SKTBNode *nodep) const {
|
---|
112 | return (SKTBNodeT*)(nodep+1); // We assume linking in DFS order
|
---|
113 | }
|
---|
114 | SKTBNodeT* GetRight(const SKTBNodeT *nodep) const {
|
---|
115 | // We assume 8-Bytes aligned nodes in memory in 32-Bits environment
|
---|
116 | // This has to be checked during node linking.
|
---|
117 | return (SKTBNodeT*)(nodep->offset & MaskForOffset);
|
---|
118 | }
|
---|
119 |
|
---|
120 | SKTBNodeT* GetLinkNode(const SKTBNodeT *nodep) const {
|
---|
121 | // We assume 8-Bytes aligned nodes in memory in 32-Bits environment
|
---|
122 | // This has to be checked during node linking.
|
---|
123 | return (SKTBNodeT*)(nodep->linkedNode);
|
---|
124 | }
|
---|
125 | // We assume linking in DFS order, this is for EncBox
|
---|
126 | SKTBNodeT* GetLeftLong(const SKTBNodeT *nodep) const {
|
---|
127 | return (SKTBNodeT*)(((char*)nodep) + 4*sizeof(SKTBNode));
|
---|
128 | }
|
---|
129 | SKTBNode* GetParentBoxNode(const SKTBNode *nodep) const {
|
---|
130 | return (SKTBNode*)(nodep+1)->parentBoxNode;
|
---|
131 | }
|
---|
132 |
|
---|
133 | #ifdef _SHORT_FORM_MINBOX
|
---|
134 | SKTBNode* GetLeftMinBox(const SKTBNode *nodep) const {
|
---|
135 | return (SKTBNode*)(nodep+2);
|
---|
136 | }
|
---|
137 | int GetDepth(const SKTBNode * /*nodep*/) const {
|
---|
138 | return 0; // depth was not stored
|
---|
139 | }
|
---|
140 | #else
|
---|
141 | SKTBNode* GetLeftMinBox(const SKTBNode *nodep) const {
|
---|
142 | return (SKTBNode*)(((char*)nodep) + 5*sizeof(SKTBNode));
|
---|
143 | }
|
---|
144 | int GetDepth(const SKTBNode *nodep) const {
|
---|
145 | return (int)((nodep+1)->depth);
|
---|
146 | }
|
---|
147 | #endif // _SHORT_FORM_MINBOX
|
---|
148 |
|
---|
149 | }; // CKTBNodeAbstract
|
---|
150 |
|
---|
151 | //----------------------------------------------------------------
|
---|
152 | // this class should be used as the base class for allocating
|
---|
153 | // and connecting the nodes in the CKTB tree and for
|
---|
154 | // for manipulating the nodes during building up
|
---|
155 | class CKTB8BAllocMan:
|
---|
156 | public CKTB8BNodeAbstract
|
---|
157 | {
|
---|
158 | protected:
|
---|
159 | #ifdef LEAVES_ARRAYS
|
---|
160 | CObjectArray arrayAlloc;
|
---|
161 | #endif
|
---|
162 |
|
---|
163 | // the direction of traversal through CKTB tree
|
---|
164 | enum EDirection { LEFT = 0, RIGHT = 1, NOWHERE = 2 };
|
---|
165 |
|
---|
166 | //#ifdef _KTB_R2
|
---|
167 | SKTBNodeT* _AllocEmptyLeaf() {
|
---|
168 | #ifdef _KTB_CONSTR_STATS
|
---|
169 | _stats_emptyLeftNodeCount++;
|
---|
170 | #endif
|
---|
171 | return (SKTBNodeT*)0;
|
---|
172 | }
|
---|
173 | protected:
|
---|
174 | // data required as the input parameter for construction of CKTB tree
|
---|
175 | int maxDepthAllowed; // maximal depth of CKTB tree
|
---|
176 | int maxListLength; // maximal list length of CKTB tree
|
---|
177 | public:
|
---|
178 | // default constructor
|
---|
179 | CKTB8BAllocMan() { InitForConstructor(); }
|
---|
180 |
|
---|
181 | // default destructor
|
---|
182 | ~CKTB8BAllocMan() { }
|
---|
183 |
|
---|
184 | // init the stack of auxiliary variables from min to max
|
---|
185 | void InitAux(int min, int max, int maxItemsAtOnce);
|
---|
186 |
|
---|
187 | // forget the content that is created by previous kd-tree construction
|
---|
188 | // or just init for the first use.
|
---|
189 | void InitForConstructor();
|
---|
190 |
|
---|
191 | // the function, which reads the parameters from envinroment/commandline
|
---|
192 | void InitPars();
|
---|
193 |
|
---|
194 | // -------------------------------------------------------
|
---|
195 | // allocate and free functions for SKTBNode
|
---|
196 | CAllocContinuous *alloc2; // the allocator saving space
|
---|
197 | SKTBNodeT *root; // this is the root node of the whole tree
|
---|
198 |
|
---|
199 | // This is the node to return from the allocation functions
|
---|
200 | // Here it can be implemented some linking when DFS order allocation,
|
---|
201 | // so the node can be different than the representation of the real
|
---|
202 | // node with the information
|
---|
203 | SKTBNodeT *nodeToLink;
|
---|
204 |
|
---|
205 | // Create the representation of the interior node
|
---|
206 | SKTBNodeT* AllocInteriorNode(int axis, float position,
|
---|
207 | int cntLeft, int cntRight);
|
---|
208 |
|
---|
209 | // Create the representation of the interior node with box, where box
|
---|
210 | // can be used during the traversal
|
---|
211 | SKTBNodeT* AllocInteriorNodeWithBox(int axis, float position,
|
---|
212 | int cntLeft, int cntRight,
|
---|
213 | const SBBox &tsbox, SKTBNodeT* prevMinBoxNode,
|
---|
214 | int depthStore);
|
---|
215 |
|
---|
216 | // Create the representation of the node with the bounding box
|
---|
217 | SKTBNodeT* AllocEncBoxNode(const SBBox &sbox);
|
---|
218 |
|
---|
219 | // Create the representation of the leaf. Note that possibly there
|
---|
220 | // can be special cases, such as 0, 1, 2, or 3 objects, or in general
|
---|
221 | // N objects.
|
---|
222 | SKTBNodeT* AllocLeaf(int cntObjects);
|
---|
223 |
|
---|
224 | ObjectContainer* GetObjList(const SKTBNodeT *nodep) const {
|
---|
225 | return nodep->objlist;
|
---|
226 | }
|
---|
227 |
|
---|
228 | // -------------------------------------------------------
|
---|
229 | // linking and setting functions for CKTB tree
|
---|
230 |
|
---|
231 | // Set the pointers to children for the interior node
|
---|
232 | void SetInteriorNodeLinks(SKTBNodeT *node,
|
---|
233 | SKTBNodeT *leftChild,
|
---|
234 | SKTBNodeT *rightChild);
|
---|
235 |
|
---|
236 | void SetInteriorNodeLeft(SKTBNodeT *node,
|
---|
237 | SKTBNodeT *leftChild);
|
---|
238 | void SetInteriorNodeRight(SKTBNodeT *node,
|
---|
239 | SKTBNodeT *rightChild);
|
---|
240 |
|
---|
241 | // Set the objects list to the leaf. The object list is used as it is
|
---|
242 | // ... it is not copied !!
|
---|
243 | int SetFullLeaf(SKTBNodeT *node, const ObjectContainer *objlist);
|
---|
244 |
|
---|
245 | // -------------------------------------------------------
|
---|
246 | // inquiry functions for CKTB tree nodes for current node
|
---|
247 |
|
---|
248 | // returns the pointer to the root node of tree
|
---|
249 | SKTBNodeT* GetRootNode() { return root;}
|
---|
250 |
|
---|
251 | // postprocessing of CKTB tree after its initial construction
|
---|
252 | virtual void PostBuild();
|
---|
253 |
|
---|
254 | // provides the information on the method used for CKTB tree
|
---|
255 | // and some setting parameters to given stream
|
---|
256 | virtual void ProvideID(ostream &app) = 0;
|
---|
257 |
|
---|
258 | // ---- Get Statistical Data ---------------------------------
|
---|
259 | void GetKTBTreeStats(int &nodes, int &leaves, int &emptyLeaves)
|
---|
260 | {
|
---|
261 | #ifdef _KTB_CONSTR_STATS
|
---|
262 | nodes = _stats_interiorCount + _stats_bboxCount + _stats_minbboxCount +
|
---|
263 | + _stats_leafNodeCount + _stats_emptyLeftNodeCount;
|
---|
264 | leaves = _stats_leafNodeCount + _stats_emptyLeftNodeCount;
|
---|
265 | emptyLeaves = _stats_emptyLeftNodeCount;
|
---|
266 | #endif
|
---|
267 | }
|
---|
268 |
|
---|
269 | // constructs the CKTB tree for given objectlist and given bounding box
|
---|
270 | virtual SKTBNodeT* BuildUp(ObjectContainer &objlist,
|
---|
271 | const AxisAlignedBox3 &box,
|
---|
272 | bool verbose = true) = 0;
|
---|
273 |
|
---|
274 | // deletes all the structure starting from the root node
|
---|
275 | virtual void Remove();
|
---|
276 |
|
---|
277 | // The current depth in the tree
|
---|
278 | inline int GetDepth() const {return _currDepth;}
|
---|
279 | void IncDepth() {_currDepth++;}
|
---|
280 | void DecDepth() {_currDepth--;}
|
---|
281 |
|
---|
282 |
|
---|
283 | // --------------------------------------------------------------
|
---|
284 | // Statistics
|
---|
285 | public:
|
---|
286 | #ifdef _KTB_CONSTR_STATS
|
---|
287 | int _stats_interiorCount;
|
---|
288 | int _stats_bboxCount;
|
---|
289 | int _stats_minbboxCount;
|
---|
290 | int _stats_leafNodeCount;
|
---|
291 | int _stats_emptyLeftNodeCount;
|
---|
292 |
|
---|
293 | // maximal depth of the currently built path during building up
|
---|
294 | int _maxDepth;
|
---|
295 | // Sum of depths of leaf nodes (empty + full)
|
---|
296 | unsigned long int _sumLeafDepth;
|
---|
297 | // Sum of depths of empty leaves
|
---|
298 | unsigned long int _sumFullLeafDepth;
|
---|
299 | // The count of object references in leaves
|
---|
300 | unsigned long int _sumObjectRefCount;
|
---|
301 | // The maximum number of object references in a leaf
|
---|
302 | unsigned long int _maxObjectRefInLeaf;
|
---|
303 | // Surface area of leaves and interior nodes
|
---|
304 | float _sumSurfaceAreaLeaves;
|
---|
305 | float _sumSurfaceAreaMULcntLeaves;
|
---|
306 | float _sumSurfaceAreaInteriorNodes;
|
---|
307 | #endif
|
---|
308 |
|
---|
309 | // General statistics on the depth of current node
|
---|
310 | // the depth of the currently accessed node during building up
|
---|
311 | int _currDepth;
|
---|
312 | };
|
---|
313 |
|
---|
314 | //------------------------------------------------------
|
---|
315 | // class which enables to use some functions with direct
|
---|
316 | // access to the members of the tree
|
---|
317 | // traversal classes should be derived from this class
|
---|
318 | class CKTB8BNodeIterator:
|
---|
319 | public CKTB8BNodeAbstract
|
---|
320 | {
|
---|
321 | protected:
|
---|
322 | int rayOffset;
|
---|
323 | public:
|
---|
324 | // default constructor
|
---|
325 | CKTB8BNodeIterator();
|
---|
326 | // default destructor
|
---|
327 | ~CKTB8BNodeIterator() { }
|
---|
328 |
|
---|
329 | float GetSplitValue(const SKTBNodeT *nodep) const {
|
---|
330 | return nodep->splitPlane;
|
---|
331 | }
|
---|
332 |
|
---|
333 | ObjectContainer* GetObjList(const SKTBNodeT *nodep) const {
|
---|
334 | return nodep->objlist;
|
---|
335 | }
|
---|
336 | SBBox* GetEncBox(const SKTBNodeT *nodep) const {
|
---|
337 | // Here is the overlapping to save some memory !!!
|
---|
338 | return (SBBox*)(((char*)nodep)+8);
|
---|
339 | }
|
---|
340 |
|
---|
341 | #ifdef _SHORT_FORM_MINBOX
|
---|
342 | SBBox* GetMinBox(const SKTBNodeT *nodep) const {
|
---|
343 | return (SBBox*)((nodep+1)->pointer);
|
---|
344 | }
|
---|
345 | #else // _SHORT_FORM_MINBOX
|
---|
346 | SBBox* GetMinBox(const SKTBNodeT *nodep) const {
|
---|
347 | // Here is the overlapping to save some memory !!!
|
---|
348 | return (SBBox*)(((char*)nodep)+16);
|
---|
349 | }
|
---|
350 | #endif // _SHORT_FORM_MINBOX
|
---|
351 |
|
---|
352 | // test the objects in the full leaf p and if finds the closest intersection
|
---|
353 | // with object so tmin<= t <= tmax, returns the pointer to that
|
---|
354 | // object, t is returned in tmax
|
---|
355 | int TestFullLeaf(const SimpleRay &ray, const SKTBNodeT *p);
|
---|
356 | int TestFullLeaf(const SimpleRay &ray, const SKTBNode *p, int rayIndex);
|
---|
357 |
|
---|
358 | // test the objects in the full leaf and finds out any intersection
|
---|
359 | // in this case returns the pointer to the object, otherwise NULL
|
---|
360 | int HitAnyObj(const SimpleRay &ray, const SKTBNodeT *p);
|
---|
361 |
|
---|
362 | // ------------------------------------------------------------------------
|
---|
363 | // Only abstract functions to simplify the interface
|
---|
364 |
|
---|
365 | // this resets the nesting to start from the zero depth (root)
|
---|
366 | virtual void ResetTraversalDepth() = 0;
|
---|
367 |
|
---|
368 | // sets the bbox and the root node for this traversal class
|
---|
369 | virtual void Setup(const AxisAlignedBox3 &box, SKTBNodeT *Nroot) = 0;
|
---|
370 |
|
---|
371 | // Find a leaf or the minimum box containg a point.
|
---|
372 | virtual const SKTBNode* Locate(const Vector3& /*position*/);
|
---|
373 | }; // class CKTBNodeIterator
|
---|
374 |
|
---|
375 | }
|
---|
376 |
|
---|
377 | #endif // __KTB8B_H__
|
---|
378 |
|
---|