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