1 /** @file gsKdNode.h
2 
3     @brief Provides declaration of the tree node.
4 
5     This file is part of the G+Smo library.
6 
7     This Source Code Form is subject to the terms of the Mozilla Public
8     License, v. 2.0. If a copy of the MPL was not distributed with this
9     file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11     Author(s): Mantzaflaris
12 */
13 
14 # pragma once
15 
16 namespace gismo {
17 
18 
19 /**
20     @brief Struct of for an Axis-aligned bounding box
21 
22     Template parameters
23     \param d is the dimension
24     \param Z is the box-coordinate index type
25 
26     \ingroup HSplines
27 */
28 template<short_t d, class Z = index_t>
29 struct gsAabb
30 {
31 public:
32     typedef gsVector<Z,d> point;
33 
gsAabbgsAabb34     gsAabb(const point & l, const point & u)
35     {
36         first  = l;
37         second = u;
38     }
39 
gsAabbgsAabb40     gsAabb(const point & u)
41     {
42         first.setZero();
43         second = u;
44     }
45 
46 public:
47 
48     //point lower;
49     //point upper;
50     point first;
51     point second;
52 
53     /// Level in which the box lives
54     int level ;
55 
56     // see http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
57     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
58 };
59 
60 /**
61     @brief Struct representing a kd-tree node
62 
63     The nodes are of two types:
64     - Split nodes
65     - Leaf nodes
66 
67     Template parameters
68     \param d is the dimension
69     \param Z is the box-coordinate index type
70 
71     \ingroup HSplines
72 */
73 template<short_t d, class Z = index_t>
74 struct kdnode
75 {
76     // Defines the type of the box
77     typedef          gsAabb<d,Z> kdBox;
78     typedef typename kdBox::point point;
79 
80     /// axis in which the children of this node split the domain
81     /// special value -1 denotes a leaf node
82     int axis;
83 
84     /// Split coordinate (meaningfull only for split nodes)
85     Z pos;
86 
87     /// level in which the box in the node is completely contained
88     /// special value -1 denotes unknown level (in case of a split node)
89     int level ;
90 
91     /// The box held in this leaf node (if leaf)
92     /// box->first is the lower left corner of the box
93     /// box->second is the upper right corner of the box
94     kdBox * box;
95 
96     /// Pointer to the parent node
97     kdnode * parent;
98 
99     /// Pointer to the left child of this split node (if it is one)
100     kdnode * left ;
101 
102     /// Pointer to the right child of this split node (if it is one)
103     kdnode * right;
104 
105     /// Constructor (empty node)
kdnodekdnode106     kdnode() : axis(-2) ,level(0), box(0),
107                parent(0), left(0), right(0)
108     { }
109 
110     /// Constructor (root node)
kdnodekdnode111     kdnode(point const & upp) : axis(-1) , level(0),
112                                 parent(0), left(0) , right(0)
113     {
114         // Initial box, upp is expected to be indexed in finest level
115         box = new kdBox( point::Zero(), upp);
116     }
117 
118     /// Constructor (leaf node)
kdnodekdnode119     kdnode(kdBox const & bb)
120         : axis(-1) , level(0),
121           parent(0), left(0) , right(0)
122     {
123         // ..
124     }
125 
126     /// Recursively copies the whole subtree under \a o, and sets it's
127     /// parent to \a parentNode
128     kdnode(const kdnode & o, kdnode * parentNode = NULL) :
129         axis(o.axis), level(o.level)
130     {
131         parent = parentNode;
132         if ( axis == -1 )
133         {
134             GISMO_ASSERT( (o.left == 0) && (o.right == 0),
135                           "Problem: leaf with children." );
136             box  = new kdBox(*o.box);
137             left = right = NULL;
138         }
139         else
140         {
141             GISMO_ASSERT( o.box == 0,
142                           "Problem: split node with box." );
143             pos   = o.pos;
144             left  = new kdnode(*o.left , this);
145             right = new kdnode(*o.right, this);
146             box   = NULL;
147         }
148     }
149 
150     /// Recursively deletes the whole subtree under this node
~kdnodekdnode151     ~kdnode()
152     {
153         // to do: non-reccursive
154 
155         if ( isLeaf() )
156         {
157             // No throw in destructor
158             //GISMO_ASSERT( (left == 0) && (right == 0),
159             //              "Problem: leaf with children." );
160                 delete box;
161         }
162         else
163         {
164             // No throw in destructor
165             //GISMO_ASSERT( box == 0,
166             //              "Problem: split node with box." );
167             delete left;
168             delete right;
169         }
170     }
171 
172     // Box Accessors
lowCornerkdnode173     const point & lowCorner() const
174     {
175         GISMO_ASSERT(box, "Asked for lowCorner at node without box data.");
176         return box->first ;
177     }
178 
uppCornerkdnode179     const point & uppCorner() const
180     {
181         GISMO_ASSERT(box, "Asked for uppCorner at node without box data.");
182         return box->second;
183     }
184 
isLeafkdnode185     bool isLeaf() const { return axis == -1; }
186 
isRootkdnode187     bool isRoot() const { return parent == NULL; }
188 
isTerminalkdnode189     bool isTerminal() const
190     { return (axis!=-1) && (left->axis==-1) && (right->axis==-1); }
191 
isLeftChildkdnode192     bool isLeftChild()  const { return parent!=NULL && this==parent->left; }
193 
isRightChildkdnode194     bool isRightChild() const { return parent!=NULL && this==parent->right; }
195 
siblingkdnode196     kdnode * sibling() const
197     {
198         GISMO_ASSERT( parent != 0, "Root does not have a sibling.");
199         return (parent->left == this ? parent->right : parent->left );
200     }
201 
multiplyByTwokdnode202     void multiplyByTwo()
203     {
204         if ( isLeaf() )
205         {
206             box->first .array() *= 2;
207             box->second.array() *= 2;
208         }
209         else
210         {
211             pos *= 2;
212         }
213     }
214 
215     // Splits the node (ie. two children are added)
splitkdnode216     inline void split()
217     {
218         GISMO_ASSERT( (left == 0) && (right == 0),
219                       "Can only split leaf nodes.");
220         GISMO_ASSERT( axis > -1, "Split axis not prescribed.");
221 
222         // Make new left and right children
223         left          = new kdnode;
224         right         = new kdnode;
225         // Set axis to -1 (since they are leaves)
226         left ->axis   =
227         right->axis   = -1;
228         // Set parent to this node
229         left ->parent =
230         right->parent = this;
231         // Set level
232         left ->level  =
233         right->level  = level;
234         // Set box
235         left ->box    = box;
236         right->box    = new kdBox(*box);
237         // Detach box from parent (is now at left child)
238         box = NULL;
239         // Resize properly the box coordinates
240         left ->box->second[axis] =
241         right->box->first [axis] = pos;
242     }
243 
244     // Merges terminal node (ie. two children are joined)
mergekdnode245     inline void merge()
246     {
247         GISMO_ASSERT( (left->isLeaf()) && (right->isLeaf()),
248                       "Can only merge terminal nodes.");
249 
250         // Recover box
251         box = left->box;
252         left->box = NULL;
253         box->second[axis] = right->box->second[axis];
254         axis  = - 1;
255         level = left->level;
256 
257         // Delete children
258         delete  left;
259         left  = NULL;
260         delete right;
261         right = NULL;
262     }
263 
264 
265     // Splits the node (ie. two children are added)
splitkdnode266     void split(int splitAxis, Z splitPos)
267     {
268         GISMO_ASSERT( box->second[splitAxis] != splitPos, "Degenerate split");
269         GISMO_ASSERT( box->first [splitAxis] != splitPos, "Degenerate split");
270         axis = splitAxis;
271         pos  = splitPos;
272         split();
273     }
274 
275     /// Splits the node in the middle (ie. two children are added)
276     // to do: remove
nextMidSplitkdnode277     void nextMidSplit()
278     {
279         axis = ( parent == 0 ? 0 : (parent->axis+1)%d );
280         pos  = box->first [axis] +
281             (box->second[axis] - box->first[axis])/2 ;
282         split(); // Can be degenerate
283     }
284 
285     /// Splits the node in the middle (ie. two children are added)
286     /// If non-degenerate split is impossible, then this is a no-op
anyMidSplitkdnode287     void anyMidSplit(int index_level)
288     {
289         const unsigned h = 1 << (index_level - level) ;
290         const unsigned mask = ~(h - 1);
291         for ( unsigned i = 0; i < d; ++i )
292         {
293             const unsigned c =
294                 (box->first [i] + (box->second[i] - box->first[i])/2) & mask ;
295             if ( c != box->first [i] ) // avoid degenerate split
296             {
297                 split(i, c);
298                 return;
299             }
300         }
301     }
302 
303 
304     /// Splits the node adaptively (ie. two children are added)
305     /// according to \a insBox.  If non-degenerate split is impossible,
306     /// then this is a no-op.
307     /// Splitting is done on a coordinate of the current \a level (aligned)
308     /// returns the child that intersects \a insBox or NULL (if no split)
adaptiveAlignedSplitkdnode309     kdnode * adaptiveAlignedSplit(kdBox const & insBox, int index_level)
310     {
311         const unsigned h = 1 << (index_level - level) ;
312         //const unsigned mask = ~(h - 1);
313 
314         for ( short_t i = 0; i < d; ++i )
315         {
316             const index_t c1 = insBox. first[i] - insBox. first[i] % h;//floor
317             const index_t cc = insBox.second[i] % h;
318             const index_t c2 = insBox.second[i] + (cc ? h-cc : 0 ) ;// ceil
319 
320             //const unsigned c1 = (insBox. first[i] & mask)    ;
321             //const unsigned c2 = (insBox.second[i] & mask) + ..;
322 
323             if ( c1 > box->first[i] )
324             {
325                 // right child intersects insBox
326                 split(i, c1 );
327                 return right;
328             }
329             else if ( c2 < box->second[i]  )
330             {
331                 // left child intersects insBox
332                 split(i, c2 );
333                 return left;
334             }
335         }
336         return NULL;
337     }
338 
339     /// Splits the node adaptively (ie. two children are added)
340     /// according to \a insBox.  If non-degenerate split is impossible,
341     /// then this is a no-op
342     // to do: remove
adaptiveSplitkdnode343     kdnode * adaptiveSplit(kdBox const & insBox)
344     {
345         // assumption: insBox intersects box
346         for ( unsigned i = 0; i < d; ++i )
347         {
348             // to do: strategy: try to split as close to the middle as
349             // possible
350             if ( insBox.first[i] > box->first[i] )
351             {
352                 axis = i;
353                 pos  = insBox.first[i];
354                 split();
355                 return right;
356             }
357             else if ( insBox.second[i] < box->second[i] )
358             {
359                 axis = i;
360                 pos  = insBox.second[i];
361                 split();
362                 return left ;
363             }
364         }
365         // insBox is equal to this->box or they do not overlap
366         return NULL;
367     }
368 
369     friend std::ostream & operator<<(std::ostream & os, const kdnode & n)
370     {
371         if ( n.isLeaf() )
372         {
373             os << "Leaf node ("<< n.box->first.transpose() <<"), ("
374                << n.box->second.transpose() <<"). level="<<n.level<<" \n";
375         }
376         else
377         {
378             os << "Split node, axis= "<< n.axis <<", pos="<< n.pos <<"\n";
379         }
380         //os<<"\n";
381 
382         return os;
383     }
384 
385 };
386 
387 
388 }// namespace gismo
389