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