1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkCellTreeLocator.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkCellTreeLocator.h"
17 #include <cstdlib>
18 #include <cassert>
19 #include <cmath>
20 #include <stack>
21 #include <vector>
22 #include <limits>
23 #include <algorithm>
24 #include "vtkObjectFactory.h"
25 #include "vtkGenericCell.h"
26 #include "vtkIdListCollection.h"
27 #include "vtkSmartPointer.h"
28 #include "vtkCellArray.h"
29 #include "vtkPolyData.h"
30 #include "vtkBoundingBox.h"
31 #include "vtkPointData.h"
32
33 vtkStandardNewMacro(vtkCellTreeLocator);
34
35 namespace
36 {
37 const double EPSILON_= 1E-8;
38 enum { POS_X, NEG_X, POS_Y, NEG_Y, POS_Z, NEG_Z };
39 #define CELLTREE_MAX_DEPTH 32
40 }
41
42 // -------------------------------------------------------------------------
43 // This class is the basic building block of the cell tree. There is a node per dimension. i.e. There are 3 vtkCellTreeNode
44 // in x,y,z directions. In contrast, vtkModifiedBSPTree class stores the bounding planes for all 3 dimensions in a single node.
45 // LeftMax and rm defines the bounding planes.
46 // start is the location in the cell tree. e.g. for root node start is zero.
47 // size is the number of the nodes under the tree
MakeNode(unsigned int left,unsigned int d,float b[2])48 inline void vtkCellTreeLocator::vtkCellTreeNode::MakeNode( unsigned int left, unsigned int d, float b[2] ) // b is an array containing left max and right min values
49 {
50 this->Index = (d & 3) | (left << 2);
51 this->LeftMax = b[0];
52 this->RightMin = b[1];
53 }
54 //----------------------------------------------------------------------------
SetChildren(unsigned int left)55 inline void vtkCellTreeLocator::vtkCellTreeNode::SetChildren( unsigned int left )
56 {
57 this->Index = GetDimension() | (left << 2); // In index 2 LSBs (Least Significant Bits) store the dimension. MSBs store the position
58 }
59 //----------------------------------------------------------------------------
IsNode() const60 inline bool vtkCellTreeLocator::vtkCellTreeNode::IsNode() const
61 {
62 return (this->Index & 3) != 3; // For a leaf 2 LSBs in index is 3
63 }
64 //----------------------------------------------------------------------------
GetLeftChildIndex() const65 inline unsigned int vtkCellTreeLocator::vtkCellTreeNode::GetLeftChildIndex() const
66 {
67 return (this->Index >> 2);
68 }
69 //----------------------------------------------------------------------------
GetRightChildIndex() const70 inline unsigned int vtkCellTreeLocator::vtkCellTreeNode::GetRightChildIndex() const
71 {
72 return (this->Index >> 2) + 1; // Right child node is adjacent to the Left child node in the data structure
73 }
74 //----------------------------------------------------------------------------
GetDimension() const75 inline unsigned int vtkCellTreeLocator::vtkCellTreeNode::GetDimension() const
76 {
77 return this->Index & 3;
78 }
79 //----------------------------------------------------------------------------
GetLeftMaxValue() const80 inline const float& vtkCellTreeLocator::vtkCellTreeNode::GetLeftMaxValue() const
81 {
82 return this->LeftMax;
83 }
84 //----------------------------------------------------------------------------
GetRightMinValue() const85 inline const float& vtkCellTreeLocator::vtkCellTreeNode::GetRightMinValue() const
86 {
87 return this->RightMin;
88 }
89 //----------------------------------------------------------------------------
MakeLeaf(unsigned int start,unsigned int size)90 inline void vtkCellTreeLocator::vtkCellTreeNode::MakeLeaf( unsigned int start, unsigned int size )
91 {
92 this->Index = 3;
93 this->Sz = size;
94 this->St = start;
95 }
96 //----------------------------------------------------------------------------
IsLeaf() const97 bool vtkCellTreeLocator::vtkCellTreeNode::IsLeaf() const
98 {
99 return this->Index == 3;
100 }
101 //----------------------------------------------------------------------------
Start() const102 unsigned int vtkCellTreeLocator::vtkCellTreeNode::Start() const
103 {
104 return this->St;
105 }
106 //----------------------------------------------------------------------------
Size() const107 unsigned int vtkCellTreeLocator::vtkCellTreeNode::Size() const
108 {
109 return this->Sz;
110 }
111 //----------------------------------------------------------------------------
112 //
113 //----------------------------------------------------------------------------
114 // This is a helper class to traverse the cell tree. This is derived from avtCellLocatorBIH class in VisIT
115 // Member variables of this class starts with m_*
116 class vtkCellPointTraversal
117 {
118 private:
119 const vtkCellTreeLocator::vtkCellTree& m_ct;
120 unsigned int m_stack[CELLTREE_MAX_DEPTH];
121 unsigned int* m_sp; // stack pointer
122 const float* m_pos; //3-D coordinates of the points
123 vtkCellPointTraversal(const vtkCellPointTraversal&) = delete;
124 void operator=(vtkCellPointTraversal&) = delete;
125
126 protected:
127 friend class vtkCellTreeLocator::vtkCellTree;
128 friend class vtkCellTreeLocator::vtkCellTreeNode;
129 friend class vtkCellTreeBuilder;
130
131 public:
vtkCellPointTraversal(const vtkCellTreeLocator::vtkCellTree & ct,const float * pos)132 vtkCellPointTraversal( const vtkCellTreeLocator::vtkCellTree& ct, const float* pos ) :
133 m_ct(ct), m_pos(pos)
134 {
135 this->m_stack[0] = 0; // first element is set to zero
136 this->m_sp = this->m_stack + 1; //this points to the second element of the stack
137 }
138
Next()139 const vtkCellTreeLocator::vtkCellTreeNode* Next() // this returns n (the location in the CellTree) if it is a leaf or 0 if the point doesn't contain in the data domain
140 {
141 while( true )
142 {
143 if( this->m_sp == this->m_stack ) //This means the point is not within the domain
144 {
145 return nullptr;
146 }
147
148 const vtkCellTreeLocator::vtkCellTreeNode* n = &this->m_ct.Nodes.front() + *(--this->m_sp);
149
150 if( n->IsLeaf() )
151 {
152 return n;
153 }
154
155 const float p = m_pos[n->GetDimension()];
156 const unsigned int left = n->GetLeftChildIndex();
157
158 bool l = p <= n->GetLeftMaxValue(); // Check if the points is within the left sub tree
159 bool r = p >= n->GetRightMinValue(); // Check if the point is within the right sub tree
160
161 if( l && r ) // This means if there is a overlap region both left and right sub trees should be traversed
162 {
163 if( n->GetLeftMaxValue()-p < p-n->GetRightMinValue() )
164 {
165 *(this->m_sp++) = left;
166 *(this->m_sp++) = left+1;
167 }
168 else
169 {
170 *(this->m_sp++) = left+1;
171 *(this->m_sp++) = left;
172 }
173 }
174 else if( l )
175 {
176 *(this->m_sp++) = left;
177 }
178 else if( r )
179 {
180 *(this->m_sp++) = left+1;
181 }
182 }
183 }
184 };
185 //----------------------------------------------------------------------------
186 // This class builds the CellTree according to the algorithm given in the paper.
187 // This class is derived from the avtCellLocatorBIH class in VisIT. Member variables of this class starts with m_*
188 //----------------------------------------------------------------------------
189 class vtkCellTreeBuilder
190 {
191 private:
192
193 struct Bucket
194 {
195 float Min;
196 float Max;
197 unsigned int Cnt;
198
BucketvtkCellTreeBuilder::Bucket199 Bucket()
200 {
201 Cnt = 0;
202 Min = std::numeric_limits<float>::max();
203 Max = -std::numeric_limits<float>::max();
204 }
205
AddvtkCellTreeBuilder::Bucket206 void Add( const float _min, const float _max )
207 {
208 ++Cnt;
209
210 if( _min < Min )
211 {
212 Min = _min;
213 }
214
215 if( _max > Max )
216 {
217 Max = _max;
218 }
219 }
220 };
221
222 struct PerCell
223 {
224 float Min[3];
225 float Max[3];
226 unsigned int Ind;
227 };
228
229 struct CenterOrder
230 {
231 unsigned int d;
CenterOrdervtkCellTreeBuilder::CenterOrder232 CenterOrder( unsigned int _d ) : d(_d) {}
233
operator ()vtkCellTreeBuilder::CenterOrder234 bool operator()( const PerCell& pc0, const PerCell& pc1 )
235 {
236 return (pc0.Min[d] + pc0.Max[d]) < (pc1.Min[d] + pc1.Max[d]);
237 }
238 };
239
240 struct LeftPredicate
241 {
242 unsigned int d;
243 float p;
LeftPredicatevtkCellTreeBuilder::LeftPredicate244 LeftPredicate( unsigned int _d, float _p ) : d(_d), p(2.0f*_p) {}
245
operator ()vtkCellTreeBuilder::LeftPredicate246 bool operator()( const PerCell& pc )
247 {
248 return (pc.Min[d] + pc.Max[d]) < p;
249 }
250 };
251
252
253 // -------------------------------------------------------------------------
254
FindMinMax(const PerCell * begin,const PerCell * end,float * min,float * max)255 void FindMinMax( const PerCell* begin, const PerCell* end,
256 float* min, float* max )
257 {
258 if( begin == end )
259 {
260 return;
261 }
262
263 for( unsigned int d=0; d<3; ++d )
264 {
265 min[d] = begin->Min[d];
266 max[d] = begin->Max[d];
267 }
268
269
270 while( ++begin != end )
271 {
272 for( unsigned int d=0; d<3; ++d )
273 {
274 if( begin->Min[d] < min[d] ) min[d] = begin->Min[d];
275 if( begin->Max[d] > max[d] ) max[d] = begin->Max[d];
276 }
277 }
278 }
279
280 // -------------------------------------------------------------------------
281
Split(unsigned int index,float min[3],float max[3])282 void Split( unsigned int index, float min[3], float max[3] )
283 {
284 unsigned int start = this->m_nodes[index].Start();
285 unsigned int size = this->m_nodes[index].Size();
286
287 if( size < this->m_leafsize )
288 {
289 return;
290 }
291
292 PerCell* begin = &(this->m_pc[start]);
293 PerCell* end = &(this->m_pc[0])+start + size;
294 PerCell* mid = begin;
295
296 const int nbuckets = 6;
297
298 const float ext[3] = { max[0]-min[0], max[1]-min[1], max[2]-min[2] };
299 const float iext[3] = { nbuckets/ext[0], nbuckets/ext[1], nbuckets/ext[2] };
300
301 Bucket b[3][nbuckets];
302
303 for( const PerCell* pc=begin; pc!=end; ++pc )
304 {
305 for( unsigned int d=0; d<3; ++d )
306 {
307 float cen = (pc->Min[d] + pc->Max[d])/2.0f;
308 int ind = (int)( (cen-min[d])*iext[d] );
309
310 if( ind<0 )
311 {
312 ind = 0;
313 }
314
315 if( ind>=nbuckets )
316 {
317 ind = nbuckets-1;
318 }
319
320 b[d][ind].Add( pc->Min[d], pc->Max[d] );
321 }
322 }
323
324 float cost = std::numeric_limits<float>::max();
325 float plane = VTK_FLOAT_MIN; // bad value in case it doesn't get setx
326 unsigned int dim = VTK_INT_MAX; // bad value in case it doesn't get set
327
328 for( unsigned int d=0; d<3; ++d )
329 {
330 unsigned int sum = 0;
331
332 for( unsigned int n=0; n< (unsigned int)nbuckets-1; ++n )
333 {
334 float lmax = -std::numeric_limits<float>::max();
335 float rmin = std::numeric_limits<float>::max();
336
337 for( unsigned int m=0; m<=n; ++m )
338 {
339 if( b[d][m].Max > lmax )
340 {
341 lmax = b[d][m].Max;
342 }
343 }
344
345 for( unsigned int m=n+1; m< (unsigned int) nbuckets; ++m )
346 {
347 if( b[d][m].Min < rmin )
348 {
349 rmin = b[d][m].Min;
350 }
351 }
352
353 //
354 // JB : added if (...) to stop floating point error if rmin is unset
355 // this happens when some buckets are empty (bad volume calc)
356 //
357 if (lmax != -std::numeric_limits<float>::max() &&
358 rmin != std::numeric_limits<float>::max())
359 {
360 sum += b[d][n].Cnt;
361
362 float lvol = (lmax-min[d])/ext[d];
363 float rvol = (max[d]-rmin)/ext[d];
364
365 float c = lvol*sum + rvol*(size-sum);
366
367 if( sum > 0 && sum < size && c < cost )
368 {
369 cost = c;
370 dim = d;
371 plane = min[d] + (n+1)/iext[d];
372 }
373 }
374 }
375 }
376
377 if( cost != std::numeric_limits<float>::max() )
378 {
379 mid = std::partition( begin, end, LeftPredicate( dim, plane ) );
380 }
381
382 // fallback
383 if( mid == begin || mid == end )
384 {
385 dim = std::max_element( ext, ext+3 ) - ext;
386
387 mid = begin + (end-begin)/2;
388 std::nth_element( begin, mid, end, CenterOrder( dim ) );
389 }
390
391 float lmin[3], lmax[3], rmin[3], rmax[3];
392
393 FindMinMax( begin, mid, lmin, lmax );
394 FindMinMax( mid, end, rmin, rmax );
395
396 float clip[2] = { lmax[dim], rmin[dim]};
397
398 vtkCellTreeLocator::vtkCellTreeNode child[2];
399 child[0].MakeLeaf( begin - &(this->m_pc[0]), mid-begin );
400 child[1].MakeLeaf( mid - &(this->m_pc[0]), end-mid );
401
402 this->m_nodes[index].MakeNode( (int)m_nodes.size(), dim, clip );
403 this->m_nodes.insert( m_nodes.end(), child, child+2 );
404
405 Split( this->m_nodes[index].GetLeftChildIndex(), lmin, lmax );
406 Split( this->m_nodes[index].GetRightChildIndex(), rmin, rmax );
407 }
408
409 public:
410
vtkCellTreeBuilder()411 vtkCellTreeBuilder()
412 {
413 this->m_buckets = 5;
414 this->m_leafsize = 8;
415 }
416
Build(vtkCellTreeLocator * ctl,vtkCellTreeLocator::vtkCellTree & ct,vtkDataSet * ds)417 void Build( vtkCellTreeLocator *ctl, vtkCellTreeLocator::vtkCellTree& ct, vtkDataSet* ds )
418 {
419 const vtkIdType size = ds->GetNumberOfCells();
420 double cellBounds[6];
421 this->m_pc.resize(size);
422
423 float min[3] =
424 {
425 std::numeric_limits<float>::max(),
426 std::numeric_limits<float>::max(),
427 std::numeric_limits<float>::max()
428 };
429
430 float max[3] =
431 {
432 -std::numeric_limits<float>::max(),
433 -std::numeric_limits<float>::max(),
434 -std::numeric_limits<float>::max(),
435 };
436
437 for( vtkIdType i=0; i<size; ++i )
438 {
439 this->m_pc[i].Ind = i;
440
441 double *boundsPtr = cellBounds;
442 if (ctl->CellBounds)
443 {
444 boundsPtr = ctl->CellBounds[i];
445 }
446 else
447 {
448 ds->GetCellBounds(i, boundsPtr);
449 }
450
451 for( int d=0; d<3; ++d )
452 {
453 this->m_pc[i].Min[d] = boundsPtr[2*d+0];
454 this->m_pc[i].Max[d] = boundsPtr[2*d+1];
455
456 if( this->m_pc[i].Min[d] < min[d] )
457 {
458 min[d] = this->m_pc[i].Min[d];
459 }
460
461 if( this->m_pc[i].Max[d] > max[d] ) /// This can be m_pc[i].max[d] instead of min
462 {
463 max[d] = this->m_pc[i].Max[d];
464 }
465 }
466 }
467
468 ct.DataBBox[0] = min[0];
469 ct.DataBBox[1] = max[0];
470 ct.DataBBox[2] = min[1];
471 ct.DataBBox[3] = max[1];
472 ct.DataBBox[4] = min[2];
473 ct.DataBBox[5] = max[2];
474
475 vtkCellTreeLocator::vtkCellTreeNode root;
476 root.MakeLeaf( 0, size );
477 this->m_nodes.push_back( root );
478
479 Split( 0, min, max );
480
481 ct.Nodes.resize( this->m_nodes.size() );
482 ct.Nodes[0] = this->m_nodes[0];
483
484 std::vector<vtkCellTreeLocator::vtkCellTreeNode>::iterator ni = ct.Nodes.begin();
485 std::vector<vtkCellTreeLocator::vtkCellTreeNode>::iterator nn = ct.Nodes.begin()+1;
486
487 for( ; ni!=ct.Nodes.end(); ++ni )
488 {
489 if( ni->IsLeaf() )
490 {
491 continue;
492 }
493
494 *(nn++) = this->m_nodes[ni->GetLeftChildIndex()];
495 *(nn++) = this->m_nodes[ni->GetRightChildIndex()];
496
497 ni->SetChildren( nn-ct.Nodes.begin()-2 );
498 }
499
500 // --- final
501
502 ct.Leaves.resize( size );
503
504 for( int i=0; i<size; ++i )
505 {
506 ct.Leaves[i] = this->m_pc[i].Ind;
507 }
508
509 this->m_pc.clear();
510 }
511
512 public:
513 unsigned int m_buckets;
514 unsigned int m_leafsize;
515 std::vector<PerCell> m_pc;
516 std::vector<vtkCellTreeLocator::vtkCellTreeNode> m_nodes;
517 };
518
519 //----------------------------------------------------------------------------
520
521 typedef std::stack<vtkCellTreeLocator::vtkCellTreeNode*, std::vector<vtkCellTreeLocator::vtkCellTreeNode*> > nodeStack;
522
vtkCellTreeLocator()523 vtkCellTreeLocator::vtkCellTreeLocator( )
524 {
525 this->NumberOfCellsPerNode = 8;
526 this->NumberOfBuckets = 5;
527 this->Tree = nullptr;
528 }
529
530 //----------------------------------------------------------------------------
531
~vtkCellTreeLocator()532 vtkCellTreeLocator::~vtkCellTreeLocator()
533 {
534 // make it obvious that this is calling a virtual function
535 // that IS NOT overridden by a derived class as the derived class
536 // no longer exists when this is called. really the user should
537 // call FreeSearchStructure before deleting the object
538 // but I'm not going to depend on that happening.
539 this->vtkCellTreeLocator::FreeSearchStructure();
540 }
541
542 //----------------------------------------------------------------------------
BuildLocatorIfNeeded()543 void vtkCellTreeLocator::BuildLocatorIfNeeded()
544 {
545 if (this->LazyEvaluation)
546 {
547 if (!this->Tree || (this->MTime>this->BuildTime))
548 {
549 this->Modified();
550 vtkDebugMacro(<< "Forcing BuildLocator");
551 this->ForceBuildLocator();
552 }
553 }
554 }
555 //----------------------------------------------------------------------------
ForceBuildLocator()556 void vtkCellTreeLocator::ForceBuildLocator()
557 {
558 //
559 // don't rebuild if build time is newer than modified and dataset modified time
560 if ( (this->Tree) &&
561 (this->BuildTime>this->MTime) &&
562 (this->BuildTime>DataSet->GetMTime()))
563 {
564 return;
565 }
566 // don't rebuild if UseExistingSearchStructure is ON and a tree structure already exists
567 if ( (this->Tree) && this->UseExistingSearchStructure)
568 {
569 this->BuildTime.Modified();
570 vtkDebugMacro(<< "BuildLocator exited - UseExistingSearchStructure");
571 return;
572 }
573 this->BuildLocatorInternal();
574 }
575 //----------------------------------------------------------------------------
BuildLocatorInternal()576 void vtkCellTreeLocator::BuildLocatorInternal()
577 {
578 this->FreeSearchStructure();
579 if ( !this->DataSet || (this->DataSet->GetNumberOfCells() < 1) )
580 {
581 vtkErrorMacro( << " No Cells in the data set\n");
582 return;
583 }
584 //
585 if (this->CacheCellBounds)
586 {
587 this->StoreCellBounds();
588 }
589 //
590 this->Tree = new vtkCellTree;
591 vtkCellTreeBuilder builder;
592 builder.m_leafsize = this->NumberOfCellsPerNode;
593 builder.m_buckets = NumberOfBuckets;
594 builder.Build( this, *(Tree), this->DataSet );
595 this->BuildTime.Modified();
596 }
597
BuildLocator()598 void vtkCellTreeLocator::BuildLocator()
599 {
600 if (this->LazyEvaluation)
601 {
602 return;
603 }
604 this->ForceBuildLocator();
605 }
606
607 //----------------------------------------------------------------------------
FindCell(double pos[3],double,vtkGenericCell * cell,double pcoords[3],double * weights)608 vtkIdType vtkCellTreeLocator::FindCell( double pos[3], double , vtkGenericCell *cell, double pcoords[3],
609 double* weights )
610 {
611 if( this->Tree == nullptr )
612 {
613 return -1;
614 }
615
616 double dist2;
617 int subId;
618
619 const float _pos[3] = { static_cast<float>(pos[0]), static_cast<float>(pos[1]),
620 static_cast<float>(pos[2]) };
621 vtkCellPointTraversal pt( *(this->Tree), _pos );
622
623 //bool found = false;
624
625 while( const vtkCellTreeNode* n = pt.Next() )
626 {
627 const unsigned int* begin = &(this->Tree->Leaves[n->Start()]);
628 const unsigned int* end = begin + n->Size();
629
630 for( ; begin!=end; ++begin )
631 {
632 this->DataSet->GetCell(*begin, cell);
633 if( cell->EvaluatePosition(pos, nullptr, subId, pcoords, dist2, weights)==1 )
634 {
635 return *begin;
636 }
637 }
638 }
639
640 return -1;
641 }
642
643 //----------------------------------------------------------------------------
644
645 namespace
646 {
_getMinDistPOS_X(const double origin[3],const double dir[3],const double B[6])647 double _getMinDistPOS_X(const double origin[3], const double dir[3], const double B[6])
648 {
649 return ((B[0] - origin[0]) / dir[0]);
650 }
_getMinDistNEG_X(const double origin[3],const double dir[3],const double B[6])651 double _getMinDistNEG_X(const double origin[3], const double dir[3], const double B[6])
652 {
653 return ((B[1] - origin[0]) / dir[0]);
654 }
_getMinDistPOS_Y(const double origin[3],const double dir[3],const double B[6])655 double _getMinDistPOS_Y(const double origin[3], const double dir[3], const double B[6])
656 {
657 return ((B[2] - origin[1]) / dir[1]);
658 }
_getMinDistNEG_Y(const double origin[3],const double dir[3],const double B[6])659 double _getMinDistNEG_Y(const double origin[3], const double dir[3], const double B[6])
660 {
661 return ((B[3] - origin[1]) / dir[1]);
662 }
_getMinDistPOS_Z(const double origin[3],const double dir[3],const double B[6])663 double _getMinDistPOS_Z(const double origin[3], const double dir[3], const double B[6])
664 {
665 return ((B[4] - origin[2]) / dir[2]);
666 }
_getMinDistNEG_Z(const double origin[3],const double dir[3],const double B[6])667 double _getMinDistNEG_Z(const double origin[3], const double dir[3], const double B[6])
668 {
669 return ((B[5] - origin[2]) / dir[2]);
670 }
671
672 }
673 typedef std::pair<double, int> Intersection;
674
IntersectWithLine(const double p1[3],const double p2[3],double tol,double & t,double x[3],double pcoords[3],int & subId,vtkIdType & cellId,vtkGenericCell * cell)675 int vtkCellTreeLocator::IntersectWithLine(const double p1[3],
676 const double p2[3],
677 double tol,
678 double &t,
679 double x[3],
680 double pcoords[3],
681 int &subId,
682 vtkIdType &cellId,
683 vtkGenericCell *cell)
684 {
685 int hit = this->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId, cellId);
686 if (hit)
687 {
688 this->DataSet->GetCell(cellId, cell);
689 }
690 return hit;
691 }
692
IntersectWithLine(const double p1[3],const double p2[3],double tol,double & t,double x[3],double pcoords[3],int & subId,vtkIdType & cellIds)693 int vtkCellTreeLocator::IntersectWithLine(const double p1[3], const double p2[3], double tol,
694 double& t, double x[3], double pcoords[3],
695 int &subId, vtkIdType &cellIds)
696 {
697 //
698 vtkCellTreeNode *node, *near, *far;
699 double ctmin, ctmax, tmin, tmax, _tmin, _tmax, tDist;
700 double ray_vec[3] = { p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2] };
701
702 double cellBounds[6];
703
704 this->BuildLocatorIfNeeded();
705
706 // Does ray pass through root BBox
707 tmin = 0; tmax = 1;
708
709 if (!this->RayMinMaxT(p1, ray_vec, tmin, tmax)) // 0 for root node
710 {
711 return false;
712 }
713 // Ok, setup a stack and various params
714 nodeStack ns;
715 double closest_intersection = VTK_FLOAT_MAX;
716 bool HIT = false;
717 // setup our axis optimized ray box edge stuff
718 int axis = getDominantAxis(ray_vec);
719 double (*_getMinDist)(const double origin[3], const double dir[3], const double B[6]);
720 switch (axis)
721 {
722 case POS_X: _getMinDist = _getMinDistPOS_X; break;
723 case NEG_X: _getMinDist = _getMinDistNEG_X; break;
724 case POS_Y: _getMinDist = _getMinDistPOS_Y; break;
725 case NEG_Y: _getMinDist = _getMinDistNEG_Y; break;
726 case POS_Z: _getMinDist = _getMinDistPOS_Z; break;
727 default: _getMinDist = _getMinDistNEG_Z; break;
728 }
729
730
731 //
732 // OK, lets walk the tree and find intersections
733 //
734 vtkCellTreeNode* n = &this->Tree->Nodes.front();
735 ns.push(n);
736 while (!ns.empty())
737 {
738 node = ns.top();
739 ns.pop();
740 // We do as few tests on the way down as possible, because our BBoxes
741 // can be quite tight and we want to reject as many boxes as possible without
742 // testing them at all - mainly because we quickly get to a leaf node and
743 // test candidates, once we've found a hit, we note the intersection t val,
744 // as soon as we pull a BBox of the stack that has a closest point further
745 // than the t val, we know we can stop.
746
747 int mustCheck = 0; // to check if both left and right sub trees need to be checked
748
749 //
750 while (!node->IsLeaf())
751 { // this must be a parent node
752 // Which child node is closest to ray origin - given direction
753 Classify(p1, ray_vec, tDist, near, node, far, mustCheck);
754 // if the distance to the far edge of the near box is > tmax, no need to test far box
755 // (we still need to test Mid because it may overlap slightly)
756 if(mustCheck)
757 {
758 ns.push(far);
759 node = near;
760 }
761 else if ((tDist > tmax) || (tDist <= 0) )
762 { // <=0 for ray on edge
763 node = near;
764 }
765 // if the distance to the far edge of the near box is < tmin, no need to test near box
766 else if (tDist < tmin)
767 {
768 ns.push(near);
769 node = far;
770 }
771 // All the child nodes may be candidates, keep near, push far then mid
772 else
773 {
774 ns.push(far);
775 node = near;
776 }
777 }
778 double t_hit, ipt[3];
779 // Ok, so we're a leaf node, first check the BBox against the ray
780 // then test the candidates in our sorted ray direction order
781 _tmin = tmin; _tmax = tmax;
782 // if (node->RayMinMaxT(p1, ray_vec, _tmin, _tmax)) {
783 // Was the closest point on the box > intersection point
784 //if (_tmax>closest_intersection) break;
785 //
786 for (int i=0; i< (int)node->Size(); i++)
787 {
788 vtkIdType cell_ID = this->Tree->Leaves[node->Start()+i];
789 //
790
791 double* boundsPtr = cellBounds;
792 if (this->CellBounds)
793 {
794 boundsPtr = this->CellBounds[cell_ID];
795 }
796 else
797 {
798 this->DataSet->GetCellBounds(cell_ID, cellBounds);
799 }
800 if (_getMinDist(p1, ray_vec, boundsPtr) > closest_intersection)
801 {
802 break;
803 }
804 //
805 ctmin = _tmin; ctmax = _tmax;
806 if (this->RayMinMaxT(boundsPtr, p1, ray_vec, ctmin, ctmax))
807 {
808 if (this->IntersectCellInternal(cell_ID, p1, p2, tol, t_hit, ipt, pcoords, subId))
809 {
810 if (t_hit<closest_intersection)
811 {
812 HIT = true;
813 closest_intersection = t_hit;
814 cellIds = cell_ID;
815 x[0] = ipt[0];
816 x[1] = ipt[1];
817 x[2] = ipt[2];
818 }
819
820
821 }
822 }
823 }
824 // }
825 }
826 if (HIT)
827 {
828 t = closest_intersection;
829 }
830 //
831 return HIT;
832
833 }
834 //----------------------------------------------------------------------------
RayMinMaxT(const double origin[3],const double dir[3],double & rTmin,double & rTmax)835 bool vtkCellTreeLocator::RayMinMaxT(const double origin[3],
836 const double dir[3],
837 double &rTmin,
838 double &rTmax)
839 {
840 double tT;
841 // X-Axis
842 float bounds[6];
843
844 bounds[0] = this->Tree->DataBBox[0];
845 bounds[1] = this->Tree->DataBBox[1];
846 bounds[2] = this->Tree->DataBBox[2];
847 bounds[3] = this->Tree->DataBBox[3];
848 bounds[4] = this->Tree->DataBBox[4];
849 bounds[5] = this->Tree->DataBBox[5];
850
851 if (dir[0] < -EPSILON_)
852 { // ray travelling in -x direction
853 tT = (bounds[0] - origin[0]) / dir[0];
854 if (tT < rTmin)
855 {
856 return (false); // ray already left of box. Can't hit
857 }
858 if (tT <= rTmax)
859 {
860 rTmax = tT; // update new tmax
861 }
862 tT = (bounds[1] - origin[0]) / dir[0]; // distance to right edge
863 if (tT >= rTmin)
864 { // can't see this ever happening
865 if (tT > rTmax)
866 {
867 return false; // clip start of ray to right edge
868 }
869 rTmin = tT;
870 }
871 }
872 else if (dir[0] > EPSILON_)
873 {
874 tT = (bounds[1] - origin[0]) / dir[0];
875 if (tT < rTmin)
876 {
877 return (false);
878 }
879 if (tT <= rTmax)
880 {
881 rTmax = tT;
882 }
883 tT = (bounds[0] - origin[0]) / dir[0];
884 if (tT >= rTmin)
885 {
886 if (tT > rTmax)
887 {
888 return (false);
889 }
890 rTmin = tT;
891 }
892 }
893 else if (origin[0] < bounds[0] || origin[0] > bounds[1])
894 {
895 return (false);
896 }
897 // Y-Axis
898 if (dir[1] < -EPSILON_)
899 {
900 tT = (bounds[2] - origin[1]) / dir[1];
901 if (tT < rTmin)
902 {
903 return (false);
904 }
905 if (tT <= rTmax)
906 {
907 rTmax = tT;
908 }
909 tT = (bounds[3] - origin[1]) / dir[1];
910 if (tT >= rTmin)
911 {
912 if (tT > rTmax)
913 {
914 return (false);
915 }
916 rTmin = tT;
917 }
918 }
919 else if (dir[1] > EPSILON_)
920 {
921 tT = (bounds[3] - origin[1]) / dir[1];
922 if (tT < rTmin)
923 {
924 return (false);
925 }
926 if (tT <= rTmax)
927 {
928 rTmax = tT;
929 }
930 tT = (bounds[2] - origin[1]) / dir[1];
931 if (tT >= rTmin)
932 {
933 if (tT > rTmax)
934 {
935 return (false);
936 }
937 rTmin = tT;
938 }
939 }
940 else if (origin[1] < bounds[2] || origin[1] > bounds[3])
941 {
942 return (false);
943 }
944 // Z-Axis
945 if (dir[2] < -EPSILON_)
946 {
947 tT = (bounds[4] - origin[2]) / dir[2];
948 if (tT < rTmin)
949 {
950 return (false);
951 }
952 if (tT <= rTmax)
953 {
954 rTmax = tT;
955 }
956 tT = (bounds[5] - origin[2]) / dir[2];
957 if (tT >= rTmin)
958 {
959 if (tT > rTmax)
960 {
961 return (false);
962 }
963 rTmin = tT;
964 }
965 }
966 else if (dir[2] > EPSILON_)
967 {
968 tT = (bounds[5] - origin[2]) / dir[2];
969 if (tT < rTmin)
970 {
971 return (false);
972 }
973 if (tT <= rTmax)
974 {
975 rTmax = tT;
976 }
977 tT = (bounds[4] - origin[2]) / dir[2];
978 if (tT >= rTmin)
979 {
980 if (tT > rTmax)
981 {
982 return (false);
983 }
984 rTmin = tT;
985 }
986 }
987 else if (origin[2] < bounds[4] || origin[2] > bounds[5])
988 {
989 return (false);
990 }
991 return (true);
992 }
993 //----------------------------------------------------------------------------
RayMinMaxT(const double bounds[6],const double origin[3],const double dir[3],double & rTmin,double & rTmax)994 bool vtkCellTreeLocator::RayMinMaxT(const double bounds[6],
995 const double origin[3],
996 const double dir[3],
997 double &rTmin,
998 double &rTmax)
999 {
1000 double tT;
1001 // X-Axis
1002 if (dir[0] < -EPSILON_)
1003 { // ray travelling in -x direction
1004 tT = (bounds[0] - origin[0]) / dir[0]; // Ipoint less than minT - ray outside box!
1005 if (tT < rTmin)
1006 {
1007 return (false);
1008 }
1009 if (tT <= rTmax)
1010 {
1011 rTmax = tT; // update new tmax
1012 }
1013 tT = (bounds[1] - origin[0]) / dir[0]; // distance to right edge
1014 if (tT >= rTmin)
1015 { // can't see this ever happening
1016 if (tT > rTmax)
1017 {
1018 return false; // clip start of ray to right edge
1019 }
1020 rTmin = tT;
1021 }
1022 }
1023 else if (dir[0] > EPSILON_)
1024 {
1025 tT = (bounds[1] - origin[0]) / dir[0];
1026 if (tT < rTmin)
1027 {
1028 return (false);
1029 }
1030 if (tT <= rTmax)
1031 {
1032 rTmax = tT;
1033 }
1034 tT = (bounds[0] - origin[0]) / dir[0];
1035 if (tT >= rTmin)
1036 {
1037 if (tT > rTmax)
1038 {
1039 return (false);
1040 }
1041 rTmin = tT;
1042 }
1043 }
1044 else if (origin[0] < bounds[0] || origin[0] > bounds[1])
1045 {
1046 return (false);
1047 }
1048 // Y-Axis
1049 if (dir[1] < -EPSILON_)
1050 {
1051 tT = (bounds[2] - origin[1]) / dir[1];
1052 if (tT < rTmin)
1053 {
1054 return (false);
1055 }
1056 if (tT <= rTmax) rTmax = tT;
1057 tT = (bounds[3] - origin[1]) / dir[1];
1058 if (tT >= rTmin)
1059 {
1060 if (tT > rTmax)
1061 {
1062 return (false);
1063 }
1064 rTmin = tT;
1065 }
1066 }
1067 else if (dir[1] > EPSILON_)
1068 {
1069 tT = (bounds[3] - origin[1]) / dir[1];
1070 if (tT < rTmin)
1071 {
1072 return (false);
1073 }
1074 if (tT <= rTmax)
1075 {
1076 rTmax = tT;
1077 }
1078 tT = (bounds[2] - origin[1]) / dir[1];
1079 if (tT >= rTmin)
1080 {
1081 if (tT > rTmax)
1082 {
1083 return (false);
1084 }
1085 rTmin = tT;
1086 }
1087 }
1088 else if (origin[1] < bounds[2] || origin[1] > bounds[3])
1089 {
1090 return (false);
1091 }
1092 // Z-Axis
1093 if (dir[2] < -EPSILON_)
1094 {
1095 tT = (bounds[4] - origin[2]) / dir[2];
1096 if (tT < rTmin)
1097 {
1098 return (false);
1099 }
1100 if (tT <= rTmax)
1101 {
1102 rTmax = tT;
1103 }
1104 tT = (bounds[5] - origin[2]) / dir[2];
1105 if (tT >= rTmin)
1106 {
1107 if (tT > rTmax)
1108 {
1109 return (false);
1110 }
1111 rTmin = tT;
1112 }
1113 }
1114 else if (dir[2] > EPSILON_)
1115 {
1116 tT = (bounds[5] - origin[2]) / dir[2];
1117 if (tT < rTmin)
1118 {
1119 return (false);
1120 }
1121 if (tT <= rTmax)
1122 {
1123 rTmax = tT;
1124 }
1125 tT = (bounds[4] - origin[2]) / dir[2];
1126 if (tT >= rTmin)
1127 {
1128 if (tT > rTmax)
1129 {
1130 return (false);
1131 }
1132 rTmin = tT;
1133 }
1134 }
1135 else if (origin[2] < bounds[4] || origin[2] > bounds[5])
1136 {
1137 return (false);
1138 }
1139 return (true);
1140 }
1141 //----------------------------------------------------------------------------
getDominantAxis(const double dir[3])1142 int vtkCellTreeLocator::getDominantAxis(const double dir[3])
1143 {
1144 double tX = (dir[0]>0) ? dir[0] : -dir[0];
1145 double tY = (dir[1]>0) ? dir[1] : -dir[1];
1146 double tZ = (dir[2]>0) ? dir[2] : -dir[2];
1147 if (tX > tY && tX > tZ)
1148 {
1149 return ((dir[0] > 0) ? POS_X : NEG_X);
1150 }
1151 else if ( tY > tZ )
1152 {
1153 return ((dir[1] > 0) ? POS_Y : NEG_Y);
1154 }
1155 else
1156 {
1157 return ((dir[2] > 0) ? POS_Z : NEG_Z);
1158 }
1159 }
1160 //----------------------------------------------------------------------------
Classify(const double origin[3],const double dir[3],double & rDist,vtkCellTreeNode * & near,vtkCellTreeNode * & parent,vtkCellTreeNode * & far,int & mustCheck)1161 void vtkCellTreeLocator::Classify(const double origin[3],
1162 const double dir[3],
1163 double &rDist,
1164 vtkCellTreeNode *&near, vtkCellTreeNode *&parent,
1165 vtkCellTreeNode *&far, int& mustCheck)
1166 {
1167 double tOriginToDivPlane = parent->GetLeftMaxValue() - origin[parent->GetDimension()];
1168 double tOriginToDivPlane2 = parent->GetRightMinValue() - origin[parent->GetDimension()];
1169 double tDivDirection = dir[parent->GetDimension()];
1170 if ( tOriginToDivPlane2 > 0 ) // origin is right of the rmin
1171 {
1172 near = &this->Tree->Nodes.at(parent->GetLeftChildIndex());
1173 far = &this->Tree->Nodes.at(parent->GetLeftChildIndex()+1);
1174 rDist = (tDivDirection) ? tOriginToDivPlane2 / tDivDirection : VTK_FLOAT_MAX;
1175 }
1176 else if (tOriginToDivPlane < 0) // origin is left of the lm
1177 {
1178 far = &this->Tree->Nodes.at(parent->GetLeftChildIndex());
1179 near = &this->Tree->Nodes.at(parent->GetLeftChildIndex()+1);
1180 rDist = (tDivDirection) ? tOriginToDivPlane / tDivDirection : VTK_FLOAT_MAX;
1181 }
1182
1183
1184 else
1185 {
1186 if(tOriginToDivPlane > 0 && tOriginToDivPlane2 < 0)
1187 {
1188 mustCheck = 1; // The point is within right min and left max. both left and right subtrees must be checked
1189 }
1190
1191 if ( tDivDirection < 0)
1192 {
1193 near = &this->Tree->Nodes.at(parent->GetLeftChildIndex());
1194 far = &this->Tree->Nodes.at(parent->GetLeftChildIndex()+1);
1195 if(!(tOriginToDivPlane > 0 || tOriginToDivPlane < 0))
1196 {
1197 mustCheck=1; // Ray was exactly on edge left max box.
1198 }
1199 rDist = (tDivDirection) ? 0 / tDivDirection : VTK_FLOAT_MAX;
1200 }
1201 else
1202 {
1203 far = &this->Tree->Nodes.at(parent->GetLeftChildIndex());
1204 near = &this->Tree->Nodes.at(parent->GetLeftChildIndex()+1);
1205 if(!(tOriginToDivPlane2 > 0 || tOriginToDivPlane2 < 0))
1206 {
1207 mustCheck=1; // Ray was exactly on edge right min box.
1208 }
1209 rDist = (tDivDirection) ? 0 / tDivDirection : VTK_FLOAT_MAX;
1210 }
1211 }
1212
1213 }
1214 //----------------------------------------------------------------------------
IntersectCellInternal(vtkIdType cell_ID,const double p1[3],const double p2[3],const double tol,double & t,double ipt[3],double pcoords[3],int & subId)1215 int vtkCellTreeLocator::IntersectCellInternal(
1216 vtkIdType cell_ID,
1217 const double p1[3],
1218 const double p2[3],
1219 const double tol,
1220 double &t,
1221 double ipt[3],
1222 double pcoords[3],
1223 int &subId)
1224 {
1225 this->DataSet->GetCell(cell_ID, this->GenericCell);
1226 return this->GenericCell->IntersectWithLine(const_cast<double*>(p1), const_cast<double*>(p2), tol, t, ipt, pcoords, subId);
1227 }
1228 //----------------------------------------------------------------------------
FreeSearchStructure(void)1229 void vtkCellTreeLocator::FreeSearchStructure(void)
1230 {
1231 delete this->Tree;
1232 this->Tree = nullptr;
1233 this->Superclass::FreeCellBounds();
1234 }
1235 //---------------------------------------------------------------------------
1236 // For drawing coloured boxes, we want the level/depth
1237 typedef std::pair<vtkBoundingBox, int> boxLevel;
1238 typedef std::vector<boxLevel> boxlist;
1239 // For testing bounds of the tree we need node/box
1240 typedef std::pair<vtkCellTreeLocator::vtkCellTreeNode*, boxLevel> nodeBoxLevel;
1241 typedef std::stack<nodeBoxLevel, std::vector<nodeBoxLevel> > nodeinfostack;
1242 //---------------------------------------------------------------------------
SplitNodeBox(vtkCellTreeLocator::vtkCellTreeNode * n,vtkBoundingBox & b,vtkBoundingBox & l,vtkBoundingBox & r)1243 static void SplitNodeBox(vtkCellTreeLocator::vtkCellTreeNode *n, vtkBoundingBox &b, vtkBoundingBox &l, vtkBoundingBox &r)
1244 {
1245 double minpt[3], maxpt[3];
1246 // create a box for left node
1247 vtkBoundingBox ll(b);
1248 ll.GetMaxPoint(maxpt[0], maxpt[1], maxpt[2]);
1249 maxpt[n->GetDimension()] = n->GetLeftMaxValue();
1250 ll.SetMaxPoint(maxpt[0], maxpt[1], maxpt[2]);
1251 l = ll;
1252 // create a box for right node
1253 vtkBoundingBox rr(b);
1254 rr.GetMinPoint(minpt[0], minpt[1], minpt[2]);
1255 minpt[n->GetDimension()] = n->GetRightMinValue();
1256 rr.SetMinPoint(minpt[0], minpt[1], minpt[2]);
1257 r = rr;
1258 }
1259 //---------------------------------------------------------------------------
AddBox(vtkPolyData * pd,double * bounds,int level)1260 static void AddBox(vtkPolyData *pd, double *bounds, int level)
1261 {
1262 vtkPoints *pts = pd->GetPoints();
1263 vtkCellArray *lines = pd->GetLines();
1264 vtkIntArray *levels = vtkArrayDownCast<vtkIntArray>(pd->GetPointData()->GetArray(0));
1265 double x[3];
1266 vtkIdType cells[8], ids[2];
1267 //
1268 x[0] = bounds[0]; x[1] = bounds[2]; x[2] = bounds[4];
1269 cells[0] = pts->InsertNextPoint(x);
1270 x[0] = bounds[1]; x[1] = bounds[2]; x[2] = bounds[4];
1271 cells[1] = pts->InsertNextPoint(x);
1272 x[0] = bounds[0]; x[1] = bounds[3]; x[2] = bounds[4];
1273 cells[2] = pts->InsertNextPoint(x);
1274 x[0] = bounds[1]; x[1] = bounds[3]; x[2] = bounds[4];
1275 cells[3] = pts->InsertNextPoint(x);
1276 x[0] = bounds[0]; x[1] = bounds[2]; x[2] = bounds[5];
1277 cells[4] = pts->InsertNextPoint(x);
1278 x[0] = bounds[1]; x[1] = bounds[2]; x[2] = bounds[5];
1279 cells[5] = pts->InsertNextPoint(x);
1280 x[0] = bounds[0]; x[1] = bounds[3]; x[2] = bounds[5];
1281 cells[6] = pts->InsertNextPoint(x);
1282 x[0] = bounds[1]; x[1] = bounds[3]; x[2] = bounds[5];
1283 cells[7] = pts->InsertNextPoint(x);
1284 //
1285 ids[0] = cells[0]; ids[1] = cells[1];
1286 lines->InsertNextCell(2,ids);
1287 ids[0] = cells[2]; ids[1] = cells[3];
1288 lines->InsertNextCell(2,ids);
1289 ids[0] = cells[4]; ids[1] = cells[5];
1290 lines->InsertNextCell(2,ids);
1291 ids[0] = cells[6]; ids[1] = cells[7];
1292 lines->InsertNextCell(2,ids);
1293 ids[0] = cells[0]; ids[1] = cells[2];
1294 lines->InsertNextCell(2,ids);
1295 ids[0] = cells[1]; ids[1] = cells[3];
1296 lines->InsertNextCell(2,ids);
1297 ids[0] = cells[4]; ids[1] = cells[6];
1298 lines->InsertNextCell(2,ids);
1299 ids[0] = cells[5]; ids[1] = cells[7];
1300 lines->InsertNextCell(2,ids);
1301 ids[0] = cells[0]; ids[1] = cells[4];
1302 lines->InsertNextCell(2,ids);
1303 ids[0] = cells[1]; ids[1] = cells[5];
1304 lines->InsertNextCell(2,ids);
1305 ids[0] = cells[2]; ids[1] = cells[6];
1306 lines->InsertNextCell(2,ids);
1307 ids[0] = cells[3]; ids[1] = cells[7];
1308 lines->InsertNextCell(2,ids);
1309 //
1310 // Colour boxes by scalar if array present
1311 //
1312 for (int i=0; levels && i<8; i++)
1313 {
1314 levels->InsertNextTuple1(level);
1315 }
1316 }
1317 //---------------------------------------------------------------------------
GenerateRepresentation(int level,vtkPolyData * pd)1318 void vtkCellTreeLocator::GenerateRepresentation(int level, vtkPolyData *pd)
1319 {
1320 this->BuildLocatorIfNeeded();
1321 //
1322 nodeinfostack ns;
1323 boxlist bl;
1324 //
1325 vtkCellTreeNode *n0 = &this->Tree->Nodes.front();
1326 // create a box for the root
1327 float *DataBBox = this->Tree->DataBBox;
1328 vtkBoundingBox lbox, rbox, rootbox(DataBBox[0], DataBBox[1], DataBBox[2], DataBBox[3], DataBBox[4], DataBBox[5]);
1329 ns.push(nodeBoxLevel(n0,boxLevel(rootbox,0)));
1330 while (!ns.empty())
1331 {
1332 n0 = ns.top().first;
1333 int lev = ns.top().second.second;
1334 if (n0->IsLeaf() && ((lev==level) || (level==-1)))
1335 {
1336 bl.push_back(boxLevel(ns.top().second.first,lev));
1337 ns.pop();
1338 }
1339 else if (n0->IsLeaf())
1340 {
1341 ns.pop();
1342 }
1343 else if (n0->IsNode())
1344 {
1345 SplitNodeBox(n0, ns.top().second.first, lbox, rbox);
1346 vtkCellTreeNode *n1 = &this->Tree->Nodes.at(n0->GetLeftChildIndex());
1347 vtkCellTreeNode *n2 = &this->Tree->Nodes.at(n0->GetLeftChildIndex()+1);
1348 ns.pop();
1349 ns.push(nodeBoxLevel(n1,boxLevel(lbox,lev+1)));
1350 ns.push(nodeBoxLevel(n2,boxLevel(rbox,lev+1)));
1351 }
1352 }
1353 //
1354 //
1355 //
1356 // For each node, add the bbox to our polydata
1357 int s = (int) bl.size();
1358 for (int i=0; i<s; i++)
1359 {
1360 double bounds[6];
1361 bl[i].first.GetBounds(bounds);
1362 AddBox(pd, bounds, bl[i].second);
1363 }
1364 }
1365 //---------------------------------------------------------------------------
FindCellsWithinBounds(double * bbox,vtkIdList * cells)1366 void vtkCellTreeLocator::FindCellsWithinBounds(double *bbox, vtkIdList *cells)
1367 {
1368 this->BuildLocatorIfNeeded();
1369 //
1370 nodeinfostack ns;
1371 double cellBounds[6];
1372 vtkBoundingBox TestBox(bbox);
1373 //
1374 vtkCellTreeNode *n0 = &this->Tree->Nodes.front();
1375 // create a box for the root
1376 float *DataBBox = this->Tree->DataBBox;
1377 vtkBoundingBox lbox, rbox, rootbox(DataBBox[0], DataBBox[1], DataBBox[2], DataBBox[3], DataBBox[4], DataBBox[5]);
1378 ns.push(nodeBoxLevel(n0,boxLevel(rootbox,0)));
1379 while (!ns.empty())
1380 {
1381 n0 = ns.top().first;
1382 vtkBoundingBox &nodebox = ns.top().second.first;
1383 if (TestBox.Intersects(nodebox))
1384 {
1385 if (n0->IsLeaf())
1386 {
1387 for (int i=0; i<(int)n0->Size(); i++)
1388 {
1389 vtkIdType cell_ID = this->Tree->Leaves[n0->Start()+i];
1390 double *boundsPtr = cellBounds;
1391 if (this->CellBounds)
1392 {
1393 boundsPtr = this->CellBounds[cell_ID];
1394 }
1395 else
1396 {
1397 this->DataSet->GetCellBounds(cell_ID, boundsPtr);
1398 }
1399 vtkBoundingBox box(boundsPtr);
1400 if (TestBox.Intersects(box))
1401 {
1402 cells->InsertNextId(cell_ID);
1403 }
1404 }
1405 ns.pop();
1406 }
1407 else
1408 {
1409 int lev = ns.top().second.second;
1410 SplitNodeBox(n0, nodebox, lbox, rbox);
1411 vtkCellTreeNode *n1 = &this->Tree->Nodes.at(n0->GetLeftChildIndex());
1412 vtkCellTreeNode *n2 = &this->Tree->Nodes.at(n0->GetLeftChildIndex()+1);
1413 ns.pop();
1414 ns.push(nodeBoxLevel(n1,boxLevel(lbox,lev+1)));
1415 ns.push(nodeBoxLevel(n2,boxLevel(rbox,lev+1)));
1416 }
1417 }
1418 else
1419 {
1420 ns.pop();
1421 }
1422 }
1423 }
1424 //---------------------------------------------------------------------------
1425
PrintSelf(ostream & os,vtkIndent indent)1426 void vtkCellTreeLocator::PrintSelf(ostream& os, vtkIndent indent)
1427 {
1428 this->Superclass::PrintSelf(os,indent);
1429 }
1430