1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkOctreePointLocator.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  Copyright (c) Sandia Corporation
17  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19 
20 #include "vtkOctreePointLocator.h"
21 
22 #include "vtkCellArray.h"
23 #include "vtkCommand.h"
24 #include "vtkDataSet.h"
25 #include "vtkFloatArray.h"
26 #include "vtkIdList.h"
27 #include "vtkIdTypeArray.h"
28 #include "vtkIntArray.h"
29 #include "vtkMath.h"
30 #include "vtkObjectFactory.h"
31 #include "vtkOctreePointLocatorNode.h"
32 #include "vtkPoints.h"
33 #include "vtkPointSet.h"
34 #include "vtkPolyData.h"
35 
36 #include <list>
37 #include <map>
38 #include <queue>
39 #include <stack>
40 #include <vector>
41 
42 vtkStandardNewMacro(vtkOctreePointLocator);
43 
44 // helper class for ordering the points in
45 // vtkOctreePointLocator::FindClosestNPoints()
46 namespace
47 {
48   class OrderPoints
49   {
50   public:
OrderPoints(int numDesiredPoints)51     OrderPoints(int numDesiredPoints)
52       {
53         this->NumDesiredPoints = numDesiredPoints;
54         this->NumPoints = 0;
55         this->LargestDist2 = VTK_FLOAT_MAX;
56       }
57 
InsertPoint(float dist2,vtkIdType id)58     void InsertPoint(float dist2, vtkIdType id)
59       {
60         if(dist2 <= this->LargestDist2 ||
61            this->NumPoints < this->NumDesiredPoints)
62           {
63           std::map<float, std::list<vtkIdType> >::iterator it=
64             this->dist2ToIds.find(dist2);
65           this->NumPoints++;
66           if(it == this->dist2ToIds.end())
67             {
68             std::list<vtkIdType> idset;
69             idset.push_back(id);
70             this->dist2ToIds[dist2] = idset;
71             }
72           else
73             {
74             it->second.push_back(id);
75             }
76           if(this->NumPoints > this->NumDesiredPoints)
77             {
78             it=this->dist2ToIds.end();
79             it--;
80             if((this->NumPoints-it->second.size()) > this->NumDesiredPoints)
81               {
82               this->NumPoints -= it->second.size();
83               std::map<float, std::list<vtkIdType> >::iterator it2 = it;
84               it2--;
85               this->LargestDist2 = it2->first;
86               this->dist2ToIds.erase(it);
87               }
88             }
89           }
90       }
GetSortedIds(vtkIdList * ids)91     void GetSortedIds(vtkIdList* ids)
92       {
93         ids->Reset();
94         vtkIdType numIds = (this->NumDesiredPoints < this->NumPoints)
95           ? this->NumDesiredPoints : this->NumPoints;
96         ids->SetNumberOfIds(numIds);
97         vtkIdType counter = 0;
98         std::map<float, std::list<vtkIdType> >::iterator it=
99           this->dist2ToIds.begin();
100         while(counter < numIds && it!=this->dist2ToIds.end())
101           {
102           std::list<vtkIdType>::iterator lit=it->second.begin();
103           while(counter < numIds && lit!=it->second.end())
104             {
105             ids->InsertId(counter, *lit);
106             counter++;
107             lit++;
108             }
109           it++;
110           }
111       }
112 
GetLargestDist2()113     float GetLargestDist2()
114       {
115         return this->LargestDist2;
116       }
117 
118   private:
119     size_t NumDesiredPoints, NumPoints;
120     float LargestDist2;
121     // map from dist^2 to a list of ids
122     std::map<float, std::list<vtkIdType> > dist2ToIds;
123   };
124 }
125 
126 //----------------------------------------------------------------------------
vtkOctreePointLocator()127 vtkOctreePointLocator::vtkOctreePointLocator()
128 {
129   this->FudgeFactor = 0;
130   this->MaxWidth = 0.0;
131   this->MaxLevel  = 20;
132   this->MaximumPointsPerRegion = 100;
133   this->Level    = 0;
134   this->Top      = NULL;
135   this->NumberOfLocatorPoints = 0;
136   this->LocatorPoints = NULL;
137   this->LocatorIds = NULL;
138   this->LeafNodeList = NULL;
139   this->CreateCubicOctants = 1;
140   this->NumberOfLeafNodes = 0;
141 }
142 
143 //----------------------------------------------------------------------------
DeleteAllDescendants(vtkOctreePointLocatorNode * octant)144 void vtkOctreePointLocator::DeleteAllDescendants(
145   vtkOctreePointLocatorNode *octant)
146 {
147   if(octant->GetChild(0))
148     {
149     for(int i=0;i<8;i++)
150       {
151       vtkOctreePointLocatorNode* child = octant->GetChild(i);
152       vtkOctreePointLocator::DeleteAllDescendants(child);
153       }
154     octant->DeleteChildNodes();
155     }
156 }
157 
158 //----------------------------------------------------------------------------
~vtkOctreePointLocator()159 vtkOctreePointLocator::~vtkOctreePointLocator()
160 {
161   this->FreeSearchStructure();
162 
163   delete []this->LocatorPoints;
164   this->LocatorPoints = 0;
165 
166   delete []this->LocatorIds;
167   this->LocatorIds = 0;
168 
169   delete []this->LeafNodeList;
170   this->LeafNodeList = 0;
171 }
172 
173 //----------------------------------------------------------------------------
GetBounds(double * bounds)174 void vtkOctreePointLocator::GetBounds(double *bounds)
175 {
176   if (this->Top)
177     {
178     this->Top->GetBounds(bounds);
179     }
180 }
181 
182 //----------------------------------------------------------------------------
GetBounds()183 double* vtkOctreePointLocator::GetBounds()
184 {
185   double* bounds = vtkAbstractPointLocator::GetBounds();
186   if (this->Top)
187     {
188     this->Top->GetBounds(bounds);
189     }
190   return bounds;
191 }
192 
193 //----------------------------------------------------------------------------
GetRegionBounds(int leafNodeId,double bounds[6])194 void vtkOctreePointLocator::GetRegionBounds(int leafNodeId,
195                                             double bounds[6])
196 {
197   if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
198     {
199     vtkErrorMacro("Invalid region.");
200     return;
201     }
202 
203   vtkOctreePointLocatorNode *node = this->LeafNodeList[leafNodeId];
204 
205   node->GetBounds(bounds);
206 }
207 
208 //----------------------------------------------------------------------------
GetRegionDataBounds(int leafNodeId,double bounds[6])209 void vtkOctreePointLocator::GetRegionDataBounds(int leafNodeId,
210                                                 double bounds[6])
211 {
212   if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
213     {
214     vtkErrorMacro("Invalid region.");
215     return;
216     }
217 
218   vtkOctreePointLocatorNode *node = this->LeafNodeList[leafNodeId];
219 
220   node->GetDataBounds(bounds);
221 }
222 
223 //----------------------------------------------------------------------------
SetDataBoundsToSpatialBounds(vtkOctreePointLocatorNode * octant)224 void vtkOctreePointLocator::SetDataBoundsToSpatialBounds(
225   vtkOctreePointLocatorNode *octant)
226 {
227   octant->SetMinDataBounds(octant->GetMinBounds());
228   octant->SetMaxDataBounds(octant->GetMaxBounds());
229 
230   if (octant->GetChild(0))
231     {
232     for(int i=0;i<8;i++)
233       {
234       vtkOctreePointLocator::SetDataBoundsToSpatialBounds(octant->GetChild(i));
235       }
236     }
237 }
238 
239 //----------------------------------------------------------------------------
DivideTest(int size,int level)240 int vtkOctreePointLocator::DivideTest(int size, int level)
241 {
242   if (level >= this->MaxLevel)
243     {
244     return 0;
245     }
246 
247   if(size > this->GetMaximumPointsPerRegion())
248     {
249     return 1;
250     }
251   return 0;
252 }
253 
254 //----------------------------------------------------------------------------
DivideRegion(vtkOctreePointLocatorNode * node,int * ordering,int level)255 void vtkOctreePointLocator::DivideRegion(
256   vtkOctreePointLocatorNode *node, int*  ordering, int level)
257 {
258   if(!this->DivideTest(node->GetNumberOfPoints(), level))
259     {
260     return;
261     }
262   if(level >= this->Level)
263     {
264     this->Level = level + 1;
265     }
266 
267   node->CreateChildNodes();
268   int numberOfPoints = node->GetNumberOfPoints();
269   vtkDataSet* ds = this->GetDataSet();
270 
271   std::vector<int> points[7];
272   int  i;
273   int subOctantNumberOfPoints[8] = {0,0,0,0,0,0,0,0};
274   for(i=0;i<numberOfPoints;i++)
275     {
276     int index = node->GetSubOctantIndex(ds->GetPoint(ordering[i]), 0);
277     if(index)
278       {
279       points[index-1].push_back(ordering[i]);
280       }
281     else
282       {
283       ordering[subOctantNumberOfPoints[0]] = ordering[i];
284       }
285     subOctantNumberOfPoints[index]++;
286     }
287   int counter = 0;
288   int sizeOfInt = sizeof(int);
289   for(i=0;i<7;i++)
290     {
291     counter += subOctantNumberOfPoints[i];
292     if(!points[i].empty())
293       {
294       memcpy(ordering+counter, &(points[i][0]),
295              subOctantNumberOfPoints[i+1]*sizeOfInt);
296       }
297     }
298   counter = 0;
299   for(i=0;i<8;i++)
300     {
301     node->GetChild(i)->SetNumberOfPoints(subOctantNumberOfPoints[i]);
302     this->DivideRegion(node->GetChild(i), ordering+counter, level + 1);
303     counter += subOctantNumberOfPoints[i];
304     }
305 }
306 
307 //----------------------------------------------------------------------------
BuildLocator()308 void vtkOctreePointLocator::BuildLocator()
309 {
310   if(!this->GetDataSet())
311     {
312     vtkErrorMacro("Must set a valid data set first.");
313     }
314 
315   int numPoints = this->GetDataSet()->GetNumberOfPoints();
316 
317   if (numPoints < 1)
318     {
319     vtkErrorMacro(<< "No points to build from.");
320     return;
321     }
322 
323   if (numPoints >= VTK_INT_MAX)
324     {
325      // When point IDs are stored in an "int" instead of a vtkIdType,
326      // performance doubles.  So we store point IDs in an "int" during
327      // the calculation.  This will need to be rewritten if true 64 bit
328      // IDs are required.
329 
330     vtkErrorMacro("Intentional 64 bit error - time to rewrite code.");
331      return;
332     }
333 
334   vtkDebugMacro( << "Creating octree" );
335 
336   if ( (this->BuildTime > this->MTime)
337        && (this->BuildTime > this->DataSet->GetMTime()) )
338     {
339     return;
340     }
341   this->FreeSearchStructure();
342 
343   // Fix bounds - (1) push out a little if flat
344   // (2) pull back the x, y and z lower bounds a little bit so that
345   // points are clearly "inside" the spatial region.  Point p is
346   // "inside" region r = [r1, r2] if r1 < p <= r2.
347 
348   double bounds[6], diff[3];
349 
350   this->GetDataSet()->GetBounds(bounds);
351 
352   this->MaxWidth = 0.0;
353   int i;
354   for (i=0; i<3; i++)
355     {
356     diff[i] = bounds[2*i+1] - bounds[2*i];
357     this->MaxWidth = static_cast<float>
358       ((diff[i] > this->MaxWidth) ? diff[i] : this->MaxWidth);
359     }
360 
361   if(this->CreateCubicOctants)
362     {
363     // make the bounding box have equal length sides so that all octants
364     // will also have equal length sides
365     for(i=0;i<3;i++)
366       {
367       if(diff[i] != this->MaxWidth)
368         {
369         double delta = this->MaxWidth - diff[i];
370         bounds[2*i] -= .5*delta;
371         bounds[2*i+1] += .5*delta;
372         diff[i] =  this->MaxWidth;
373         }
374       }
375     }
376 
377   this->FudgeFactor = this->MaxWidth * 10e-6;
378 
379   double aLittle = this->MaxWidth * 10e-2;
380 
381   for (i=0; i<3; i++)
382     {
383     if (diff[i] < aLittle)         // case (1) above
384       {
385       double temp = bounds[2*i];
386       bounds[2*i]   = bounds[2*i+1] - aLittle;
387       bounds[2*i+1] = temp + aLittle;
388       }
389     else                           // case (2) above
390       {
391       bounds[2*i] -= this->FudgeFactor;
392       }
393     }
394 
395   // root node of octree - it's the whole space
396 
397   vtkOctreePointLocatorNode *node = this->Top = vtkOctreePointLocatorNode::New();
398 
399   node->SetBounds(bounds[0], bounds[1],
400                   bounds[2], bounds[3],
401                   bounds[4], bounds[5]);
402 
403   node->SetNumberOfPoints(numPoints);
404 
405   node->SetDataBounds(bounds[0], bounds[1],
406                       bounds[2], bounds[3],
407                       bounds[4], bounds[5]);
408 
409 
410   this->LocatorIds = new int [numPoints];
411   this->LocatorPoints = new float [3 * numPoints];
412 
413   if ( !this->LocatorPoints || !this->LocatorIds)
414     {
415     this->FreeSearchStructure();
416     vtkErrorMacro("vtkOctreePointLocator::BuildLocatorFromPoints - memory allocation");
417     return;
418     }
419 
420   for(i=0;i<numPoints;i++)
421     {
422     this->LocatorIds[i] = i;
423     }
424   this->DivideRegion(node, this->LocatorIds, 0);
425   // TODO: may want to directly check if there exists a point array that
426   // is of type float and directly copy that instead of dealing with
427   // all of the casts
428   vtkDataSet* ds = this->GetDataSet();
429   for(i=0;i<numPoints;i++)
430     {
431     double *pt = ds->GetPoint(this->LocatorIds[i]);
432 
433     this->LocatorPoints[i*3] = static_cast<float>(pt[0]);
434     this->LocatorPoints[i*3+1] = static_cast<float>(pt[1]);
435     this->LocatorPoints[i*3+2] = static_cast<float>(pt[2]);
436     }
437 
438   int nextLeafNodeId = 0;
439   int nextMinId = 0;
440   this->Top->ComputeOctreeNodeInformation(this->Top, nextLeafNodeId,
441                                           nextMinId, this->LocatorPoints);
442 
443   this->NumberOfLeafNodes = nextLeafNodeId;
444   int index = 0;
445   this->LeafNodeList = new vtkOctreePointLocatorNode*[this->NumberOfLeafNodes];
446   this->BuildLeafNodeList(this->Top, index);
447   this->BuildTime.Modified();
448 }
449 
450 //----------------------------------------------------------------------------
BuildLeafNodeList(vtkOctreePointLocatorNode * node,int & index)451 void vtkOctreePointLocator::BuildLeafNodeList(vtkOctreePointLocatorNode* node,
452                                               int & index)
453 {
454   if(node->GetChild(0))
455     {
456     for(int i=0;i<8;i++)
457       {
458       this->BuildLeafNodeList(node->GetChild(i), index);
459       }
460     }
461   else
462     {
463     this->LeafNodeList[index] = node;
464     index++;
465     }
466 }
467 
468 //----------------------------------------------------------------------------
FindClosestPoint(const double x[3])469 vtkIdType vtkOctreePointLocator::FindClosestPoint(const double x[3])
470 {
471   double dist2(0);
472   return this->FindClosestPoint(x[0], x[1], x[2], dist2);
473 }
474 
475 //----------------------------------------------------------------------------
FindClosestPoint(double x,double y,double z,double & dist2)476 vtkIdType vtkOctreePointLocator::FindClosestPoint(
477   double x, double y, double z, double &dist2)
478 {
479   this->BuildLocator();
480 
481   int closeId=-1;
482   vtkIdType newCloseId=-1;
483   double newDistance2 = 4 * this->MaxWidth * this->MaxWidth;
484 
485   int regionId = this->GetRegionContainingPoint(x, y, z);
486   vtkIdType closePointId = -1;
487   if (regionId < 0)
488     {
489     // This point is not inside the space divided by the octree.
490     // Find the point on the boundary that is closest to it.
491 
492     double pt[3];
493     this->Top->GetDistance2ToBoundary(x, y, z, pt, this->Top, 1);
494 
495     double *min = this->Top->GetMinBounds();
496     double *max = this->Top->GetMaxBounds();
497 
498     // GetDistance2ToBoundary will sometimes return a point *just*
499     // *barely* outside the bounds of the region.  Move that point to
500     // just barely *inside* instead.
501 
502     if (pt[0] <= min[0])
503       {
504       pt[0] = min[0] + this->FudgeFactor;
505       }
506     if (pt[1] <= min[1])
507       {
508       pt[1] = min[1] + this->FudgeFactor;
509       }
510     if (pt[2] <= min[2])
511       {
512       pt[2] = min[2] + this->FudgeFactor;
513       }
514     if (pt[0] >= max[0])
515       {
516       pt[0] = max[0] - this->FudgeFactor;
517       }
518     if (pt[1] >= max[1])
519       {
520       pt[1] = max[1] - this->FudgeFactor;
521       }
522     if (pt[2] >= max[2])
523       {
524       pt[2] = max[2] - this->FudgeFactor;
525       }
526 
527     regionId = this->GetRegionContainingPoint(pt[0], pt[1], pt[2]);
528 
529     closeId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
530 
531     closePointId = static_cast<vtkIdType>(this->LocatorIds[closeId]);
532 
533     // Check to see if neighboring regions have a closer point
534     newCloseId =  this->FindClosestPointInSphere(x, y, z,
535                                                  sqrt(dist2),        // radius
536                                                  regionId,     // skip this region
537                                                  newDistance2);// distance to closest point
538     if(newDistance2 < dist2)
539       {
540       dist2 = newDistance2;
541       closePointId = newCloseId;
542       }
543     }
544   else     // Point is inside an octree region
545     {
546     closeId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
547     closePointId = static_cast<vtkIdType>(this->LocatorIds[closeId]);
548 
549     if (dist2 > 0.0)
550       {
551       float dist2ToBoundary = static_cast<float>(
552         this->LeafNodeList[regionId]->GetDistance2ToInnerBoundary(x, y, z, this->Top));
553 
554       if (dist2ToBoundary < dist2)
555         {
556         // The closest point may be in a neighboring region
557         newCloseId = this->FindClosestPointInSphere(x, y, z,
558                                                     sqrt(dist2),        // radius
559                                                     regionId,     // skip this region
560                                                     newDistance2);
561         if(newDistance2 < dist2)
562           {
563           dist2 = newDistance2;
564           closePointId = newCloseId;
565           }
566         }
567       }
568     }
569 
570   return closePointId;
571 }
572 
573 //----------------------------------------------------------------------------
FindClosestPointWithinRadius(double radius,const double x[3],double & dist2)574 vtkIdType vtkOctreePointLocator::FindClosestPointWithinRadius(
575   double radius, const double x[3], double& dist2)
576 {
577   return this->FindClosestPointInSphere(x[0], x[1], x[2], radius, -2, dist2);
578 }
579 
580 
581 //----------------------------------------------------------------------------
FindClosestPointInRegion(int regionId,double * x,double & dist2)582 vtkIdType vtkOctreePointLocator::FindClosestPointInRegion(
583   int regionId, double *x, double &dist2)
584 {
585   return this->FindClosestPointInRegion(regionId, x[0], x[1], x[2], dist2);
586 }
587 
588 //----------------------------------------------------------------------------
FindClosestPointInRegion(int regionId,double x,double y,double z,double & dist2)589 vtkIdType vtkOctreePointLocator::FindClosestPointInRegion(
590   int regionId, double x, double y, double z, double &dist2)
591 {
592   if (!this->LocatorPoints)
593     {
594     // if the locator hasn't been built yet the regionId is garbage!
595     vtkErrorMacro("vtkOctreePointLocator::FindClosestPointInRegion - must build locator first");
596     return -1;
597     }
598   int localId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
599 
600   vtkIdType originalId = -1;
601 
602   if (localId >= 0)
603     {
604     originalId = static_cast<vtkIdType>(this->LocatorIds[localId]);
605     }
606 
607   return originalId;
608 }
609 
610 //----------------------------------------------------------------------------
_FindClosestPointInRegion(int leafNodeId,double x,double y,double z,double & dist2)611 int vtkOctreePointLocator::_FindClosestPointInRegion(
612   int leafNodeId, double x, double y, double z, double &dist2)
613 {
614   int minId=0;
615 
616   float fx = static_cast<float>(x);
617   float fy = static_cast<float>(y);
618   float fz = static_cast<float>(z);
619 
620   float minDistance2 = 4 * this->MaxWidth * this->MaxWidth;
621 
622   int idx = this->LeafNodeList[leafNodeId]->GetMinID();
623 
624   float *candidate = this->LocatorPoints + (idx * 3);
625 
626   int numPoints = this->LeafNodeList[leafNodeId]->GetNumberOfPoints();
627   for (int i=0; i < numPoints; i++)
628     {
629     float diffx = fx-candidate[0];
630     float diffy = fy-candidate[1];
631     float diffz = fz-candidate[2];
632     float dxyz = diffx*diffx + diffy*diffy + diffz*diffz;
633     if(dxyz < minDistance2)
634       {
635       minId = idx + i;
636       minDistance2 = dxyz;
637       if(dxyz == 0.0)
638         {
639         break;
640         }
641       }
642 
643     candidate += 3;
644     }
645 
646   dist2 = minDistance2;
647 
648   return minId;
649 }
650 
651 //----------------------------------------------------------------------------
FindClosestPointInSphere(double x,double y,double z,double radius,int skipRegion,double & dist2)652 int vtkOctreePointLocator::FindClosestPointInSphere(
653   double x, double y, double z, double radius, int skipRegion, double &dist2)
654 {
655   this->BuildLocator();
656 
657   dist2 = radius * radius * 1.0001;
658   int localCloseId = -1;
659 
660   std::stack<vtkOctreePointLocatorNode*> regions;
661   regions.push(this->Top);
662   while(!regions.empty())
663     {
664     vtkOctreePointLocatorNode* region = regions.top();
665     regions.pop();
666     if(region->GetChild(0))
667       {
668       for(int i=0;i<8;i++)
669         {
670         vtkOctreePointLocatorNode* child = region->GetChild(i);
671         // must check for leaf nodes here in case skipRegion == -1
672         // since all non-leaf nodes have Id = -1.
673         if(child->GetID() != skipRegion &&
674            (child->GetDistance2ToBoundary(x, y, z, this->Top, 1) < dist2 ||
675             child->ContainsPoint(x, y, z, 0)))
676           {
677           regions.push(child);
678           }
679         }
680       }
681     else
682       {
683       double tempDist2 = dist2;
684       int tempId =
685         this->_FindClosestPointInRegion(region->GetID(), x, y, z, tempDist2);
686 
687       if (tempDist2 < dist2)
688         {
689         dist2 = tempDist2;
690         localCloseId = tempId;
691         }
692       }
693     }
694 
695   vtkIdType originalId = -1;
696   if(localCloseId >= 0 && dist2 <= radius*radius)
697     {
698     originalId = static_cast<vtkIdType>(this->LocatorIds[localCloseId]);
699     }
700   return originalId;
701 }
702 
703 //----------------------------------------------------------------------------
FindPointsWithinRadius(double radius,const double x[3],vtkIdList * result)704 void vtkOctreePointLocator::FindPointsWithinRadius(
705   double radius, const double x[3], vtkIdList* result)
706 {
707   result->Reset();
708   this->BuildLocator();
709   // don't forget to square the radius
710   this->FindPointsWithinRadius(this->Top, radius*radius, x, result);
711 }
712 
713 //----------------------------------------------------------------------------
FindPointsWithinRadius(vtkOctreePointLocatorNode * node,double radiusSquared,const double x[3],vtkIdList * result)714 void vtkOctreePointLocator::FindPointsWithinRadius(
715   vtkOctreePointLocatorNode* node, double radiusSquared, const double x[3],
716   vtkIdList* result)
717 {
718   double b[6];
719   node->GetBounds(b);
720 
721   double mindist2 = 0; // distance to closest vertex of BB
722   double maxdist2 = 0; // distance to furthest vertex of BB
723   // x-dir
724   if(x[0] < b[0])
725     {
726     mindist2 = (b[0]-x[0])*(b[0]-x[0]);
727     maxdist2 = (b[1]-x[0])*(b[1]-x[0]);
728     }
729   else if(x[0] > b[1])
730     {
731     mindist2 = (b[1]-x[0])*(b[1]-x[0]);
732     maxdist2 = (b[0]-x[0])*(b[0]-x[0]);
733     }
734   else if((b[1]-x[0]) > (x[0]-b[0]))
735     {
736     maxdist2 = (b[1]-x[0])*(b[1]-x[0]);
737     }
738   else
739     {
740     maxdist2 = (b[0]-x[0])*(b[0]-x[0]);
741     }
742   // y-dir
743   if(x[1] < b[2])
744     {
745     mindist2 += (b[2]-x[1])*(b[2]-x[1]);
746     maxdist2 += (b[3]-x[1])*(b[3]-x[1]);
747     }
748   else if(x[1] > b[3])
749     {
750     mindist2 += (b[3]-x[1])*(b[3]-x[1]);
751     maxdist2 += (b[2]-x[1])*(b[2]-x[1]);
752     }
753   else if((b[3]-x[1]) > (x[1]-b[2]))
754     {
755     maxdist2 += (b[3]-x[1])*(b[3]-x[1]);
756     }
757   else
758     {
759     maxdist2 += (b[2]-x[1])*(b[2]-x[1]);
760     }
761   // z-dir
762   if(x[2] < b[4])
763     {
764     mindist2 += (b[4]-x[2])*(b[4]-x[2]);
765     maxdist2 += (b[5]-x[2])*(b[5]-x[2]);
766     }
767   else if(x[2] > b[5])
768     {
769     mindist2 += (b[5]-x[2])*(b[5]-x[2]);
770     maxdist2 += (b[4]-x[2])*(b[4]-x[2]);
771     }
772   else if((b[5]-x[2]) > (x[2]-b[4]))
773     {
774     maxdist2 += (b[5]-x[2])*(b[5]-x[2]);
775     }
776   else
777     {
778     maxdist2 += (x[2]-b[4])*(x[2]-b[4]);
779     }
780 
781   if(mindist2 > radiusSquared)
782     {
783     // non-intersecting
784     return;
785     }
786 
787   if(maxdist2 <= radiusSquared)
788     {
789     // sphere contains BB
790     this->AddAllPointsInRegion(node, result);
791     return;
792     }
793 
794   // partial intersection of sphere & BB
795   if (node->GetChild(0) == NULL)
796     {
797     //int regionID = node->GetID();
798     int regionLoc = node->GetMinID();
799     float* pt = this->LocatorPoints + (regionLoc * 3);
800     vtkIdType numPoints = node->GetNumberOfPoints();
801     for (vtkIdType i = 0; i < numPoints; i++)
802       {
803       double dist2 = (pt[0]-x[0])*(pt[0]-x[0])+
804         (pt[1]-x[1])*(pt[1]-x[1])+(pt[2]-x[2])*(pt[2]-x[2]);
805       if(dist2 <= radiusSquared)
806         {
807         vtkIdType ptId =
808           static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
809         result->InsertNextId(ptId);
810         }
811       pt += 3;
812       }
813     }
814   else
815     {
816     for(int i=0;i<8;i++)
817       {
818       this->FindPointsWithinRadius(
819         node->GetChild(i), radiusSquared, x, result);
820       }
821     }
822 }
823 
824 //----------------------------------------------------------------------------
FindClosestNPoints(int N,const double x[3],vtkIdList * result)825 void vtkOctreePointLocator::FindClosestNPoints(int N, const double x[3],
826                                                vtkIdList* result)
827 {
828   result->Reset();
829   if(N<=0)
830     {
831     return;
832     }
833   this->BuildLocator();
834 
835   int numTotalPoints = this->Top->GetNumberOfPoints();
836   if(numTotalPoints < N)
837     {
838     vtkWarningMacro("Number of requested points is greater than total number of points in OctreePointLocator");
839     N = numTotalPoints;
840     }
841   result->SetNumberOfIds(N);
842 
843   // now we want to go about finding a region that contains at least N points
844   // but not many more -- hopefully the region contains X as well but we
845   // can't depend on that
846   vtkOctreePointLocatorNode* node = this->Top;
847   vtkOctreePointLocatorNode* startingNode = 0;
848   if(!node->ContainsPoint(x[0], x[1], x[2], 0))
849     {
850     // point is not in the region
851     int numPoints = node->GetNumberOfPoints();
852     vtkOctreePointLocatorNode* prevNode = node;
853     while(node->GetChild(0) && numPoints > N)
854       {
855       prevNode = node;
856       vtkOctreePointLocatorNode* nextNode = node->GetChild(0);
857       double minDist2 =
858         nextNode->GetDistance2ToBoundary(x[0], x[1], x[2], this->Top, 1);
859       for(int i=1;i<8;i++)
860         {
861         double dist2 = node->GetChild(i)->GetDistance2ToBoundary(
862           x[0], x[1], x[2], this->Top, 1);
863         if(dist2 < minDist2)
864           {
865           nextNode = node->GetChild(i);
866           minDist2 = dist2;
867           }
868         }
869       node = nextNode;
870       numPoints = node->GetNumberOfPoints();
871       }
872     if(numPoints < N)
873       {
874       startingNode = prevNode;
875       }
876     else
877       {
878       startingNode = node;
879       }
880     }
881   else
882     {
883     int numPoints = node->GetNumberOfPoints();
884     vtkOctreePointLocatorNode* prevNode = node;
885     while(node->GetChild(0) && numPoints > N)
886       {
887       prevNode = node;
888       int i;
889       for(i=0;i<8;i++)
890         {
891         if(node->GetChild(i)->ContainsPoint(x[0], x[1], x[2], 0))
892           {
893           node = node->GetChild(i);
894           break;
895           }
896         }
897       numPoints = node->GetNumberOfPoints();
898       }
899     if(numPoints < N)
900       {
901       startingNode = prevNode;
902       }
903     else
904       {
905       startingNode = node;
906       }
907     }
908 
909   // now that we have a starting region, go through its points
910   // and order them
911   int regionId = startingNode->GetID();
912   int numPoints = startingNode->GetNumberOfPoints();
913   int where = startingNode->GetMinID();
914   if(regionId < 0) // if not a leaf node
915     {
916     vtkOctreePointLocatorNode* parentOfNext = startingNode->GetChild(0);
917     vtkOctreePointLocatorNode* next = parentOfNext->GetChild(0);
918     while(next)
919       {
920       parentOfNext = next;
921       next = next->GetChild(0);
922       }
923     where = parentOfNext->GetMinID();
924     }
925   int *ids = this->LocatorIds + where;
926   float* pt = this->LocatorPoints + (where*3);
927   float xfloat[3] = {static_cast<float>(x[0]), static_cast<float>(x[1]),
928                      static_cast<float>(x[2])};
929   OrderPoints orderedPoints(N);
930   for (int i=0; i<numPoints; i++)
931     {
932     float dist2 = vtkMath::Distance2BetweenPoints(xfloat, pt);
933     orderedPoints.InsertPoint(dist2, ids[i]);
934     pt += 3;
935     }
936 
937   // to finish up we have to check other regions for
938   // closer points
939   float largestDist2 = orderedPoints.GetLargestDist2();
940   double bounds[6];
941   node = this->Top;
942   std::queue<vtkOctreePointLocatorNode*> nodesToBeSearched;
943   nodesToBeSearched.push(node);
944   while(!nodesToBeSearched.empty())
945     {
946     node = nodesToBeSearched.front();
947     nodesToBeSearched.pop();
948     if(node == startingNode)
949       {
950       continue;
951       }
952     if(node->GetChild(0))
953       {
954       for(int j=0;j<8;j++)
955         {
956         vtkOctreePointLocatorNode* child = node->GetChild(j);
957         child->GetDataBounds(bounds);
958         double delta[3] = {0,0,0};
959         if(vtkMath::PointIsWithinBounds(const_cast<double*>(x), bounds, delta) == 1 ||
960            child->GetDistance2ToBoundary(x[0], x[1], x[2], 0, 1) < largestDist2)
961           {
962           nodesToBeSearched.push(child);
963           }
964         }
965       }
966     else if(node->GetDistance2ToBoundary(x[0], x[1], x[2], this->Top, 1) < largestDist2)
967       {
968       numPoints = node->GetNumberOfPoints();
969       where = node->GetMinID();
970       ids = this->LocatorIds + where;
971       pt = this->LocatorPoints + (where*3);
972       for (int i=0; i<numPoints; i++)
973         {
974         float dist2 = vtkMath::Distance2BetweenPoints(xfloat, pt);
975         orderedPoints.InsertPoint(dist2, ids[i]);
976         pt += 3;
977         }
978       largestDist2 = orderedPoints.GetLargestDist2();
979       }
980     }
981   orderedPoints.GetSortedIds(result);
982 }
983 
984 //----------------------------------------------------------------------------
GetPointsInRegion(int leafNodeId)985 vtkIdTypeArray *vtkOctreePointLocator::GetPointsInRegion(int leafNodeId)
986 {
987   if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
988     {
989     vtkErrorMacro("vtkOctreePointLocator::GetPointsInRegion invalid leaf node ID");
990     return NULL;
991     }
992 
993   if (!this->LocatorIds)
994     {
995     // don't build locator since leafNodeId is probably garbage anyways
996     vtkErrorMacro("vtkOctreePointLocator::GetPointsInRegion build locator first");
997     return NULL;
998     }
999 
1000   int numPoints = this->LeafNodeList[leafNodeId]->GetNumberOfPoints();
1001   int where = this->LeafNodeList[leafNodeId]->GetMinID();
1002 
1003   vtkIdTypeArray *ptIds = vtkIdTypeArray::New();
1004   ptIds->SetNumberOfValues(numPoints);
1005 
1006   int *ids = this->LocatorIds + where;
1007 
1008   for (int i=0; i<numPoints; i++)
1009     {
1010     ptIds->SetValue(i, ids[i]);
1011     }
1012 
1013   return ptIds;
1014 }
1015 
1016 //----------------------------------------------------------------------------
FreeSearchStructure()1017 void vtkOctreePointLocator::FreeSearchStructure()
1018 {
1019   if (this->Top)
1020     {
1021     vtkOctreePointLocator::DeleteAllDescendants(this->Top);
1022     this->Top->Delete();
1023     this->Top = NULL;
1024     }
1025   delete [] this->LeafNodeList;
1026   this->LeafNodeList = NULL;
1027 
1028   this->NumberOfLeafNodes = 0;
1029 
1030   delete [] this->LocatorPoints;
1031   this->LocatorPoints = NULL;
1032 
1033   delete [] this->LocatorIds;
1034   this->LocatorIds = NULL;
1035 }
1036 
1037 //----------------------------------------------------------------------------
1038 // build PolyData representation of all spacial regions------------
1039 //
GenerateRepresentation(int level,vtkPolyData * pd)1040 void vtkOctreePointLocator::GenerateRepresentation(int level,
1041                                                    vtkPolyData *pd)
1042 {
1043   if ( this->Top == NULL )
1044     {
1045     vtkErrorMacro("vtkOctreePointLocator::GenerateRepresentation no tree");
1046     return;
1047     }
1048 
1049   std::list<vtkOctreePointLocatorNode*> nodesAtLevel;
1050   // queue of nodes to be examined and what level each one is at
1051   std::queue<std::pair<vtkOctreePointLocatorNode*, int> > testNodes;
1052   testNodes.push(std::make_pair(this->Top, 0));
1053   while(!testNodes.empty())
1054     {
1055     vtkOctreePointLocatorNode* node = testNodes.front().first;
1056     int nodeLevel = testNodes.front().second;
1057     testNodes.pop();
1058     if(nodeLevel == level)
1059       {
1060       nodesAtLevel.push_back(node);
1061       }
1062     else if(node->GetChild(0))
1063       {
1064       for(int i=0;i<8;i++)
1065         {
1066         testNodes.push(std::make_pair(node->GetChild(i), nodeLevel+1));
1067         }
1068       }
1069     }
1070 
1071   int npoints = 8 * static_cast<int>(nodesAtLevel.size());
1072   int npolys  = 6 * static_cast<int>(nodesAtLevel.size());
1073 
1074   vtkPoints* pts = vtkPoints::New();
1075   pts->Allocate(npoints);
1076   vtkCellArray* polys = vtkCellArray::New();
1077   polys->Allocate(npolys);
1078 
1079   for(std::list<vtkOctreePointLocatorNode*>::iterator it=nodesAtLevel.begin();
1080       it!=nodesAtLevel.end();it++)
1081     {
1082     vtkOctreePointLocator::AddPolys(*it, pts, polys);
1083     }
1084 
1085   pd->SetPoints(pts);
1086   pts->Delete();
1087   pd->SetPolys(polys);
1088   polys->Delete();
1089   pd->Squeeze();
1090 }
1091 
1092 //----------------------------------------------------------------------------
AddPolys(vtkOctreePointLocatorNode * node,vtkPoints * pts,vtkCellArray * polys)1093 void vtkOctreePointLocator::AddPolys(vtkOctreePointLocatorNode* node,
1094                                      vtkPoints* pts, vtkCellArray * polys)
1095 {
1096   vtkIdType ids[8];
1097   vtkIdType idList[4];
1098   double     x[3];
1099 
1100   double* min = node->GetMinBounds();
1101   double* max = node->GetMaxBounds();
1102 
1103   x[0]  = min[0]; x[1]  = max[1]; x[2]  = min[2];
1104   ids[0] = pts->InsertNextPoint(x);
1105 
1106   x[0]  = max[0]; x[1]  = max[1]; x[2]  = min[2];
1107   ids[1] = pts->InsertNextPoint(x);
1108 
1109   x[0]  = max[0]; x[1]  = max[1]; x[2]  = max[2];
1110   ids[2] = pts->InsertNextPoint(x);
1111 
1112   x[0]  = min[0]; x[1]  = max[1]; x[2]  = max[2];
1113   ids[3] = pts->InsertNextPoint(x);
1114 
1115   x[0]  = min[0]; x[1]  = min[1]; x[2]  = min[2];
1116   ids[4] = pts->InsertNextPoint(x);
1117 
1118   x[0]  = max[0]; x[1]  = min[1]; x[2]  = min[2];
1119   ids[5] = pts->InsertNextPoint(x);
1120 
1121   x[0]  = max[0]; x[1]  = min[1]; x[2]  = max[2];
1122   ids[6] = pts->InsertNextPoint(x);
1123 
1124   x[0]  = min[0]; x[1]  = min[1]; x[2]  = max[2];
1125   ids[7] = pts->InsertNextPoint(x);
1126 
1127   idList[0] = ids[0]; idList[1] = ids[1]; idList[2] = ids[2]; idList[3] = ids[3];
1128   polys->InsertNextCell(4, idList);
1129 
1130   idList[0] = ids[1]; idList[1] = ids[5]; idList[2] = ids[6]; idList[3] = ids[2];
1131   polys->InsertNextCell(4, idList);
1132 
1133   idList[0] = ids[5]; idList[1] = ids[4]; idList[2] = ids[7]; idList[3] = ids[6];
1134   polys->InsertNextCell(4, idList);
1135 
1136   idList[0] = ids[4]; idList[1] = ids[0]; idList[2] = ids[3]; idList[3] = ids[7];
1137   polys->InsertNextCell(4, idList);
1138 
1139   idList[0] = ids[3]; idList[1] = ids[2]; idList[2] = ids[6]; idList[3] = ids[7];
1140   polys->InsertNextCell(4, idList);
1141 
1142   idList[0] = ids[1]; idList[1] = ids[0]; idList[2] = ids[4]; idList[3] = ids[5];
1143   polys->InsertNextCell(4, idList);
1144 }
1145 
1146 //----------------------------------------------------------------------------
FindRegion(vtkOctreePointLocatorNode * node,float x,float y,float z)1147 int vtkOctreePointLocator::FindRegion(vtkOctreePointLocatorNode *node, float x,
1148                                       float y, float z)
1149 {
1150   return vtkOctreePointLocator::FindRegion(
1151     node, static_cast<double>(x),static_cast<double>(y),static_cast<double>(z));
1152 }
1153 
1154 //----------------------------------------------------------------------------
FindRegion(vtkOctreePointLocatorNode * node,double x,double y,double z)1155 int vtkOctreePointLocator::FindRegion(vtkOctreePointLocatorNode *node, double x,
1156                                       double y, double z)
1157 {
1158   if (!node->ContainsPoint(x, y, z, 0))
1159     {
1160     return -1; // no region is found
1161     }
1162 
1163   if (node->GetChild(0) == NULL)
1164     {
1165     return node->GetID();
1166     }
1167 
1168   int regionId = -1;
1169   for(int i=0;i<8;i++)
1170     {
1171     regionId =
1172       vtkOctreePointLocator::FindRegion(node->GetChild(i), x, y, z);
1173     if(regionId >=0 )
1174       {
1175       return regionId;
1176       }
1177     }
1178 
1179   return -1; // no region is found
1180 }
1181 
1182 //----------------------------------------------------------------------------
GetRegionContainingPoint(double x,double y,double z)1183 int vtkOctreePointLocator::GetRegionContainingPoint(double x, double y,
1184                                                     double z)
1185 {
1186   return vtkOctreePointLocator::FindRegion(this->Top, x, y, z);
1187 }
1188 
1189 //----------------------------------------------------------------------------
FindPointsInArea(double * area,vtkIdTypeArray * ids,bool clearArray)1190 void vtkOctreePointLocator::FindPointsInArea(
1191   double* area, vtkIdTypeArray* ids, bool clearArray)
1192 {
1193   if (clearArray)
1194     {
1195     ids->Reset();
1196     }
1197   this->BuildLocator();
1198   this->FindPointsInArea(this->Top, area, ids);
1199 }
1200 
1201 //----------------------------------------------------------------------------
FindPointsInArea(vtkOctreePointLocatorNode * node,double * area,vtkIdTypeArray * ids)1202 void vtkOctreePointLocator::FindPointsInArea(
1203   vtkOctreePointLocatorNode* node, double* area, vtkIdTypeArray* ids)
1204 {
1205   double b[6];
1206   node->GetBounds(b);
1207 
1208   if (b[0] > area[1] || b[1] < area[0] ||
1209     b[2] > area[3] || b[3] < area[2] ||
1210     b[4] > area[5] || b[5] < area[4])
1211     {
1212     return; // no intersection
1213     }
1214 
1215   bool contains = false;
1216   if (area[0] <= b[0] && b[1] <= area[1] &&
1217     area[2] <= b[2] && b[3] <= area[3] &&
1218     area[4] <= b[4] && b[5] <= area[5])
1219     {
1220     contains = true;
1221     }
1222 
1223   if (contains)
1224     {
1225     this->AddAllPointsInRegion(node, ids);
1226     }
1227   else // intersects
1228     {
1229     if (node->GetChild(0) == NULL)
1230       {
1231       //int regionID = node->GetID();
1232       int regionLoc = node->GetMinID();
1233       float* pt = this->LocatorPoints + (regionLoc * 3);
1234       vtkIdType numPoints = node->GetNumberOfPoints();
1235       for (vtkIdType i = 0; i < numPoints; i++)
1236         {
1237         if (area[0] <= pt[0] && pt[0] <= area[1] &&
1238           area[2] <= pt[1] && pt[1] <= area[3] &&
1239           area[4] <= pt[2] && pt[2] <= area[5])
1240           {
1241           vtkIdType ptId =
1242             static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
1243           ids->InsertNextValue(ptId);
1244           }
1245         pt += 3;
1246         }
1247       }
1248     else
1249       {
1250       for(int i=0;i<8;i++)
1251         {
1252         this->FindPointsInArea(node->GetChild(i), area, ids);
1253         }
1254       }
1255     }
1256 }
1257 
1258 //----------------------------------------------------------------------------
AddAllPointsInRegion(vtkOctreePointLocatorNode * node,vtkIdTypeArray * ids)1259 void vtkOctreePointLocator::AddAllPointsInRegion(vtkOctreePointLocatorNode* node,
1260                                                  vtkIdTypeArray* ids)
1261 {
1262   int regionLoc = node->GetMinID();
1263   vtkIdType numPoints = node->GetNumberOfPoints();
1264   for (vtkIdType i = 0; i < numPoints; i++)
1265     {
1266     vtkIdType ptId = static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
1267     ids->InsertNextValue(ptId);
1268     }
1269 }
1270 
1271 //----------------------------------------------------------------------------
AddAllPointsInRegion(vtkOctreePointLocatorNode * node,vtkIdList * ids)1272 void vtkOctreePointLocator::AddAllPointsInRegion(vtkOctreePointLocatorNode* node,
1273                                                  vtkIdList* ids)
1274 {
1275   int regionLoc = node->GetMinID();
1276   vtkIdType numPoints = node->GetNumberOfPoints();
1277   for (vtkIdType i = 0; i < numPoints; i++)
1278     {
1279     vtkIdType ptId = static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
1280     ids->InsertNextId(ptId);
1281     }
1282 }
1283 
1284 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1285 void vtkOctreePointLocator::PrintSelf(ostream& os, vtkIndent indent)
1286 {
1287   this->Superclass::PrintSelf(os,indent);
1288 
1289   os << indent << "MaximumPointsPerRegion: " <<
1290     this->MaximumPointsPerRegion << endl;
1291   os << indent << "NumberOfLeafNodes: " << this->NumberOfLeafNodes << endl;
1292   os << indent << "Top: " << this->Top << endl;
1293   os << indent << "LeafNodeList: " << this->LeafNodeList << endl;
1294   os << indent << "LocatorPoints: " << this->LocatorPoints << endl;
1295   os << indent << "NumberOfLocatorPoints: "
1296      << this->NumberOfLocatorPoints << endl;
1297   os << indent << "LocatorIds: " << this->LocatorIds << endl;
1298   os << indent << "FudgeFactor: " << this->FudgeFactor << endl;
1299   os << indent << "MaxWidth: " << this->MaxWidth << endl;
1300   os << indent << "CreateCubicOctants: " << this->CreateCubicOctants << endl;
1301 }
1302