G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsHDomain.hpp
Go to the documentation of this file.
1
16#include <gsHSplines/gsKdNode.h>
18#include <gsCore/gsBoundary.h>
19
20#include <queue>
21
22namespace
23{
24 // Query 1
25 struct query1_visitor
26 {
27 typedef bool return_type;
28
29 // initialize result as true
30 static return_type init() {return true;}
31
32 template<short_t d, class Z>
33 static void visitLeaf(gismo::gsKdNode<d, Z> * leafNode , int level, return_type & res)
34 {
35 if ( leafNode->level != level )
36 res = false;
37 }
38 };
39
40 // Query 2
41 struct query2_visitor
42 {
43 typedef bool return_type;
44
45 // initialize result as true
46 static return_type init() {return true;}
47
48 template<short_t d, class Z>
49 static void visitLeaf(gismo::gsKdNode<d, Z> * leafNode , int level, return_type & res)
50 {
51 if ( leafNode->level <= level )
52 res = false;
53 }
54 };
55
56 // Query 3
57 struct query3_visitor
58 {
59 typedef int return_type;
60
61 // initialize result as a max possible value, since we are looking
62 // for a minimum
63 static return_type init() {return 1000000;}
64
65 template<short_t d, class Z>
66 static void visitLeaf(gismo::gsKdNode<d, Z> * leafNode , int , return_type & res)
67 {
68 if ( leafNode->level < res )
69 res = leafNode->level;
70 }
71 };
72
73 // Query 4
74 struct query4_visitor
75 {
76 typedef int return_type;
77
78 // initialize result as a minimum possible value, since we are
79 // looking for a maximum
80 static return_type init() {return -1;}
81
82 template<short_t d, class Z>
83 static void visitLeaf(gismo::gsKdNode<d, Z> * leafNode , int , return_type & res)
84 {
85 if ( leafNode->level > res )
86 res = leafNode->level;
87 }
88 };
89
90} //namespace
91
92namespace gismo {
93
94
95template<short_t d, class Z>
97{
98 return new gsHDomain(*this);
99}
100
101
102template<short_t d, class Z>
103inline bool gsHDomain<d, Z>::haveOverlap(box const & box1, box const & box2)
104{
105 return !( (box1.second.array() <= box1.first .array()).any() ||
106 (box2.first .array() >= box1.second.array()).any() );
107}
108
109template<short_t d, class Z>
110inline bool gsHDomain<d, Z>::isContained(box const & box1, box const & box2)
111{
112 return !( (box1.first .array() < box2.first .array()).any() ||
113 (box1.second.array() > box2.second.array()).any() ) ;
114}
115
116template<short_t d, class Z> void
118{
119 // to do: non-recc.
120 if ( _node->isLeaf() )
121 {
122 // if the level in the *_node is smaller the value of lvl we
123 // modify it
124 _node->level = lvl;
125 }
126 else
127 {
128 // we call the function set level for all existing children of
129 // the node *_node
130 setLevel(_node->left , lvl);
131 setLevel(_node->right, lvl);
132 }
133}
134
135template<short_t d, class Z> inline bool
137{
138 return (someBox.first.array() >= someBox.second.array()).any() ;
139}
140
141//use "surface area heuristic" (SAH) ?
142template<short_t d, class Z> void
143gsHDomain<d, Z>::insertBox ( point const & k1, point const & k2,
144 node *_node, int lvl) // CONSTRAINT: lvl is "minimum level"
145{
146 GISMO_ENSURE( lvl <= static_cast<int>(m_indexLevel), "Max index level reached..");
147
148 // Make a box
149 box iBox(k1,k2);
150 if( isDegenerate(iBox) )
151 return;
152
153 // Represent box in the index level
154 // iBox.first .unaryExpr(toGlobalIndex(lvl, m_index_level) );
155 // iBox.second.unaryExpr(toGlobalIndex(lvl, m_index_level) );
156 local2globalIndex( iBox.first , static_cast<unsigned>(lvl), iBox.first );
157 local2globalIndex( iBox.second, static_cast<unsigned>(lvl), iBox.second);
158
159 // Ensure that the box is within the valid limits
160 if ( ( iBox.first.array() >= m_upperIndex.array() ).any() )
161 {
162 gsWarn<<" Invalid box coordinate "<< k1.transpose() <<" at level" <<lvl<<".\n";
163 return;
164 }
165
166 // Initialize stack
167 std::vector<node*> stack;
168 stack.reserve( 2 * (m_maxPath + d) );
169 stack.push_back(_node); //push(_node);
170
171 node * curNode;
172 while ( ! stack.empty() )
173 {
174 curNode = stack.back(); //top();
175 stack.pop_back(); //pop();
176
177 if ( curNode->isLeaf() ) // reached a leaf
178 {
179 // Since we reached a leaf, it should overlap with iBox
180
181 // If this leaf is already in level lvl, then we have nothing to do
182 if ( lvl <= curNode->level )
183 continue;
184
185 // Split the leaf (if possible)
186 //node * newLeaf = curNode->adaptiveSplit(iBox);
187 node * newLeaf = curNode->adaptiveAlignedSplit(iBox, m_indexLevel);
188
189 // If curNode is still a leaf, its domain is almost
190 // contained in iBox
191 if ( !newLeaf ) // curNode->isLeaf()
192 {
193 // Increase level and reccurse
194 if ( ++curNode->level != lvl)
195 stack.push_back(curNode);
196 }
197 else // treat new child
198 {
199 stack.push_back(newLeaf);
200 }
201 }
202 else // roll down the tree
203 {
204 if ( iBox.second[curNode->axis] <= curNode->pos)
205 // iBox overlaps only left child of this split-node
206 stack.push_back(curNode->left);
207 else if ( iBox.first[curNode->axis] >= curNode->pos)
208 // iBox overlaps only right child of this split-node
209 stack.push_back(curNode->right);
210 else
211 {
212 // iBox overlaps both children of this split-node
213 stack.push_back(curNode->left );
214 stack.push_back(curNode->right);
215 }
216 }
217 }
218
219 // Update maximum inserted level
220 if ( static_cast<unsigned>(lvl) > m_maxInsLevel)
221 m_maxInsLevel = lvl;
222}
223
224template<short_t d, class Z> void
225gsHDomain<d, Z>::clearBox ( point const & k1, point const & k2,
226 int lvl) // CONSTRAINT: lvl is "minimum level"
227{
228 GISMO_ENSURE( lvl <= static_cast<int>(m_indexLevel), "Max index level reached..");
229
230 // Make a box
231 box iBox(k1,k2);
232 if( isDegenerate(iBox) )
233 return;
234
235 // Represent box in the index level
236 // iBox.first .unaryExpr(toGlobalIndex(lvl, m_index_level) );
237 // iBox.second.unaryExpr(toGlobalIndex(lvl, m_index_level) );
238 local2globalIndex( iBox.first , static_cast<unsigned>(lvl), iBox.first );
239 local2globalIndex( iBox.second, static_cast<unsigned>(lvl), iBox.second);
240
241 // Ensure that the box is within the valid limits
242 if ( ( iBox.first.array() >= m_upperIndex.array() ).any() )
243 {
244 gsWarn<<" Invalid box coordinate "<< k1.transpose() <<" at level" <<lvl<<".\n";
245 return;
246 }
247
248 // Initialize stack
249 std::vector<node*> stack;
250 stack.reserve( 2 * (m_maxPath + d) );
251 stack.push_back(m_root); //push(m_root);
252
253 node * curNode;
254 while ( ! stack.empty() )
255 {
256 curNode = stack.back(); //top();
257 stack.pop_back(); //pop();
258
259 if ( curNode->isLeaf() ) // reached a leaf
260 {
261 // Since we reached a leaf, it should overlap with iBox
262
263 // If this leaf is already in level lvl, then we have nothing to do
264 if ( curNode->level <= lvl )
265 continue;
266
267 // Split the leaf (if possible)
268 node * newLeaf = curNode->adaptiveAlignedSplit(iBox, m_indexLevel);
269
270 // If curNode is still a leaf, its domain is almost
271 // contained in iBox
272 if ( !newLeaf ) // curNode->isLeaf()
273 {
274 // Decrease level and reccurse
275 if ( --curNode->level != lvl)
276 stack.push_back(curNode);
277 }
278 else // treat new child
279 {
280 stack.push_back(newLeaf);
281 }
282 }
283 else // roll down the tree
284 {
285 if ( iBox.second[curNode->axis] <= curNode->pos)
286 // iBox overlaps only left child of this split-node
287 stack.push_back(curNode->left);
288 else if ( iBox.first[curNode->axis] >= curNode->pos)
289 // iBox overlaps only right child of this split-node
290 stack.push_back(curNode->right);
291 else
292 {
293 // iBox overlaps both children of this split-node
294 stack.push_back(curNode->left );
295 stack.push_back(curNode->right);
296 }
297 }
298 }
299
300 computeMaxInsLevel(); // compute again globally
301}
302
303template<short_t d, class Z> void
305 point const & k2, int lvl)
306{
307 GISMO_ENSURE( m_maxInsLevel+1 <= m_indexLevel,
308 "Max index level might be reached..");
309
310 // Make a box
311 box iBox(k1,k2);
312 if( isDegenerate(iBox) )
313 return;
314
315 // Represent box in the index level
316 local2globalIndex( iBox.first , static_cast<unsigned>(lvl), iBox.first );
317 local2globalIndex( iBox.second, static_cast<unsigned>(lvl), iBox.second);
318
319 // Ensure that the box is within the valid limits
320 if ( ( iBox.first.array() >= m_upperIndex.array() ).any() )
321 {
322 //gsWarn<<" Invalid box coordinate "<< k1.transpose() <<" at level" <<lvl<<".\n";
323 return;
324 }
325
326 // Initialize stack
327 std::stack<node*, std::vector<node*> > stack;
328 stack.push(m_root);
329
330 node * curNode;
331 while ( ! stack.empty() )
332 {
333 curNode = stack.top();
334 stack.pop();
335
336 if ( curNode->isLeaf() ) // reached a leaf
337 {
338 // Since we reached a leaf, it should overlap with iBox.
339 // Split the leaf (if possible)
340 node * newLeaf = curNode->adaptiveAlignedSplit(iBox, m_indexLevel);
341
342 // If curNode is still a leaf, its domain is almost
343 // contained in iBox
344 if ( !newLeaf ) // implies curNode was a leaf
345 {
346 // Increase level
347 if ( ++curNode->level > static_cast<int>(m_maxInsLevel) )
348 m_maxInsLevel = curNode->level;
349 }
350 else // treat new child
351 {
352 stack.push(newLeaf);
353 }
354 }
355 else // walk down the tree
356 {
357 if ( iBox.second[curNode->axis] <= curNode->pos)
358 // iBox overlaps only left child of this split-node
359 stack.push(curNode->left);
360 else if ( iBox.first[curNode->axis] >= curNode->pos)
361 // iBox overlaps only right child of this split-node
362 stack.push(curNode->right);
363 else
364 {
365 // iBox overlaps both children of this split-node
366 stack.push(curNode->left );
367 stack.push(curNode->right);
368 }
369 }
370 }
371}
372
373template<short_t d, class Z>
375{
376 std::stack<node*, std::vector<node*> > tstack;
377 node * curNode;
378
379 // First step: gather all terminal nodes
380 std::stack<node*, std::vector<node*> > stack;
381 stack.push(m_root);
382 while ( ! stack.empty() )
383 {
384 curNode = stack.top();
385 stack.pop();
386
387 if ( curNode->isTerminal() )
388 {
389 // Remember this terminal node
390 tstack.push(curNode);
391 }
392 else if ( ! curNode->isLeaf() ) // this is a non-terminal split-node
393 {
394 stack.push(curNode->left );
395 stack.push(curNode->right);
396 }
397 }
398
399 // Second step: reccursively merge siblings that have the same level
400 while ( ! tstack.empty() )
401 {
402 curNode = tstack.top();
403 tstack.pop();
404
405 if (curNode->left->level == curNode->right->level)
406 {
407 // Merge left and right
408 curNode->merge();
409 if ( !curNode->isRoot() &&
410 curNode->parent->isTerminal() )
411 tstack.push(curNode->parent );
412 }
413 }
414
415 // Store the max path length
416 m_maxPath = minMaxPath().second;
417}
418
419template<short_t d, class Z>
420bool gsHDomain<d, Z>::query1(point const & lower, point const & upper,
421 int level, node *_node) const
422{
423 return boxSearch< query1_visitor >(upper,lower,level,_node);
424}
425
426template<short_t d, class Z>
427bool gsHDomain<d, Z>::query1(point const & lower, point const & upper,
428 int level) const
429{
430 return boxSearch< query1_visitor >(upper,lower,level,m_root);
431}
432
433template<short_t d, class Z>
434bool gsHDomain<d, Z>::query2(point const & lower, point const & upper,
435 int level, node *_node) const
436{
437 return boxSearch< query2_visitor >(lower,upper,level,_node);
438}
439
440template<short_t d, class Z>
441bool gsHDomain<d, Z>::query2 (point const & lower, point const & upper,
442 int level) const
443{
444 return boxSearch< query2_visitor >(lower,upper,level,m_root);
445}
446
447template<short_t d, class Z>
448int gsHDomain<d, Z>::query3(point const & lower, point const & upper,
449 int level, node *_node) const
450{
451 return boxSearch< query3_visitor >(lower,upper,level,_node);
452}
453
454template<short_t d, class Z>
455int gsHDomain<d, Z>::query3(point const & lower, point const & upper,
456 int level) const
457{
458 return boxSearch< query3_visitor >(lower,upper,level,m_root);
459}
460
461template<short_t d, class Z>
462int gsHDomain<d, Z>::query4(point const & lower, point const & upper,
463 int level, node *_node) const
464{
465 return boxSearch< query4_visitor >(lower,upper,level,_node);
466}
467
468template<short_t d, class Z>
469int gsHDomain<d, Z>::query4(point const & lower, point const & upper,
470 int level) const
471{
472 return boxSearch< query4_visitor >(lower,upper,level,m_root);
473}
474
475template<short_t d, class Z>
476std::pair<typename gsHDomain<d, Z>::point, typename gsHDomain<d, Z>::point>
477gsHDomain<d, Z>::queryLevelCell(point const & lower, point const & upper,
478 int level) const
479{
480 std::pair<point,point> tmp = boxSearch< get_cell_visitor >(lower,upper,level,m_root);
481 global2localIndex(tmp.first,level,tmp.first);
482 global2localIndex(tmp.second,level,tmp.second);
483 return tmp;
484}
485
486template<short_t d, class Z>
487std::pair<typename gsHDomain<d, Z>::point, typename gsHDomain<d, Z>::point>
489 point const & k3, point const & k4)
490{
491 // intersect boxes
492 std::pair<point,point> result;
493
494 for( short_t i = 0; i<d; ++i)
495 {
496 //find the lower left corner
497 result.first[i] = ( k1[i] >= k3[i] ? k1[i] : k3[i] );
498 //find the upper right corner
499 result.second[i] = ( k2[i] >= k4[i] ? k4[i] : k2[i] );
500 }
501 return result;
502}
503
504template<short_t d, class Z> void
505gsHDomain<d, Z>::bisectBox(box const & original, int k, Z coord,
506 box & leftBox, box & rightBox )
507{
508 GISMO_ASSERT( ! isDegenerate(original) , "Invalid box .");
509 GISMO_ASSERT( (k>=0) && (k< static_cast<int>(d)) , "Invalid axis "<< k <<".");
510 leftBox = rightBox = original;
511 leftBox.second[k] = rightBox.first[k] = coord;
512}
513
514
515template<short_t d, class Z>
516template<typename visitor>
517typename visitor::return_type
519 int level, node *_node ) const
520{
521 // Make a box
522 box qBox(k1,k2);
523 local2globalIndex( qBox.first , static_cast<unsigned>(level), qBox.first );
524 local2globalIndex( qBox.second, static_cast<unsigned>(level), qBox.second);
525
526 GISMO_ASSERT( !isDegenerate(qBox),
527 "boxSearch: Wrong order of points defining the box (or empty box): "
528 << qBox.first.transpose() <<", "<< qBox.second.transpose() <<".\n" );
529
530 typename visitor::return_type res = visitor::init();
531
532 std::vector<node*> stack;
533 stack.reserve( 2 * m_maxPath );
534 stack.push_back(_node); //push(_node);
535
536 node * curNode;
537 while ( ! stack.empty() )
538 {
539 curNode = stack.back(); //top();
540 stack.pop_back(); //pop();
541
542 if ( curNode->isLeaf() )
543 {
544 // Visit the leaf
545 GISMO_ASSERT( !isDegenerate(*curNode->box), "Encountered an empty leaf");
546 visitor::visitLeaf(curNode, level, res );
547 }
548 else // this is a split-node
549 {
550 if ( qBox.second[curNode->axis] <= curNode->pos)
551 // qBox overlaps only left child of this split-node
552 stack.push_back(curNode->left); //push(curNode->left);
553 else if ( qBox.first[curNode->axis] >= curNode->pos)
554 // qBox overlaps only right child of this split-node
555 stack.push_back(curNode->right); //push(curNode->right);
556 else
557 {
558 // qBox overlaps both children of this split-node
559 stack.push_back(curNode->left ); //push(curNode->left );
560 stack.push_back(curNode->right); //push(curNode->right);
561 }
562 }
563 }
564
565 return res;
566}
567
568
569
570template<short_t d, class Z>
571typename gsHDomain<d, Z>::node *
572gsHDomain<d, Z>::pointSearch(const point & p, int level, node *_node ) const
573{
574 point pp;
575 local2globalIndex(p, static_cast<unsigned>(level), pp);
576
577 GISMO_ASSERT( ( pp.array() <= m_upperIndex.array() ).all(),
578 "pointSearch: Wrong input: "<< p.transpose()<<", level "<<level<<".\n" );
579
580 std::vector<node*> stack;
581 stack.reserve( 2 * m_maxPath );
582 stack.push_back(_node);
583
584 node * curNode;
585 while ( ! stack.empty() )
586 {
587 curNode = stack.back(); //top();
588 stack.pop_back(); //pop();
589
590 if ( curNode->isLeaf() )
591 {
592 // Point found at current node
593 return curNode;
594 }
595 else // this is a split-node
596 {
597 if ( pp[curNode->axis] < curNode->pos)
598 stack.push_back(curNode->left);
599 else
600 stack.push_back(curNode->right);
601 }
602 }
603 GISMO_ERROR("pointSearch: Error ("<< p.transpose()<<").\n" );
604}
605
606
607template<short_t d, class Z>
608template<typename visitor>
609typename visitor::return_type
611{
612 typename visitor::return_type i = visitor::init();
613
614 node * curNode = m_root;
615
616 while(true)
617 {
618 visitor::visitNode(curNode, i);
619
620 if ( !curNode->isLeaf() )
621 { //property: tree has no singles
622 curNode = curNode->left;
623 }
624 else
625 {
626 while (curNode->parent != NULL &&
627 curNode != curNode->parent->left)
628 curNode = curNode->parent;
629
630 if ( curNode->isRoot() )
631 break;
632 else
633 curNode = curNode->parent->right;
634 }
635 }
636 return i;
637}
638
639template<short_t d, class Z>
640template<typename visitor>
641typename visitor::return_type
643{
644 typename visitor::return_type i = visitor::init();
645
646 node * curNode = m_root;
647
648 while(true)
649 {
650 if ( !curNode->isLeaf() )
651 { //property: tree has no singles (only childs)
652 curNode = curNode->left;
653 }
654 else
655 {
656 // Visit the leaf
657 visitor::visitLeaf(curNode, i);
658
659 while (curNode->parent != NULL &&
660 curNode != curNode->parent->left)
661 curNode = curNode->parent;
662
663 if ( curNode->isRoot() )
664 break;
665 else
666 curNode = curNode->parent->right;
667 }
668 }
669 return i;
670}
671
672
673template<short_t d, class Z>
674std::pair<int,int>
676{
677 node * curNode = m_root;
678 int min = 1000000000, max = -1, cur = 0;
679
680 while(true)
681 {
682 if ( !curNode->isLeaf() )
683 { //property: tree has no singles
684 curNode = curNode->left;
685 cur++;
686 }
687 else
688 {
689 // Update min-max
690 min = math::min(min,cur);
691 max = math::max(max,cur);
692
693 while (curNode->parent != NULL &&
694 curNode != curNode->parent->left)
695 {
696 curNode = curNode->parent;
697 cur--;
698 }
699
700 if ( curNode->isRoot() )
701 break;
702 else
703 curNode = curNode->parent->right;
704 }
705 }
706 return std::make_pair(min,max);
707}
708
709template<short_t d, class Z>
711{
712 std::vector<std::vector<Z> > boxes;
713
714 // get all boxes in vector-format
715 getBoxes_vec(boxes);
716
717 // connect boxes which have the same levels and are
718 // are aligned such that their union again is an
719 // axis-aligned box.
720 connect_Boxes(boxes);
721
722 // write the result into b1, b2, and level
723 b1.resize(boxes.size(),d);
724 b2.resize(boxes.size(),d);
725 level.resize(boxes.size());
726 for(size_t i = 0; i < boxes.size(); i++)
727 {
728 for(short_t j = 0; j < d; j++)
729 {
730 b1(i,j) = boxes[i][j];
731 b2(i,j) = boxes[i][j+d];
732 }
733 level[i] = boxes[i][2*d];
734 }
735}
736
737
738template<short_t d, class Z>
740{
741
742 getBoxes( b1, b2, level);
743 std::vector<Z> onSide;
744
745 unsigned remainder = (s-1) % 2;
746 // remainder will be
747 // 0 for sides 1 (west), 3 (south/down), or 5 (front)
748 // 1 for sides 2 (east), 4 (north/up), or 6 (back)
749 unsigned quotient = ( (s-1) - remainder ) / 2;
750 // quotient will be
751 // 0 for east/west
752 // 1 for south/north or down/up
753 // 2 for front/back
754
755 if( remainder == 0 ) // sides 1 (west), 3 (south/down), or 5 (front)
756 {
757 // if a box touches
758 for(index_t i = 0; i < b1.rows(); i++)
759 if( b1(i, quotient ) == 0 )
760 onSide.push_back(i);
761 }
762 else // remainder == 1, sides east, north/up, or back
763 {
764 for(index_t i = 0; i < b1.rows(); i++)
765 {
766 // index of upper corner
767 Z B2( b2(i, quotient ) );
768 // transform to index-level
769 B2 = B2 << (m_indexLevel - m_maxInsLevel);
770
771 // check if this index is on the boundary
772 if( B2 == m_upperIndex[ quotient ] )
773 onSide.push_back( i );
774 }
775 }
776
777 // select only the boxes on side s:
778 for(size_t i=0; i < onSide.size(); i++)
779 {
780 b1.row(i) = b1.row( onSide[i] );
781 b2.row(i) = b2.row( onSide[i] );
782 level[i] = level( onSide[i] );
783 }
784 b1.conservativeResize( onSide.size(), b1.cols() );
785 b2.conservativeResize( onSide.size(), b2.cols() );
786 level.conservativeResize( onSide.size() );
787}
788
789template<short_t d, class Z>
791 gsMatrix<Z>& b2,
792 gsVector<index_t>& level) const
793{
794 std::vector<std::vector<Z> > boxes;
795 getBoxes_vec(boxes);
796 GISMO_ASSERT(d==2 || d==3, "Wrong dimension, should be 2 or 3.");
797 //is this test really necessary? florian b.
798 for(size_t i = 0; i < boxes.size(); i++)
799 {
800 if ((boxes[i][0]==boxes[i][d+0]) || (boxes[i][1]==boxes[i][1+d]))
801 {
802 boxes.erase(boxes.begin()+i);
803 i--;
804 }
805 else if((d == 3) && (boxes[i][2]==boxes[i][d+2]))
806 {
807 boxes.erase(boxes.begin()+i);
808 i--;
809 }
810 }
811 gsVector<Z, d> lowerCorner;
812 gsVector<Z, d> upperCorner;
813 connect_Boxes(boxes);
814 b1.resize(boxes.size(), d);
815 b2.resize(boxes.size(), d);
816 level.resize(boxes.size());
817 for(size_t i = 0; i < boxes.size(); i++)
818 {
819 for(short_t j = 0; j < d; j++)
820 {
821 lowerCorner[j] = boxes[i][j];
822 upperCorner[j] = boxes[i][j+d];
823 }
824 level[i] = boxes[i][2*d];
825 computeLevelIndex(lowerCorner, level[i], lowerCorner);
826 computeLevelIndex(upperCorner, level[i], upperCorner);
827 b1.row(i) = lowerCorner;
828 b2.row(i) = upperCorner;
829 }
830}
831
832// Old version that only works for 2D
833// Should be replaced by the "new" connect_Boxes.
834// Keeping the code for the moment, in order not to loose
835// the old code before the new one is properly tested.
836template<short_t d, class Z> void
837gsHDomain<d, Z>::connect_Boxes2d(std::vector<std::vector<Z>> &boxes) const
838{
839 GISMO_ASSERT( d == 2, "This one only works for 2D");
840 bool change = true;
841 while(change)
842 {
843 change = false;
844 size_t s = boxes.size();
845 for(size_t i = 0; i < s; i++)
846 {
847 for(size_t j = i+1; j < s; j++)
848 {
849 // if the levels are the same:
850 if(boxes[i][4]==boxes[j][4])
851 {
852 if( (boxes[i][0]==boxes[j][0]) && (boxes[i][2]==boxes[j][2]))
853 {
854 if(boxes[i][1]==boxes[j][3])
855 {
856 boxes[i][1] = boxes[j][1];
857 boxes.erase(boxes.begin()+j);
858 s--;
859 j--;
860 change = true;
861 }
862 if(boxes[i][3]==boxes[j][1])
863 {
864 boxes[i][3] = boxes[j][3];
865 boxes.erase(boxes.begin()+j);
866 s--;
867 j--;
868 change = true;
869 }
870 }
871 if( (boxes[i][1]==boxes[j][1]) && (boxes[i][3]==boxes[j][3])
872)
873 {
874 if(boxes[i][0]==boxes[j][2])
875 {
876 boxes[i][0] = boxes[j][0];
877 boxes.erase(boxes.begin()+j);
878 s--;
879 j--;
880 change = true;
881 }
882 if(boxes[i][2]==boxes[j][0])
883 {
884 boxes[i][2] = boxes[j][2];
885 boxes.erase(boxes.begin()+j);
886 s--;
887 j--;
888 change = true;
889 }
890 }
891 }
892 }
893 }
894 }
895}
896
897template<short_t d, class Z> void
898gsHDomain<d, Z>::connect_Boxes(std::vector<std::vector<Z>> &boxes) const
899{
900 bool change = true;
901 while(change)
902 {
903 change = false;
904 size_t s = boxes.size();
905 for(size_t i = 0; i < s; i++)
906 {
907 for(size_t j = i+1; j < s; j++)
908 {
909 if(boxes[i][2*d]==boxes[j][2*d]) // if( the levels are the same )
910 {
911 unsigned nmCoordLo = 0;
912 unsigned nmCoordUp = 0;
913 unsigned nmCountUp = 0;
914 unsigned nmCountLo = 0; //...the "nm" is for non-matching
915
916 // Compare the lower and upper corners of the boxes
917 // coordinate-wise, and check if there are differences.
918 // If there are differences, count and store the coordinate
919 for(short_t k=0; k < d; k++)
920 {
921 if( boxes[i][k] != boxes[j][k] )
922 {
923 nmCountLo++;
924 nmCoordLo = k;
925 }
926
927 if( boxes[i][d+k] != boxes[j][d+k] )
928 {
929 nmCountUp++;
930 nmCoordUp = k;
931 }
932 }
933
934 // The boxes can only be merged if
935 // the lower and upper corners are the same,
936 // except in one coordinate direction.
937 if( nmCountLo == 1
938 && nmCountUp == 1
939 && nmCoordLo == nmCoordUp )
940 {
941
942 if( boxes[i][nmCoordLo] == boxes[j][d+nmCoordUp] )
943 {
944 // box i is "on top" of box j.
945 // It inherits the lower corner from box j:
946 boxes[i][nmCoordLo] = boxes[j][nmCoordLo];
947 boxes.erase( boxes.begin()+j );
948 s--;
949 j--;
950 change = true;
951 }
952
953 if( boxes[i][d+nmCoordUp] == boxes[i][nmCoordLo] )
954 {
955 // box i is "below" of box j.
956 // It inherits the upper corner from box j:
957 boxes[i][d+nmCoordUp] = boxes[j][d+nmCoordUp];
958 boxes.erase( boxes.begin()+j );
959 s--;
960 j--;
961 change = true;
962 }
963 }
964 } // if boxes same level
965 } // for j
966 } // for i
967 }
968}
969
970
971template<short_t d, class Z>
972void gsHDomain<d, Z>::connect_Boxes_2(std::vector<std::vector<Z> > &boxes) const
973{
974 bool change = true;
975 while(change)
976 {
977 change = false;
978 size_t s = boxes.size();
979 for(size_t i = 0; i < s;i++)
980 {
981 for(size_t j = i+1; j < s; j++)
982 {
983 if(boxes[i][4]==boxes[j][4])
984 {
985 if( (boxes[i][0]==boxes[j][0]) && (boxes[i][2]==boxes[j][2]))
986 {
987 if(boxes[i][1]==boxes[j][3])
988 {
989 boxes[i][1] = boxes[j][1];
990 boxes.erase(boxes.begin()+j);
991 s--;
992 j--;
993 change = true;
994 }
995 if(boxes[i][3]==boxes[j][1])
996 {
997 boxes[i][3] = boxes[j][3];
998 boxes.erase(boxes.begin()+j);
999 s--;
1000 j--;
1001 change = true;
1002 }
1003 }
1004 }
1005 }
1006 }
1007 }
1008 change = true;
1009 while(change)
1010 {
1011 change = false;
1012 size_t s = boxes.size();
1013 for(size_t i = 0; i < s;i++)
1014 {
1015 for(size_t j = i+1; j < s; j++)
1016 {
1017 if( (boxes[i][1]==boxes[j][1]) && (boxes[i][3]==boxes[j][3]))
1018 {
1019 if(boxes[i][0]==boxes[j][2])
1020 {
1021 boxes[i][0] = boxes[j][0];
1022 boxes.erase(boxes.begin()+j);
1023 s--;
1024 j--;
1025 change = true;
1026 }
1027 if(boxes[i][2]==boxes[j][0])
1028 {
1029 boxes[i][2] = boxes[j][2];
1030 boxes.erase(boxes.begin()+j);
1031 s--;
1032 j--;
1033 change = true;
1034 }
1035 }
1036 }
1037 }
1038 }
1039}
1040
1041
1042
1043template<short_t d, class Z> void
1044gsHDomain<d, Z>::getBoxes_vec(std::vector<std::vector<Z> >& boxes) const
1045{
1046 boxes.clear();
1047
1048 std::stack<node*, std::vector<node*> > stack;
1049 //stack.reserve( 2 * m_maxPath );
1050 stack.push(m_root);
1051 node * curNode;
1052 while ( ! stack.empty() )
1053 {
1054 curNode = stack.top();
1055 stack.pop();
1056
1057 if ( curNode->isLeaf() )
1058 {
1059 // We need to convert the indices to those of m_maxInsLevel
1060 // to be able to reconstruct the earlier results.
1061 const point & lowerGlob = curNode->lowCorner();
1062 const point & upperGlob = curNode->uppCorner();
1063 unsigned int level = this->m_maxInsLevel;
1064 point lower;
1065 point upper;
1066
1067 global2localIndex(lowerGlob,level,lower);
1068 global2localIndex(upperGlob,level,upper);
1069
1070 boxes.push_back(std::vector<Z>());
1071 for(short_t i = 0; i < d; i++)
1072 {
1073 boxes.back().push_back(lower[i]);
1074 }
1075 for(short_t i = 0; i < d; i++)
1076 {
1077 boxes.back().push_back(upper[i]);
1078 }
1079 boxes.back().push_back(curNode->level);
1080 }
1081 else
1082 {
1083 stack.push(curNode->left) ;
1084 stack.push(curNode->right);
1085 }
1086 }
1087}
1088
1089/*
1090 * functions for returning the boudaries of domains
1091 */
1092template<short_t d, class Z>
1093std::vector<std::vector<std::vector< std::vector<Z> > > >
1095{
1096/*
1097 1: Get boxes from the quadtree.
1098 2: Return their borderlines.
1099
1100 Return structure:
1101 < levels < polylines_in_one_level < one_polyline < one_segment (x1, y1, x2, y2) > > > > result
1102 note that <x1, y1, x2, y2 > are so that (x1, y1) <=LEX (x2, y2)
1103*/
1104 std::vector<std::vector<Z> > boxes;
1105 getBoxes_vec(boxes);// Returns all leaves.
1106
1107 // Get rid of boxes that are not of full dimension.
1108 for(auto it = boxes.begin(); it != boxes.end(); ++it)
1109 {
1110 if( ( (*it)[0] == (*it)[2] ) || ( (*it)[0] == (*it)[2] ) )
1111 it = boxes.erase(it);
1112 }
1113
1114 std::vector<std::vector<gsVSegment<Z> > > seg;
1115 seg.resize(m_maxInsLevel+1);
1116
1117 // For each level prepare the vertical lines separately.
1118 for(size_t i = 0; i < boxes.size() ; i ++)
1119 {
1120 seg[boxes[i][4]].push_back(gsVSegment<Z>(boxes[i][0], boxes[i][1], boxes[i][3], false));
1121 seg[boxes[i][4]].push_back(gsVSegment<Z>(boxes[i][2], boxes[i][1], boxes[i][3], false));
1122 }
1123
1124 // Process vertical lines from each level separately.
1125 std::vector< std::vector<std::vector< std::vector<Z> > > > result;
1126 for(unsigned int i = 0; i < m_maxInsLevel+1; i++)
1127 {
1128 result.push_back( getPolylinesSingleLevel( seg[i] ));
1129 }
1130
1131 return result;
1132}
1133
1134
1135template<short_t d, class Z>
1136std::vector<std::vector< std::vector<Z> > > gsHDomain<d, Z>::getPolylinesSingleLevel(std::vector<gsVSegment<Z> >& seg) const
1137{
1138 // For didactic purposes the interior of the function has been refined into two procedures
1139 // (overal length of the older version was intimidating and people would not like to read it then =)).
1140
1141 // For each x coordinate there will be a list of vertical segments with this x coord.
1142 std::list< std::list< gsVSegment<Z> > > vert_seg_lists;
1143
1144 // For returning
1145 std::vector< std::vector< std::vector<Z> > > result;
1146
1147 // This magically sorts seg according to x value
1148 std::sort( seg.begin(), seg.end() );
1149
1150 // Put stuff from seg into vert_seg_lists
1151 std::list< gsVSegment<Z> > segs_x; // segments with the same particular x coord
1152 for(auto it_seg = seg.begin(); it_seg != seg.end(); ++it_seg )
1153 {
1154 if( segs_x.empty() || (*it_seg).getX() == segs_x.front().getX() )
1155 segs_x.push_back( *it_seg );
1156 else
1157 {
1158 vert_seg_lists.push_back( segs_x );
1159 segs_x.erase( segs_x.begin(), segs_x.end() );
1160 segs_x.push_back( *it_seg );
1161 }
1162 // Possible simplification: if( !empty && != ){ verts_seg.push_back; erase }segs_x.push_back;
1163 }
1164 vert_seg_lists.push_back( segs_x );
1165 // So vert_seg_lists is now the list as specified before and segs_x we do not need any further.
1166
1167 // Get rid of overlaps of the segments.
1168 getRidOfOverlaps( vert_seg_lists );
1169
1170 // And now the key point: sweepline driven connect and merge procedure
1171 sweeplineConnectAndMerge( result, vert_seg_lists );
1172 return result;
1173}
1174
1175template <short_t d, class Z>
1176void gsHDomain<d, Z>::getRidOfOverlaps( std::list<std::list<gsVSegment<Z> > >& vert_seg_lists ) const
1177{
1178 bool need_to_erase = false;
1179 for(auto it_x = vert_seg_lists.begin(); it_x != vert_seg_lists.end(); )
1180 {
1181 // For each x coordinate substract overlapping segments.
1182 for(auto it_slow = (*it_x).begin(); it_slow != (*it_x).end(); ++it_slow)
1183 {
1184 // Don't we need to start the next already at (*it_x).begin() ?
1185 for(auto it_quick = it_slow; it_quick != (*it_x).end(); ++it_quick)
1186 {
1187 if( it_quick != it_slow )
1188 {
1189 need_to_erase = it_slow->cannotDeleteOverlap( *it_quick) || need_to_erase;
1190 // We do not actually use need_to_erase as initially intended
1191 // but this prevents warnings (cannot_delete_overlap returns bool).
1192 }
1193 }
1194 }
1195
1196 // Get rid of segments of zero length
1197 for(auto it_slow = (*it_x).begin(); it_slow != (*it_x).end(); )
1198 {
1199 if( (*it_slow).length() == 0 )
1200 {
1201 (*it_x).erase( it_slow++ );
1202 }
1203 else
1204 ++it_slow; // Here instead of the internal for.
1205 }
1206
1207 // There might be some empty lists;
1208 if( (*it_x).empty() )
1209 vert_seg_lists.erase( it_x++ );
1210 else
1211 ++it_x; // Here instead of the outer for.
1212 }
1213}
1214
1215template <short_t d, class Z>
1216void gsHDomain<d, Z>::sweeplineConnectAndMerge( std::vector< std::vector< std::vector<Z> > >& result,
1217 std::list< std::list< gsVSegment<Z> > >& vert_seg_lists ) const
1218{
1219 /*========================
1220 * Algorithm description:
1221 *========================
1222 * The segments in vert_seg_lists are vertical sides of the boxes from the quadtree after getting rid of overlapping ones.
1223 * The sweepline proceeds from left to right.
1224 * Events: new x-coordinate
1225 * State: list of active (or open) polylines (their part to the left from the sweepline is non-empty and does not form an open polyline yet).
1226 * In each event we:
1227 * 1] Try to append vertical segments to the active lines. Report those that get closed.
1228 * 2] Remaining segments become polylines.
1229 * 3] Try to merge active polylines. Report those that get closed.
1230 * Remark: in kissing vertices (point, where two vertical and two horizontal line segments meet) we are allowed to turn left or right
1231 * BUT we are not allowed to go straight there. In other words, the interior must remain on the same hand side (left or right) the whole time.
1232 */
1233
1234 // vector of active polylines
1235 std::list< gsAAPolyline<Z> > act_poly;
1236 std::queue< gsAAPolyline<Z> > poly_queue;
1237
1238 for(auto it_x = vert_seg_lists.begin(); it_x != vert_seg_lists.end(); ++it_x )
1239 {
1240 // Try to extend polylines by adding segments to them.
1241 // The funny queue procedure is a trick to make sure that none of the polylines
1242 // would be extended too much (i.e., over a vertex, where it should be closed).
1243 for(auto it = act_poly.begin(); it != act_poly.end(); ++it )
1244 poly_queue.push( *it );
1245
1246 act_poly.erase( act_poly.begin(), act_poly.end() );
1247
1248 gsAAPolyline<Z> curr_poly;
1249 while( !poly_queue.empty() )
1250 {
1251 curr_poly = poly_queue.front();
1252 poly_queue.pop();
1253 bool is_active = true;
1254 for(auto it_seg = (*it_x).begin(); it_seg != (*it_x).end(); )
1255 {
1256 if( curr_poly.canBeExtended( *it_seg) )
1257 {
1258 if( curr_poly.almostClosed() )
1259 result.push_back( curr_poly.writeParasolid () );
1260 else
1261 poly_queue.push( curr_poly ); // This is the prevention of wrong behaviour in kissing vertices (cf. Remark above).
1262
1263
1264 (*it_x).erase( it_seg++ );
1265 is_active = false;
1266 break;
1267 }
1268 else
1269 ++it_seg;
1270 }
1271 if( is_active )
1272 {
1273 act_poly.push_back( curr_poly );
1274 }
1275 }
1276
1277 // The remaining segments become polylines.
1278 for(auto it = (*it_x).begin(); it != (*it_x).end(); ++it )
1279 {
1280 gsAAPolyline<Z> new_polyline( *it );
1281 act_poly.push_back( new_polyline );
1282 }
1283
1284 // Merge what's possible.
1285 // Trick: go through act_poly from left to right. Check each of them with all to the right of it in act_poly.
1286 // If they can be merged, move it to the end. Those more to the left are already finalised.
1287 // Could be replaced by sorting them first according to y-coordinate (David's suggestion) and then connecting
1288 // but I ran into some implementation trouble.
1289 for(auto it_slow = act_poly.begin(); it_slow != act_poly.end(); ++it_slow )
1290 {
1291 for(auto it_quick = it_slow; it_quick != act_poly.end(); ++it_quick)
1292 {
1293 if(( it_slow != it_quick ) && ((*it_slow).mergeWith(*it_quick)))
1294 {
1295 act_poly.erase( it_quick );
1296 act_poly.push_back( *it_slow );
1297 it_slow = act_poly.erase( it_slow );
1298 it_quick = it_slow;
1299 }
1300 }
1301 }
1302
1303 // Check for closed lines as a result of the merging.
1304 for(auto it = act_poly.begin(); it != act_poly.end(); )
1305 {
1306 if( (*it).almostClosed() )
1307 {
1308 result.push_back( (*it).writeParasolid() );
1309 act_poly.erase( it++ );
1310 }
1311 else
1312 ++it;
1313
1314 }
1315 }
1316}
1317
1318template<short_t d, class Z>
1319inline void gsHDomain<d, Z>::computeFinestIndex(gsVector<Z, d> const & index,
1320 unsigned lvl,
1321 gsVector<Z, d> & result) const
1322{
1323 for(short_t i = 0; i!=d; ++i)
1324 result[i] = index[i] << (m_maxInsLevel-lvl) ;
1325}
1326
1327template<short_t d, class Z>
1328inline void gsHDomain<d, Z>::computeLevelIndex(gsVector<Z, d> const & index,
1329 unsigned lvl,
1330 gsVector<Z, d> & result) const
1331{
1332 for(short_t i = 0; i!=d; ++i)
1333 result[i] = index[i] >> (m_maxInsLevel-lvl) ;
1334}
1335
1336template<short_t d, class Z>
1337inline void gsHDomain<d, Z>::local2globalIndex(gsVector<Z, d> const & index,
1338 unsigned lvl,
1339 gsVector<Z, d> & result) const
1340{
1341 for(short_t i = 0; i!=d; ++i)
1342 result[i] = index[i] << (m_indexLevel-lvl) ;
1343}
1344
1345template<short_t d, class Z>
1346inline void gsHDomain<d, Z>::global2localIndex(gsVector<Z, d> const & index,
1347 unsigned lvl,
1348 gsVector<Z, d> & result) const
1349{
1350 for(short_t i = 0; i!=d; ++i)
1351 result[i] = index[i] >> (this->m_indexLevel-lvl) ;
1352}
1353
1354template<short_t d, class Z>
1356{
1357 m_maxInsLevel++;
1358
1359 GISMO_ASSERT( m_maxInsLevel <= m_indexLevel,
1360 "Problem with indices, increase number of levels (to do).");
1361
1362 leafSearch< levelUp_visitor >();
1363}
1364
1365template<short_t d, class Z>
1367{
1368 m_upperIndex *= 2;
1369 nodeSearch< liftCoordsOneLevel_visitor >();
1370}
1371
1372template<short_t d, class Z>
1374{
1375 m_upperIndex /= 2;
1376 nodeSearch< reduceCoordsOneLevel_visitor >();
1377}
1378
1379template<short_t d, class Z>
1381{
1382 m_maxInsLevel--;
1383 leafSearch< levelDown_visitor >();
1384}
1385
1386template<short_t d, class Z>
1387inline int gsHDomain<d, Z>::size() const
1388{
1389 return nodeSearch< numNodes_visitor >();
1390}
1391
1392template<short_t d, class Z>
1394{
1395 return leafSearch< numLeaves_visitor >();
1396}
1397
1398template<short_t d, class Z>
1400{
1401 leafSearch< printLeaves_visitor >();
1402}
1403
1404template<short_t d, class Z>
1406{
1407 m_maxInsLevel = leafSearch< maxLevel_visitor >();
1408}
1409
1410}// end namespace gismo
Class with a hierarchical domain structure represented by a box k-d-tree.
Definition gsHDomain.h:76
bool query2(point const &lower, point const &upper, int level, node *_node) const
Returns true if the box defined by lower and upper is contained in a domain with a higher level than ...
Definition gsHDomain.hpp:434
void clearBox(point const &lower, point const &upper, int lvl)
The clear function which clears box defined by points lower and upper to level lvl.
Definition gsHDomain.hpp:225
static bool isDegenerate(box const &someBox)
Returns true if the box is degenerate (has zero volume)
Definition gsHDomain.hpp:136
int query3(point const &k1, point const &k2, int level, node *_node) const
Definition gsHDomain.hpp:448
void sweeplineConnectAndMerge(std::vector< std::vector< std::vector< Z > > > &result, std::list< std::list< gsVSegment< Z > > > &vert_seg_lists) const
Sweepline algorithm.
Definition gsHDomain.hpp:1216
visitor::return_type boxSearch(point const &k1, point const &k2, int level, node *_node) const
Definition gsHDomain.hpp:518
void sinkBox(point const &lower, point const &upper, int lvl)
Sinks the box defined by points lower and upper to one level higher.
Definition gsHDomain.hpp:304
int leafSize() const
Returns the number of leaves in the tree.
Definition gsHDomain.hpp:1393
node * pointSearch(const point &p, int level, node *_node) const
Definition gsHDomain.hpp:572
std::pair< int, int > minMaxPath() const
Returns the minimim and maximum path length in the tree.
Definition gsHDomain.hpp:675
gsHDomain * clone() const
Clones the object.
Definition gsHDomain.hpp:96
void insertBox(point const &lower, point const &upper, node *_node, int lvl)
The insert function which insert box defined by points lower and upper to level lvl.
Definition gsHDomain.hpp:143
visitor::return_type leafSearch() const
Definition gsHDomain.hpp:642
std::vector< std::vector< std::vector< std::vector< Z > > > > getPolylines() const
Definition gsHDomain.hpp:1094
void divideByTwo()
Divide all coordinates by two.
Definition gsHDomain.hpp:1373
void getBoxes_vec(std::vector< std::vector< Z > > &boxes) const
Represents boxes of the tree in a big vector.
Definition gsHDomain.hpp:1044
void printLeaves() const
Prints out the leaves of the kd-tree.
Definition gsHDomain.hpp:1399
void connect_Boxes(std::vector< std::vector< Z > > &boxes) const
connect the boxes returned from quadtree getBoxes_vec()
Definition gsHDomain.hpp:898
static bool haveOverlap(box const &box1, box const &box2)
Definition gsHDomain.hpp:103
int query4(point const &lower, point const &upper, int level, node *_node) const
Definition gsHDomain.hpp:462
bool query1(point const &lower, point const &upper, int level, node *_node) const
Returns true if the box defined by lower and upper is completely contained in level and does not over...
Definition gsHDomain.hpp:420
void getBoxesInLevelIndex(gsMatrix< Z > &b1, gsMatrix< Z > &b2, gsVector< index_t > &level) const
Definition gsHDomain.hpp:790
static std::pair< point, point > select_part(point const &k1, point const &k2, point const &k3, point const &k4)
Definition gsHDomain.hpp:488
static bool isContained(box const &box1, box const &box2)
Returns true if box1 is contained in box2.
Definition gsHDomain.hpp:110
void getBoxesOnSide(boundary::side s, gsMatrix< Z > &b1, gsMatrix< Z > &b2, gsVector< Z > &level) const
Returns the boxes which make up the hierarchical domain and the respective levels touching side s.
Definition gsHDomain.hpp:739
void getRidOfOverlaps(std::list< std::list< gsVSegment< Z > > > &vert_seg_lists) const
Definition gsHDomain.hpp:1176
static void setLevel(node *_node, int lvl)
Definition gsHDomain.hpp:117
void getBoxes(gsMatrix< Z > &b1, gsMatrix< Z > &b2, gsVector< Z > &level) const
Returns the boxes which make up the hierarchical domain and the respective levels.
Definition gsHDomain.hpp:710
void multiplyByTwo()
Multiply all coordinates by two.
Definition gsHDomain.hpp:1366
visitor::return_type nodeSearch() const
Definition gsHDomain.hpp:610
void decrementLevel()
Decrement the level index globally.
Definition gsHDomain.hpp:1380
int size() const
Returns the number of nodes in the tree.
Definition gsHDomain.hpp:1387
void incrementLevel()
Increment the level index globally.
Definition gsHDomain.hpp:1355
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Class for representing a vertical line segment in 2D. Helper for the class gsAAPolyline.
Definition gsVSegment.h:27
Class for handling an axis-aligned polyline in 2D.
Provides structs and classes related to interfaces and boundaries.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides declaration of the tree node.
This is the main header file that collects wrappers of Eigen for linear algebra.
Helper class for gsAAPolyline.
The G+Smo namespace, containing all definitions for the library.
side
Identifiers for topological sides.
Definition gsBoundary.h:58
Struct of for an Axis-aligned bounding box.
Definition gsAABB.h:31
Struct representing a kd-tree node.
Definition gsKdNode.h:35
gsKdNode * adaptiveAlignedSplit(kdBox const &insBox, int index_level)
Definition gsKdNode.h:285
kdBox * box
Definition gsKdNode.h:54
Z pos
Split coordinate (meaningfull only for split nodes)
Definition gsKdNode.h:45
gsKdNode * left
Pointer to the left child of this split node (if it is one)
Definition gsKdNode.h:60
int axis
Definition gsKdNode.h:42
gsKdNode * right
Pointer to the right child of this split node (if it is one)
Definition gsKdNode.h:63
gsKdNode * parent
Pointer to the parent node.
Definition gsKdNode.h:57
int level
Definition gsKdNode.h:49