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