G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsKdNode.h
Go to the documentation of this file.
1 
14 # pragma once
15 
16 #include <gsHSplines/gsAABB.h>
17 
18 namespace gismo {
19 
33 template<short_t d, class Z = index_t>
34 struct gsKdNode
35 {
36  // Defines the type of the box
37  typedef gsAABB<d, Z> kdBox;
38  typedef typename kdBox::point point;
39 
42  int axis;
43 
45  Z pos;
46 
49  int level ;
50 
55 
58 
61 
64 
66  gsKdNode() : axis(-2) ,level(0), box(0),
67  parent(0), left(0), right(0)
68  { }
69 
71  gsKdNode(point const & upp) : axis(-1) , level(0),
72  parent(0), left(0) , right(0)
73  {
74  // Initial box, upp is expected to be indexed in finest level
75  box = new kdBox( point::Zero(), upp);
76  }
77 
79  gsKdNode(point const & low, point const & upp) : axis(-1) , level(0),
80  parent(0), left(0) , right(0)
81  {
82  // Initial box, upp is expected to be indexed in finest level
83  box = new kdBox( low, upp);
84  }
85 
87  gsKdNode(kdBox const & bb) : axis(-1) , level(0),
88  parent(0), left(0) , right(0)
89  {
90  // ..
91  }
92 
95  gsKdNode(const gsKdNode & o, gsKdNode * parentNode = NULL) : axis(o.axis), level(o.level)
96  {
97  parent = parentNode;
98  if ( axis == -1 )
99  {
100  GISMO_ASSERT( (o.left == 0) && (o.right == 0),
101  "Problem: leaf with children." );
102  box = new kdBox(*o.box);
103  left = right = NULL;
104  }
105  else
106  {
107  GISMO_ASSERT( o.box == 0,
108  "Problem: split node with box." );
109  pos = o.pos;
110  left = new gsKdNode(*o.left , this);
111  right = new gsKdNode(*o.right, this);
112  box = NULL;
113  }
114  }
115 
118  {
119  // TODO: non-recursive
120 
121  if ( isLeaf() )
122  {
123  delete box;
124  }
125  else
126  {
127  delete left;
128  delete right;
129  }
130  }
131 
132  // Box Accessors
133  const point & lowCorner() const
134  {
135  GISMO_ASSERT(box, "Asked for lowCorner at node without box data.");
136  return box->first ;
137  }
138 
139  const point & uppCorner() const
140  {
141  GISMO_ASSERT(box, "Asked for uppCorner at node without box data.");
142  return box->second;
143  }
144 
145  bool isLeaf() const { return axis == -1; }
146 
147  bool isRoot() const { return parent == NULL; }
148 
149  bool isTerminal() const
150  { return (axis!=-1) && (left->axis==-1) && (right->axis==-1); }
151 
152  bool isLeftChild() const { return parent!=NULL && this==parent->left; }
153 
154  bool isRightChild() const { return parent!=NULL && this==parent->right; }
155 
156  bool isDegenerate() const
157  { return (box->first.array() >= box->second.array()).any(); }
158 
159  gsKdNode * sibling() const
160  {
161  GISMO_ASSERT( parent != 0, "Root does not have a sibling.");
162  return (parent->left == this ? parent->right : parent->left );
163  }
164 
165  void multiplyByTwo()
166  {
167  if ( isLeaf() )
168  {
169  box->first .array() *= 2;
170  box->second.array() *= 2;
171  }
172  else
173  {
174  pos *= 2;
175  }
176  }
177 
178  void divideByTwo()
179  {
180  if ( isLeaf() )
181  {
182  box->first .array() /= 2;
183  box->second.array() /= 2;
184  }
185  else
186  {
187  pos /= 2;
188  }
189  }
190 
192  inline void split()
193  {
194  GISMO_ASSERT( (left == 0) && (right == 0),
195  "Can only split leaf nodes.");
196  GISMO_ASSERT( axis > -1, "Split axis not prescribed.");
197 
198  // Make new left and right children
199  left = new gsKdNode;
200  right = new gsKdNode;
201  // Set axis to -1 (since they are leaves)
202  left ->axis =
203  right->axis = -1;
204  // Set parent to this node
205  left ->parent =
206  right->parent = this;
207  // Set level
208  left ->level =
209  right->level = level;
210  // Set box
211  left ->box = box;
212  right->box = new kdBox(*box);
213  // Detach box from parent (is now at left child)
214  box = NULL;
215  // Resize properly the box coordinates
216  left ->box->second[axis] =
217  right->box->first [axis] = pos;
218  }
219 
221  inline void merge()
222  {
223  GISMO_ASSERT( (left->isLeaf()) && (right->isLeaf()),
224  "Can only merge terminal nodes.");
225 
226  // Recover box
227  box = left->box;
228  left->box = NULL;
229  box->second[axis] = right->box->second[axis];
230  axis = - 1;
231  level = left->level;
232 
233  // Delete children
234  delete left;
235  left = NULL;
236  delete right;
237  right = NULL;
238  }
239 
240 
242  void split(int splitAxis, Z splitPos)
243  {
244  GISMO_ASSERT( box->second[splitAxis] != splitPos, "Degenerate split " << box->second[splitAxis] <<" != "<<splitPos);
245  GISMO_ASSERT( box->first [splitAxis] != splitPos, "Degenerate split " << box->first[splitAxis] <<" != "<<splitPos);
246  axis = splitAxis;
247  pos = splitPos;
248  split();
249  }
250 
252  // TODO: remove
254  {
255  axis = ( parent == 0 ? 0 : (parent->axis+1)%d );
256  pos = box->first [axis] +
257  (box->second[axis] - box->first[axis])/2 ;
258  split(); // Can be degenerate
259  }
260 
263  void anyMidSplit(int index_level)
264  {
265  const unsigned h = 1 << (index_level - level) ;
266  const unsigned mask = ~(h - 1);
267  for ( unsigned i = 0; i < d; ++i )
268  {
269  const unsigned c =
270  (box->first [i] + (box->second[i] - box->first[i])/2) & mask ;
271  if ( c != box->first [i] ) // avoid degenerate split
272  {
273  split(i, c);
274  return;
275  }
276  }
277  }
278 
279 
285  gsKdNode * adaptiveAlignedSplit(kdBox const & insBox, int index_level)
286  {
287  const unsigned h = 1 << (index_level - level) ;
288 
289  for (short_t i = 0; i < d; ++i)
290  {
291  const Z c1 = insBox. first[i] - insBox. first[i] % h; //floor
292  const Z cc = insBox.second[i] % h;
293  const Z c2 = insBox.second[i] + (cc ? h-cc : 0 ); // ceil
294 
295  if ( c1 > box->first[i] )
296  {
297  // right child intersects insBox
298  split(i, c1 );
299  return right;
300  }
301  else if ( c2 < box->second[i] )
302  {
303  // left child intersects insBox
304  split(i, c2 );
305  return left;
306  }
307  }
308  return NULL;
309  }
310 
314  // TODO: remove
315  gsKdNode * adaptiveSplit(kdBox const & insBox)
316  {
317  // assumption: insBox intersects box
318  for ( unsigned i = 0; i < d; ++i )
319  {
320  // TODO: strategy: Try to split as close to the middle as possible.
321  if ( insBox.first[i] > box->first[i] )
322  {
323  axis = i;
324  pos = insBox.first[i];
325  split();
326  return right;
327  }
328  else if ( insBox.second[i] < box->second[i] )
329  {
330  axis = i;
331  pos = insBox.second[i];
332  split();
333  return left ;
334  }
335  }
336  // insBox is equal to this->box or they do not overlap
337  return NULL;
338  }
339 
340  friend std::ostream & operator<<(std::ostream & os, const gsKdNode & n)
341  {
342  if ( n.isLeaf() )
343  {
344  os << "Leaf node ("<< n.box->first.transpose() <<"), ("
345  << n.box->second.transpose() <<"). level="<<n.level<<" \n";
346  }
347  else
348  {
349  os << "Split node, axis= "<< n.axis <<", pos="<< n.pos <<"\n";
350  }
351 
352  return os;
353  }
354 
355 };
356 
357 
358 }// namespace gismo
~gsKdNode()
Recursively deletes the whole subtree under this node.
Definition: gsKdNode.h:117
void split(int splitAxis, Z splitPos)
Splits the node (i.e., two children are added)
Definition: gsKdNode.h:242
#define short_t
Definition: gsConfig.h:35
gsKdNode(kdBox const &bb)
Constructor (leaf node)
Definition: gsKdNode.h:87
gsKdNode * adaptiveAlignedSplit(kdBox const &insBox, int index_level)
Definition: gsKdNode.h:285
gsKdNode * left
Pointer to the left child of this split node (if it is one)
Definition: gsKdNode.h:60
Struct representing a kd-tree node.
Definition: gsKdNode.h:34
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
void nextMidSplit()
Splits the node in the middle (ie. two children are added)
Definition: gsKdNode.h:253
gsKdNode()
Constructor (empty node)
Definition: gsKdNode.h:66
gsKdNode * adaptiveSplit(kdBox const &insBox)
Definition: gsKdNode.h:315
Z pos
Split coordinate (meaningfull only for split nodes)
Definition: gsKdNode.h:45
gsKdNode(point const &upp)
Constructor (root node)
Definition: gsKdNode.h:71
void merge()
Merges terminal node (i.e., two children are joined)
Definition: gsKdNode.h:221
int level
Definition: gsKdNode.h:49
void anyMidSplit(int index_level)
Definition: gsKdNode.h:263
gsKdNode(const gsKdNode &o, gsKdNode *parentNode=NULL)
Definition: gsKdNode.h:95
Struct of for an Axis-aligned bounding box.
Definition: gsAABB.h:30
kdBox * box
Definition: gsKdNode.h:54
void split()
Splits the node (i.e., two children are added)
Definition: gsKdNode.h:192
gsKdNode * parent
Pointer to the parent node.
Definition: gsKdNode.h:57
int axis
Definition: gsKdNode.h:42
Declarations of the class gsAABB, i.e., the axis-aligned bounding box.
gsKdNode(point const &low, point const &upp)
Constructor (root node)
Definition: gsKdNode.h:79
gsKdNode * right
Pointer to the right child of this split node (if it is one)
Definition: gsKdNode.h:63