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