You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1302 lines
36 KiB
C++
1302 lines
36 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkOctreePointLocator.cxx
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
/*----------------------------------------------------------------------------
|
|
Copyright (c) Sandia Corporation
|
|
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
#include "vtkOctreePointLocator.h"
|
|
|
|
#include "vtkCellArray.h"
|
|
#include "vtkCommand.h"
|
|
#include "vtkDataSet.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkIdList.h"
|
|
#include "vtkIdTypeArray.h"
|
|
#include "vtkIntArray.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkOctreePointLocatorNode.h"
|
|
#include "vtkPoints.h"
|
|
#include "vtkPointSet.h"
|
|
#include "vtkPolyData.h"
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <queue>
|
|
#include <stack>
|
|
#include <vector>
|
|
|
|
vtkStandardNewMacro(vtkOctreePointLocator);
|
|
|
|
// helper class for ordering the points in
|
|
// vtkOctreePointLocator::FindClosestNPoints()
|
|
namespace
|
|
{
|
|
class OrderPoints
|
|
{
|
|
public:
|
|
OrderPoints(int numDesiredPoints)
|
|
{
|
|
this->NumDesiredPoints = numDesiredPoints;
|
|
this->NumPoints = 0;
|
|
this->LargestDist2 = VTK_FLOAT_MAX;
|
|
}
|
|
|
|
void InsertPoint(float dist2, vtkIdType id)
|
|
{
|
|
if(dist2 <= this->LargestDist2 ||
|
|
this->NumPoints < this->NumDesiredPoints)
|
|
{
|
|
std::map<float, std::list<vtkIdType> >::iterator it=
|
|
this->dist2ToIds.find(dist2);
|
|
this->NumPoints++;
|
|
if(it == this->dist2ToIds.end())
|
|
{
|
|
std::list<vtkIdType> idset;
|
|
idset.push_back(id);
|
|
this->dist2ToIds[dist2] = idset;
|
|
}
|
|
else
|
|
{
|
|
it->second.push_back(id);
|
|
}
|
|
if(this->NumPoints > this->NumDesiredPoints)
|
|
{
|
|
it=this->dist2ToIds.end();
|
|
it--;
|
|
if((this->NumPoints-it->second.size()) > this->NumDesiredPoints)
|
|
{
|
|
this->NumPoints -= it->second.size();
|
|
std::map<float, std::list<vtkIdType> >::iterator it2 = it;
|
|
it2--;
|
|
this->LargestDist2 = it2->first;
|
|
this->dist2ToIds.erase(it);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void GetSortedIds(vtkIdList* ids)
|
|
{
|
|
ids->Reset();
|
|
vtkIdType numIds = (this->NumDesiredPoints < this->NumPoints)
|
|
? this->NumDesiredPoints : this->NumPoints;
|
|
ids->SetNumberOfIds(numIds);
|
|
vtkIdType counter = 0;
|
|
std::map<float, std::list<vtkIdType> >::iterator it=
|
|
this->dist2ToIds.begin();
|
|
while(counter < numIds && it!=this->dist2ToIds.end())
|
|
{
|
|
std::list<vtkIdType>::iterator lit=it->second.begin();
|
|
while(counter < numIds && lit!=it->second.end())
|
|
{
|
|
ids->InsertId(counter, *lit);
|
|
counter++;
|
|
lit++;
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
float GetLargestDist2()
|
|
{
|
|
return this->LargestDist2;
|
|
}
|
|
|
|
private:
|
|
size_t NumDesiredPoints, NumPoints;
|
|
float LargestDist2;
|
|
// map from dist^2 to a list of ids
|
|
std::map<float, std::list<vtkIdType> > dist2ToIds;
|
|
};
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkOctreePointLocator::vtkOctreePointLocator()
|
|
{
|
|
this->FudgeFactor = 0;
|
|
this->MaxWidth = 0.0;
|
|
this->MaxLevel = 20;
|
|
this->MaximumPointsPerRegion = 100;
|
|
this->Level = 0;
|
|
this->Top = NULL;
|
|
this->NumberOfLocatorPoints = 0;
|
|
this->LocatorPoints = NULL;
|
|
this->LocatorIds = NULL;
|
|
this->LeafNodeList = NULL;
|
|
this->CreateCubicOctants = 1;
|
|
this->NumberOfLeafNodes = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::DeleteAllDescendants(
|
|
vtkOctreePointLocatorNode *octant)
|
|
{
|
|
if(octant->GetChild(0))
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
vtkOctreePointLocatorNode* child = octant->GetChild(i);
|
|
vtkOctreePointLocator::DeleteAllDescendants(child);
|
|
}
|
|
octant->DeleteChildNodes();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkOctreePointLocator::~vtkOctreePointLocator()
|
|
{
|
|
this->FreeSearchStructure();
|
|
|
|
delete []this->LocatorPoints;
|
|
this->LocatorPoints = 0;
|
|
|
|
delete []this->LocatorIds;
|
|
this->LocatorIds = 0;
|
|
|
|
delete []this->LeafNodeList;
|
|
this->LeafNodeList = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::GetBounds(double *bounds)
|
|
{
|
|
if (this->Top)
|
|
{
|
|
this->Top->GetBounds(bounds);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double* vtkOctreePointLocator::GetBounds()
|
|
{
|
|
double* bounds = vtkAbstractPointLocator::GetBounds();
|
|
if (this->Top)
|
|
{
|
|
this->Top->GetBounds(bounds);
|
|
}
|
|
return bounds;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::GetRegionBounds(int leafNodeId,
|
|
double bounds[6])
|
|
{
|
|
if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
|
|
{
|
|
vtkErrorMacro("Invalid region.");
|
|
return;
|
|
}
|
|
|
|
vtkOctreePointLocatorNode *node = this->LeafNodeList[leafNodeId];
|
|
|
|
node->GetBounds(bounds);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::GetRegionDataBounds(int leafNodeId,
|
|
double bounds[6])
|
|
{
|
|
if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
|
|
{
|
|
vtkErrorMacro("Invalid region.");
|
|
return;
|
|
}
|
|
|
|
vtkOctreePointLocatorNode *node = this->LeafNodeList[leafNodeId];
|
|
|
|
node->GetDataBounds(bounds);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::SetDataBoundsToSpatialBounds(
|
|
vtkOctreePointLocatorNode *octant)
|
|
{
|
|
octant->SetMinDataBounds(octant->GetMinBounds());
|
|
octant->SetMaxDataBounds(octant->GetMaxBounds());
|
|
|
|
if (octant->GetChild(0))
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
vtkOctreePointLocator::SetDataBoundsToSpatialBounds(octant->GetChild(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::DivideTest(int size, int level)
|
|
{
|
|
if (level >= this->MaxLevel)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if(size > this->GetMaximumPointsPerRegion())
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::DivideRegion(
|
|
vtkOctreePointLocatorNode *node, int* ordering, int level)
|
|
{
|
|
if(!this->DivideTest(node->GetNumberOfPoints(), level))
|
|
{
|
|
return;
|
|
}
|
|
if(level >= this->Level)
|
|
{
|
|
this->Level = level + 1;
|
|
}
|
|
|
|
node->CreateChildNodes();
|
|
int numberOfPoints = node->GetNumberOfPoints();
|
|
vtkDataSet* ds = this->GetDataSet();
|
|
|
|
std::vector<int> points[7];
|
|
int i;
|
|
int subOctantNumberOfPoints[8] = {0,0,0,0,0,0,0,0};
|
|
for(i=0;i<numberOfPoints;i++)
|
|
{
|
|
int index = node->GetSubOctantIndex(ds->GetPoint(ordering[i]), 0);
|
|
if(index)
|
|
{
|
|
points[index-1].push_back(ordering[i]);
|
|
}
|
|
else
|
|
{
|
|
ordering[subOctantNumberOfPoints[0]] = ordering[i];
|
|
}
|
|
subOctantNumberOfPoints[index]++;
|
|
}
|
|
int counter = 0;
|
|
int sizeOfInt = sizeof(int);
|
|
for(i=0;i<7;i++)
|
|
{
|
|
counter += subOctantNumberOfPoints[i];
|
|
if(!points[i].empty())
|
|
{
|
|
memcpy(ordering+counter, &(points[i][0]),
|
|
subOctantNumberOfPoints[i+1]*sizeOfInt);
|
|
}
|
|
}
|
|
counter = 0;
|
|
for(i=0;i<8;i++)
|
|
{
|
|
node->GetChild(i)->SetNumberOfPoints(subOctantNumberOfPoints[i]);
|
|
this->DivideRegion(node->GetChild(i), ordering+counter, level + 1);
|
|
counter += subOctantNumberOfPoints[i];
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::BuildLocator()
|
|
{
|
|
if(!this->GetDataSet())
|
|
{
|
|
vtkErrorMacro("Must set a valid data set first.");
|
|
}
|
|
|
|
int numPoints = this->GetDataSet()->GetNumberOfPoints();
|
|
|
|
if (numPoints < 1)
|
|
{
|
|
vtkErrorMacro(<< "No points to build from.");
|
|
return;
|
|
}
|
|
|
|
if (numPoints >= VTK_INT_MAX)
|
|
{
|
|
// When point IDs are stored in an "int" instead of a vtkIdType,
|
|
// performance doubles. So we store point IDs in an "int" during
|
|
// the calculation. This will need to be rewritten if true 64 bit
|
|
// IDs are required.
|
|
|
|
vtkErrorMacro("Intentional 64 bit error - time to rewrite code.");
|
|
return;
|
|
}
|
|
|
|
vtkDebugMacro( << "Creating octree" );
|
|
|
|
if ( (this->BuildTime > this->MTime)
|
|
&& (this->BuildTime > this->DataSet->GetMTime()) )
|
|
{
|
|
return;
|
|
}
|
|
this->FreeSearchStructure();
|
|
|
|
// Fix bounds - (1) push out a little if flat
|
|
// (2) pull back the x, y and z lower bounds a little bit so that
|
|
// points are clearly "inside" the spatial region. Point p is
|
|
// "inside" region r = [r1, r2] if r1 < p <= r2.
|
|
|
|
double bounds[6], diff[3];
|
|
|
|
this->GetDataSet()->GetBounds(bounds);
|
|
|
|
this->MaxWidth = 0.0;
|
|
int i;
|
|
for (i=0; i<3; i++)
|
|
{
|
|
diff[i] = bounds[2*i+1] - bounds[2*i];
|
|
this->MaxWidth = static_cast<float>
|
|
((diff[i] > this->MaxWidth) ? diff[i] : this->MaxWidth);
|
|
}
|
|
|
|
if(this->CreateCubicOctants)
|
|
{
|
|
// make the bounding box have equal length sides so that all octants
|
|
// will also have equal length sides
|
|
for(i=0;i<3;i++)
|
|
{
|
|
if(diff[i] != this->MaxWidth)
|
|
{
|
|
double delta = this->MaxWidth - diff[i];
|
|
bounds[2*i] -= .5*delta;
|
|
bounds[2*i+1] += .5*delta;
|
|
diff[i] = this->MaxWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
this->FudgeFactor = this->MaxWidth * 10e-6;
|
|
|
|
double aLittle = this->MaxWidth * 10e-2;
|
|
|
|
for (i=0; i<3; i++)
|
|
{
|
|
if (diff[i] < aLittle) // case (1) above
|
|
{
|
|
double temp = bounds[2*i];
|
|
bounds[2*i] = bounds[2*i+1] - aLittle;
|
|
bounds[2*i+1] = temp + aLittle;
|
|
}
|
|
else // case (2) above
|
|
{
|
|
bounds[2*i] -= this->FudgeFactor;
|
|
}
|
|
}
|
|
|
|
// root node of octree - it's the whole space
|
|
|
|
vtkOctreePointLocatorNode *node = this->Top = vtkOctreePointLocatorNode::New();
|
|
|
|
node->SetBounds(bounds[0], bounds[1],
|
|
bounds[2], bounds[3],
|
|
bounds[4], bounds[5]);
|
|
|
|
node->SetNumberOfPoints(numPoints);
|
|
|
|
node->SetDataBounds(bounds[0], bounds[1],
|
|
bounds[2], bounds[3],
|
|
bounds[4], bounds[5]);
|
|
|
|
|
|
this->LocatorIds = new int [numPoints];
|
|
this->LocatorPoints = new float [3 * numPoints];
|
|
|
|
if ( !this->LocatorPoints || !this->LocatorIds)
|
|
{
|
|
this->FreeSearchStructure();
|
|
vtkErrorMacro("vtkOctreePointLocator::BuildLocatorFromPoints - memory allocation");
|
|
return;
|
|
}
|
|
|
|
for(i=0;i<numPoints;i++)
|
|
{
|
|
this->LocatorIds[i] = i;
|
|
}
|
|
this->DivideRegion(node, this->LocatorIds, 0);
|
|
// TODO: may want to directly check if there exists a point array that
|
|
// is of type float and directly copy that instead of dealing with
|
|
// all of the casts
|
|
vtkDataSet* ds = this->GetDataSet();
|
|
for(i=0;i<numPoints;i++)
|
|
{
|
|
double *pt = ds->GetPoint(this->LocatorIds[i]);
|
|
|
|
this->LocatorPoints[i*3] = static_cast<float>(pt[0]);
|
|
this->LocatorPoints[i*3+1] = static_cast<float>(pt[1]);
|
|
this->LocatorPoints[i*3+2] = static_cast<float>(pt[2]);
|
|
}
|
|
|
|
int nextLeafNodeId = 0;
|
|
int nextMinId = 0;
|
|
this->Top->ComputeOctreeNodeInformation(this->Top, nextLeafNodeId,
|
|
nextMinId, this->LocatorPoints);
|
|
|
|
this->NumberOfLeafNodes = nextLeafNodeId;
|
|
int index = 0;
|
|
this->LeafNodeList = new vtkOctreePointLocatorNode*[this->NumberOfLeafNodes];
|
|
this->BuildLeafNodeList(this->Top, index);
|
|
this->BuildTime.Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::BuildLeafNodeList(vtkOctreePointLocatorNode* node,
|
|
int & index)
|
|
{
|
|
if(node->GetChild(0))
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
this->BuildLeafNodeList(node->GetChild(i), index);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->LeafNodeList[index] = node;
|
|
index++;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdType vtkOctreePointLocator::FindClosestPoint(const double x[3])
|
|
{
|
|
double dist2(0);
|
|
return this->FindClosestPoint(x[0], x[1], x[2], dist2);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdType vtkOctreePointLocator::FindClosestPoint(
|
|
double x, double y, double z, double &dist2)
|
|
{
|
|
this->BuildLocator();
|
|
|
|
int closeId=-1;
|
|
vtkIdType newCloseId=-1;
|
|
double newDistance2 = 4 * this->MaxWidth * this->MaxWidth;
|
|
|
|
int regionId = this->GetRegionContainingPoint(x, y, z);
|
|
vtkIdType closePointId = -1;
|
|
if (regionId < 0)
|
|
{
|
|
// This point is not inside the space divided by the octree.
|
|
// Find the point on the boundary that is closest to it.
|
|
|
|
double pt[3];
|
|
this->Top->GetDistance2ToBoundary(x, y, z, pt, this->Top, 1);
|
|
|
|
double *min = this->Top->GetMinBounds();
|
|
double *max = this->Top->GetMaxBounds();
|
|
|
|
// GetDistance2ToBoundary will sometimes return a point *just*
|
|
// *barely* outside the bounds of the region. Move that point to
|
|
// just barely *inside* instead.
|
|
|
|
if (pt[0] <= min[0])
|
|
{
|
|
pt[0] = min[0] + this->FudgeFactor;
|
|
}
|
|
if (pt[1] <= min[1])
|
|
{
|
|
pt[1] = min[1] + this->FudgeFactor;
|
|
}
|
|
if (pt[2] <= min[2])
|
|
{
|
|
pt[2] = min[2] + this->FudgeFactor;
|
|
}
|
|
if (pt[0] >= max[0])
|
|
{
|
|
pt[0] = max[0] - this->FudgeFactor;
|
|
}
|
|
if (pt[1] >= max[1])
|
|
{
|
|
pt[1] = max[1] - this->FudgeFactor;
|
|
}
|
|
if (pt[2] >= max[2])
|
|
{
|
|
pt[2] = max[2] - this->FudgeFactor;
|
|
}
|
|
|
|
regionId = this->GetRegionContainingPoint(pt[0], pt[1], pt[2]);
|
|
|
|
closeId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
|
|
|
|
closePointId = static_cast<vtkIdType>(this->LocatorIds[closeId]);
|
|
|
|
// Check to see if neighboring regions have a closer point
|
|
newCloseId = this->FindClosestPointInSphere(x, y, z,
|
|
sqrt(dist2), // radius
|
|
regionId, // skip this region
|
|
newDistance2);// distance to closest point
|
|
if(newDistance2 < dist2)
|
|
{
|
|
dist2 = newDistance2;
|
|
closePointId = newCloseId;
|
|
}
|
|
}
|
|
else // Point is inside an octree region
|
|
{
|
|
closeId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
|
|
closePointId = static_cast<vtkIdType>(this->LocatorIds[closeId]);
|
|
|
|
if (dist2 > 0.0)
|
|
{
|
|
float dist2ToBoundary = static_cast<float>(
|
|
this->LeafNodeList[regionId]->GetDistance2ToInnerBoundary(x, y, z, this->Top));
|
|
|
|
if (dist2ToBoundary < dist2)
|
|
{
|
|
// The closest point may be in a neighboring region
|
|
newCloseId = this->FindClosestPointInSphere(x, y, z,
|
|
sqrt(dist2), // radius
|
|
regionId, // skip this region
|
|
newDistance2);
|
|
if(newDistance2 < dist2)
|
|
{
|
|
dist2 = newDistance2;
|
|
closePointId = newCloseId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return closePointId;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdType vtkOctreePointLocator::FindClosestPointWithinRadius(
|
|
double radius, const double x[3], double& dist2)
|
|
{
|
|
return this->FindClosestPointInSphere(x[0], x[1], x[2], radius, -2, dist2);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdType vtkOctreePointLocator::FindClosestPointInRegion(
|
|
int regionId, double *x, double &dist2)
|
|
{
|
|
return this->FindClosestPointInRegion(regionId, x[0], x[1], x[2], dist2);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdType vtkOctreePointLocator::FindClosestPointInRegion(
|
|
int regionId, double x, double y, double z, double &dist2)
|
|
{
|
|
if (!this->LocatorPoints)
|
|
{
|
|
// if the locator hasn't been built yet the regionId is garbage!
|
|
vtkErrorMacro("vtkOctreePointLocator::FindClosestPointInRegion - must build locator first");
|
|
return -1;
|
|
}
|
|
int localId = this->_FindClosestPointInRegion(regionId, x, y, z, dist2);
|
|
|
|
vtkIdType originalId = -1;
|
|
|
|
if (localId >= 0)
|
|
{
|
|
originalId = static_cast<vtkIdType>(this->LocatorIds[localId]);
|
|
}
|
|
|
|
return originalId;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::_FindClosestPointInRegion(
|
|
int leafNodeId, double x, double y, double z, double &dist2)
|
|
{
|
|
int minId=0;
|
|
|
|
float fx = static_cast<float>(x);
|
|
float fy = static_cast<float>(y);
|
|
float fz = static_cast<float>(z);
|
|
|
|
float minDistance2 = 4 * this->MaxWidth * this->MaxWidth;
|
|
|
|
int idx = this->LeafNodeList[leafNodeId]->GetMinID();
|
|
|
|
float *candidate = this->LocatorPoints + (idx * 3);
|
|
|
|
int numPoints = this->LeafNodeList[leafNodeId]->GetNumberOfPoints();
|
|
for (int i=0; i < numPoints; i++)
|
|
{
|
|
float diffx = fx-candidate[0];
|
|
float diffy = fy-candidate[1];
|
|
float diffz = fz-candidate[2];
|
|
float dxyz = diffx*diffx + diffy*diffy + diffz*diffz;
|
|
if(dxyz < minDistance2)
|
|
{
|
|
minId = idx + i;
|
|
minDistance2 = dxyz;
|
|
if(dxyz == 0.0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
candidate += 3;
|
|
}
|
|
|
|
dist2 = minDistance2;
|
|
|
|
return minId;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::FindClosestPointInSphere(
|
|
double x, double y, double z, double radius, int skipRegion, double &dist2)
|
|
{
|
|
this->BuildLocator();
|
|
|
|
dist2 = radius * radius * 1.0001;
|
|
int localCloseId = -1;
|
|
|
|
std::stack<vtkOctreePointLocatorNode*> regions;
|
|
regions.push(this->Top);
|
|
while(!regions.empty())
|
|
{
|
|
vtkOctreePointLocatorNode* region = regions.top();
|
|
regions.pop();
|
|
if(region->GetChild(0))
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
vtkOctreePointLocatorNode* child = region->GetChild(i);
|
|
// must check for leaf nodes here in case skipRegion == -1
|
|
// since all non-leaf nodes have Id = -1.
|
|
if(child->GetID() != skipRegion &&
|
|
(child->GetDistance2ToBoundary(x, y, z, this->Top, 1) < dist2 ||
|
|
child->ContainsPoint(x, y, z, 0)))
|
|
{
|
|
regions.push(child);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double tempDist2 = dist2;
|
|
int tempId =
|
|
this->_FindClosestPointInRegion(region->GetID(), x, y, z, tempDist2);
|
|
|
|
if (tempDist2 < dist2)
|
|
{
|
|
dist2 = tempDist2;
|
|
localCloseId = tempId;
|
|
}
|
|
}
|
|
}
|
|
|
|
vtkIdType originalId = -1;
|
|
if(localCloseId >= 0 && dist2 <= radius*radius)
|
|
{
|
|
originalId = static_cast<vtkIdType>(this->LocatorIds[localCloseId]);
|
|
}
|
|
return originalId;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FindPointsWithinRadius(
|
|
double radius, const double x[3], vtkIdList* result)
|
|
{
|
|
result->Reset();
|
|
this->BuildLocator();
|
|
// don't forget to square the radius
|
|
this->FindPointsWithinRadius(this->Top, radius*radius, x, result);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FindPointsWithinRadius(
|
|
vtkOctreePointLocatorNode* node, double radiusSquared, const double x[3],
|
|
vtkIdList* result)
|
|
{
|
|
double b[6];
|
|
node->GetBounds(b);
|
|
|
|
double mindist2 = 0; // distance to closest vertex of BB
|
|
double maxdist2 = 0; // distance to furthest vertex of BB
|
|
// x-dir
|
|
if(x[0] < b[0])
|
|
{
|
|
mindist2 = (b[0]-x[0])*(b[0]-x[0]);
|
|
maxdist2 = (b[1]-x[0])*(b[1]-x[0]);
|
|
}
|
|
else if(x[0] > b[1])
|
|
{
|
|
mindist2 = (b[1]-x[0])*(b[1]-x[0]);
|
|
maxdist2 = (b[0]-x[0])*(b[0]-x[0]);
|
|
}
|
|
else if((b[1]-x[0]) > (x[0]-b[0]))
|
|
{
|
|
maxdist2 = (b[1]-x[0])*(b[1]-x[0]);
|
|
}
|
|
else
|
|
{
|
|
maxdist2 = (b[0]-x[0])*(b[0]-x[0]);
|
|
}
|
|
// y-dir
|
|
if(x[1] < b[2])
|
|
{
|
|
mindist2 += (b[2]-x[1])*(b[2]-x[1]);
|
|
maxdist2 += (b[3]-x[1])*(b[3]-x[1]);
|
|
}
|
|
else if(x[1] > b[3])
|
|
{
|
|
mindist2 += (b[3]-x[1])*(b[3]-x[1]);
|
|
maxdist2 += (b[2]-x[1])*(b[2]-x[1]);
|
|
}
|
|
else if((b[3]-x[1]) > (x[1]-b[2]))
|
|
{
|
|
maxdist2 += (b[3]-x[1])*(b[3]-x[1]);
|
|
}
|
|
else
|
|
{
|
|
maxdist2 += (b[2]-x[1])*(b[2]-x[1]);
|
|
}
|
|
// z-dir
|
|
if(x[2] < b[4])
|
|
{
|
|
mindist2 += (b[4]-x[2])*(b[4]-x[2]);
|
|
maxdist2 += (b[5]-x[2])*(b[5]-x[2]);
|
|
}
|
|
else if(x[2] > b[5])
|
|
{
|
|
mindist2 += (b[5]-x[2])*(b[5]-x[2]);
|
|
maxdist2 += (b[4]-x[2])*(b[4]-x[2]);
|
|
}
|
|
else if((b[5]-x[2]) > (x[2]-b[4]))
|
|
{
|
|
maxdist2 += (b[5]-x[2])*(b[5]-x[2]);
|
|
}
|
|
else
|
|
{
|
|
maxdist2 += (x[2]-b[4])*(x[2]-b[4]);
|
|
}
|
|
|
|
if(mindist2 > radiusSquared)
|
|
{
|
|
// non-intersecting
|
|
return;
|
|
}
|
|
|
|
if(maxdist2 <= radiusSquared)
|
|
{
|
|
// sphere contains BB
|
|
this->AddAllPointsInRegion(node, result);
|
|
return;
|
|
}
|
|
|
|
// partial intersection of sphere & BB
|
|
if (node->GetChild(0) == NULL)
|
|
{
|
|
//int regionID = node->GetID();
|
|
int regionLoc = node->GetMinID();
|
|
float* pt = this->LocatorPoints + (regionLoc * 3);
|
|
vtkIdType numPoints = node->GetNumberOfPoints();
|
|
for (vtkIdType i = 0; i < numPoints; i++)
|
|
{
|
|
double dist2 = (pt[0]-x[0])*(pt[0]-x[0])+
|
|
(pt[1]-x[1])*(pt[1]-x[1])+(pt[2]-x[2])*(pt[2]-x[2]);
|
|
if(dist2 <= radiusSquared)
|
|
{
|
|
vtkIdType ptId =
|
|
static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
|
|
result->InsertNextId(ptId);
|
|
}
|
|
pt += 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
this->FindPointsWithinRadius(
|
|
node->GetChild(i), radiusSquared, x, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FindClosestNPoints(int N, const double x[3],
|
|
vtkIdList* result)
|
|
{
|
|
result->Reset();
|
|
if(N<=0)
|
|
{
|
|
return;
|
|
}
|
|
this->BuildLocator();
|
|
|
|
int numTotalPoints = this->Top->GetNumberOfPoints();
|
|
if(numTotalPoints < N)
|
|
{
|
|
vtkWarningMacro("Number of requested points is greater than total number of points in OctreePointLocator");
|
|
N = numTotalPoints;
|
|
}
|
|
result->SetNumberOfIds(N);
|
|
|
|
// now we want to go about finding a region that contains at least N points
|
|
// but not many more -- hopefully the region contains X as well but we
|
|
// can't depend on that
|
|
vtkOctreePointLocatorNode* node = this->Top;
|
|
vtkOctreePointLocatorNode* startingNode = 0;
|
|
if(!node->ContainsPoint(x[0], x[1], x[2], 0))
|
|
{
|
|
// point is not in the region
|
|
int numPoints = node->GetNumberOfPoints();
|
|
vtkOctreePointLocatorNode* prevNode = node;
|
|
while(node->GetChild(0) && numPoints > N)
|
|
{
|
|
prevNode = node;
|
|
vtkOctreePointLocatorNode* nextNode = node->GetChild(0);
|
|
double minDist2 =
|
|
nextNode->GetDistance2ToBoundary(x[0], x[1], x[2], this->Top, 1);
|
|
for(int i=1;i<8;i++)
|
|
{
|
|
double dist2 = node->GetChild(i)->GetDistance2ToBoundary(
|
|
x[0], x[1], x[2], this->Top, 1);
|
|
if(dist2 < minDist2)
|
|
{
|
|
nextNode = node->GetChild(i);
|
|
minDist2 = dist2;
|
|
}
|
|
}
|
|
node = nextNode;
|
|
numPoints = node->GetNumberOfPoints();
|
|
}
|
|
if(numPoints < N)
|
|
{
|
|
startingNode = prevNode;
|
|
}
|
|
else
|
|
{
|
|
startingNode = node;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int numPoints = node->GetNumberOfPoints();
|
|
vtkOctreePointLocatorNode* prevNode = node;
|
|
while(node->GetChild(0) && numPoints > N)
|
|
{
|
|
prevNode = node;
|
|
int i;
|
|
for(i=0;i<8;i++)
|
|
{
|
|
if(node->GetChild(i)->ContainsPoint(x[0], x[1], x[2], 0))
|
|
{
|
|
node = node->GetChild(i);
|
|
break;
|
|
}
|
|
}
|
|
numPoints = node->GetNumberOfPoints();
|
|
}
|
|
if(numPoints < N)
|
|
{
|
|
startingNode = prevNode;
|
|
}
|
|
else
|
|
{
|
|
startingNode = node;
|
|
}
|
|
}
|
|
|
|
// now that we have a starting region, go through its points
|
|
// and order them
|
|
int regionId = startingNode->GetID();
|
|
int numPoints = startingNode->GetNumberOfPoints();
|
|
int where = startingNode->GetMinID();
|
|
if(regionId < 0) // if not a leaf node
|
|
{
|
|
vtkOctreePointLocatorNode* parentOfNext = startingNode->GetChild(0);
|
|
vtkOctreePointLocatorNode* next = parentOfNext->GetChild(0);
|
|
while(next)
|
|
{
|
|
parentOfNext = next;
|
|
next = next->GetChild(0);
|
|
}
|
|
where = parentOfNext->GetMinID();
|
|
}
|
|
int *ids = this->LocatorIds + where;
|
|
float* pt = this->LocatorPoints + (where*3);
|
|
float xfloat[3] = {static_cast<float>(x[0]), static_cast<float>(x[1]),
|
|
static_cast<float>(x[2])};
|
|
OrderPoints orderedPoints(N);
|
|
for (int i=0; i<numPoints; i++)
|
|
{
|
|
float dist2 = vtkMath::Distance2BetweenPoints(xfloat, pt);
|
|
orderedPoints.InsertPoint(dist2, ids[i]);
|
|
pt += 3;
|
|
}
|
|
|
|
// to finish up we have to check other regions for
|
|
// closer points
|
|
float largestDist2 = orderedPoints.GetLargestDist2();
|
|
double bounds[6];
|
|
node = this->Top;
|
|
std::queue<vtkOctreePointLocatorNode*> nodesToBeSearched;
|
|
nodesToBeSearched.push(node);
|
|
while(!nodesToBeSearched.empty())
|
|
{
|
|
node = nodesToBeSearched.front();
|
|
nodesToBeSearched.pop();
|
|
if(node == startingNode)
|
|
{
|
|
continue;
|
|
}
|
|
if(node->GetChild(0))
|
|
{
|
|
for(int j=0;j<8;j++)
|
|
{
|
|
vtkOctreePointLocatorNode* child = node->GetChild(j);
|
|
child->GetDataBounds(bounds);
|
|
double delta[3] = {0,0,0};
|
|
if(vtkMath::PointIsWithinBounds(const_cast<double*>(x), bounds, delta) == 1 ||
|
|
child->GetDistance2ToBoundary(x[0], x[1], x[2], 0, 1) < largestDist2)
|
|
{
|
|
nodesToBeSearched.push(child);
|
|
}
|
|
}
|
|
}
|
|
else if(node->GetDistance2ToBoundary(x[0], x[1], x[2], this->Top, 1) < largestDist2)
|
|
{
|
|
numPoints = node->GetNumberOfPoints();
|
|
where = node->GetMinID();
|
|
ids = this->LocatorIds + where;
|
|
pt = this->LocatorPoints + (where*3);
|
|
for (int i=0; i<numPoints; i++)
|
|
{
|
|
float dist2 = vtkMath::Distance2BetweenPoints(xfloat, pt);
|
|
orderedPoints.InsertPoint(dist2, ids[i]);
|
|
pt += 3;
|
|
}
|
|
largestDist2 = orderedPoints.GetLargestDist2();
|
|
}
|
|
}
|
|
orderedPoints.GetSortedIds(result);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkIdTypeArray *vtkOctreePointLocator::GetPointsInRegion(int leafNodeId)
|
|
{
|
|
if ( (leafNodeId < 0) || (leafNodeId >= this->NumberOfLeafNodes))
|
|
{
|
|
vtkErrorMacro("vtkOctreePointLocator::GetPointsInRegion invalid leaf node ID");
|
|
return NULL;
|
|
}
|
|
|
|
if (!this->LocatorIds)
|
|
{
|
|
// don't build locator since leafNodeId is probably garbage anyways
|
|
vtkErrorMacro("vtkOctreePointLocator::GetPointsInRegion build locator first");
|
|
return NULL;
|
|
}
|
|
|
|
int numPoints = this->LeafNodeList[leafNodeId]->GetNumberOfPoints();
|
|
int where = this->LeafNodeList[leafNodeId]->GetMinID();
|
|
|
|
vtkIdTypeArray *ptIds = vtkIdTypeArray::New();
|
|
ptIds->SetNumberOfValues(numPoints);
|
|
|
|
int *ids = this->LocatorIds + where;
|
|
|
|
for (int i=0; i<numPoints; i++)
|
|
{
|
|
ptIds->SetValue(i, ids[i]);
|
|
}
|
|
|
|
return ptIds;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FreeSearchStructure()
|
|
{
|
|
if (this->Top)
|
|
{
|
|
vtkOctreePointLocator::DeleteAllDescendants(this->Top);
|
|
this->Top->Delete();
|
|
this->Top = NULL;
|
|
}
|
|
delete [] this->LeafNodeList;
|
|
this->LeafNodeList = NULL;
|
|
|
|
this->NumberOfLeafNodes = 0;
|
|
|
|
delete [] this->LocatorPoints;
|
|
this->LocatorPoints = NULL;
|
|
|
|
delete [] this->LocatorIds;
|
|
this->LocatorIds = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// build PolyData representation of all spacial regions------------
|
|
//
|
|
void vtkOctreePointLocator::GenerateRepresentation(int level,
|
|
vtkPolyData *pd)
|
|
{
|
|
if ( this->Top == NULL )
|
|
{
|
|
vtkErrorMacro("vtkOctreePointLocator::GenerateRepresentation no tree");
|
|
return;
|
|
}
|
|
|
|
std::list<vtkOctreePointLocatorNode*> nodesAtLevel;
|
|
// queue of nodes to be examined and what level each one is at
|
|
std::queue<std::pair<vtkOctreePointLocatorNode*, int> > testNodes;
|
|
testNodes.push(std::make_pair(this->Top, 0));
|
|
while(!testNodes.empty())
|
|
{
|
|
vtkOctreePointLocatorNode* node = testNodes.front().first;
|
|
int nodeLevel = testNodes.front().second;
|
|
testNodes.pop();
|
|
if(nodeLevel == level)
|
|
{
|
|
nodesAtLevel.push_back(node);
|
|
}
|
|
else if(node->GetChild(0))
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
testNodes.push(std::make_pair(node->GetChild(i), nodeLevel+1));
|
|
}
|
|
}
|
|
}
|
|
|
|
int npoints = 8 * static_cast<int>(nodesAtLevel.size());
|
|
int npolys = 6 * static_cast<int>(nodesAtLevel.size());
|
|
|
|
vtkPoints* pts = vtkPoints::New();
|
|
pts->Allocate(npoints);
|
|
vtkCellArray* polys = vtkCellArray::New();
|
|
polys->Allocate(npolys);
|
|
|
|
for(std::list<vtkOctreePointLocatorNode*>::iterator it=nodesAtLevel.begin();
|
|
it!=nodesAtLevel.end();it++)
|
|
{
|
|
vtkOctreePointLocator::AddPolys(*it, pts, polys);
|
|
}
|
|
|
|
pd->SetPoints(pts);
|
|
pts->Delete();
|
|
pd->SetPolys(polys);
|
|
polys->Delete();
|
|
pd->Squeeze();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::AddPolys(vtkOctreePointLocatorNode* node,
|
|
vtkPoints* pts, vtkCellArray * polys)
|
|
{
|
|
vtkIdType ids[8];
|
|
vtkIdType idList[4];
|
|
double x[3];
|
|
|
|
double* min = node->GetMinBounds();
|
|
double* max = node->GetMaxBounds();
|
|
|
|
x[0] = min[0]; x[1] = max[1]; x[2] = min[2];
|
|
ids[0] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = max[0]; x[1] = max[1]; x[2] = min[2];
|
|
ids[1] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = max[0]; x[1] = max[1]; x[2] = max[2];
|
|
ids[2] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = min[0]; x[1] = max[1]; x[2] = max[2];
|
|
ids[3] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = min[0]; x[1] = min[1]; x[2] = min[2];
|
|
ids[4] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = max[0]; x[1] = min[1]; x[2] = min[2];
|
|
ids[5] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = max[0]; x[1] = min[1]; x[2] = max[2];
|
|
ids[6] = pts->InsertNextPoint(x);
|
|
|
|
x[0] = min[0]; x[1] = min[1]; x[2] = max[2];
|
|
ids[7] = pts->InsertNextPoint(x);
|
|
|
|
idList[0] = ids[0]; idList[1] = ids[1]; idList[2] = ids[2]; idList[3] = ids[3];
|
|
polys->InsertNextCell(4, idList);
|
|
|
|
idList[0] = ids[1]; idList[1] = ids[5]; idList[2] = ids[6]; idList[3] = ids[2];
|
|
polys->InsertNextCell(4, idList);
|
|
|
|
idList[0] = ids[5]; idList[1] = ids[4]; idList[2] = ids[7]; idList[3] = ids[6];
|
|
polys->InsertNextCell(4, idList);
|
|
|
|
idList[0] = ids[4]; idList[1] = ids[0]; idList[2] = ids[3]; idList[3] = ids[7];
|
|
polys->InsertNextCell(4, idList);
|
|
|
|
idList[0] = ids[3]; idList[1] = ids[2]; idList[2] = ids[6]; idList[3] = ids[7];
|
|
polys->InsertNextCell(4, idList);
|
|
|
|
idList[0] = ids[1]; idList[1] = ids[0]; idList[2] = ids[4]; idList[3] = ids[5];
|
|
polys->InsertNextCell(4, idList);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::FindRegion(vtkOctreePointLocatorNode *node, float x,
|
|
float y, float z)
|
|
{
|
|
return vtkOctreePointLocator::FindRegion(
|
|
node, static_cast<double>(x),static_cast<double>(y),static_cast<double>(z));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::FindRegion(vtkOctreePointLocatorNode *node, double x,
|
|
double y, double z)
|
|
{
|
|
if (!node->ContainsPoint(x, y, z, 0))
|
|
{
|
|
return -1; // no region is found
|
|
}
|
|
|
|
if (node->GetChild(0) == NULL)
|
|
{
|
|
return node->GetID();
|
|
}
|
|
|
|
int regionId = -1;
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
regionId =
|
|
vtkOctreePointLocator::FindRegion(node->GetChild(i), x, y, z);
|
|
if(regionId >=0 )
|
|
{
|
|
return regionId;
|
|
}
|
|
}
|
|
|
|
return -1; // no region is found
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkOctreePointLocator::GetRegionContainingPoint(double x, double y,
|
|
double z)
|
|
{
|
|
return vtkOctreePointLocator::FindRegion(this->Top, x, y, z);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FindPointsInArea(
|
|
double* area, vtkIdTypeArray* ids, bool clearArray)
|
|
{
|
|
if (clearArray)
|
|
{
|
|
ids->Reset();
|
|
}
|
|
this->BuildLocator();
|
|
this->FindPointsInArea(this->Top, area, ids);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::FindPointsInArea(
|
|
vtkOctreePointLocatorNode* node, double* area, vtkIdTypeArray* ids)
|
|
{
|
|
double b[6];
|
|
node->GetBounds(b);
|
|
|
|
if (b[0] > area[1] || b[1] < area[0] ||
|
|
b[2] > area[3] || b[3] < area[2] ||
|
|
b[4] > area[5] || b[5] < area[4])
|
|
{
|
|
return; // no intersection
|
|
}
|
|
|
|
bool contains = false;
|
|
if (area[0] <= b[0] && b[1] <= area[1] &&
|
|
area[2] <= b[2] && b[3] <= area[3] &&
|
|
area[4] <= b[4] && b[5] <= area[5])
|
|
{
|
|
contains = true;
|
|
}
|
|
|
|
if (contains)
|
|
{
|
|
this->AddAllPointsInRegion(node, ids);
|
|
}
|
|
else // intersects
|
|
{
|
|
if (node->GetChild(0) == NULL)
|
|
{
|
|
//int regionID = node->GetID();
|
|
int regionLoc = node->GetMinID();
|
|
float* pt = this->LocatorPoints + (regionLoc * 3);
|
|
vtkIdType numPoints = node->GetNumberOfPoints();
|
|
for (vtkIdType i = 0; i < numPoints; i++)
|
|
{
|
|
if (area[0] <= pt[0] && pt[0] <= area[1] &&
|
|
area[2] <= pt[1] && pt[1] <= area[3] &&
|
|
area[4] <= pt[2] && pt[2] <= area[5])
|
|
{
|
|
vtkIdType ptId =
|
|
static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
|
|
ids->InsertNextValue(ptId);
|
|
}
|
|
pt += 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
this->FindPointsInArea(node->GetChild(i), area, ids);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::AddAllPointsInRegion(vtkOctreePointLocatorNode* node,
|
|
vtkIdTypeArray* ids)
|
|
{
|
|
int regionLoc = node->GetMinID();
|
|
vtkIdType numPoints = node->GetNumberOfPoints();
|
|
for (vtkIdType i = 0; i < numPoints; i++)
|
|
{
|
|
vtkIdType ptId = static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
|
|
ids->InsertNextValue(ptId);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::AddAllPointsInRegion(vtkOctreePointLocatorNode* node,
|
|
vtkIdList* ids)
|
|
{
|
|
int regionLoc = node->GetMinID();
|
|
vtkIdType numPoints = node->GetNumberOfPoints();
|
|
for (vtkIdType i = 0; i < numPoints; i++)
|
|
{
|
|
vtkIdType ptId = static_cast<vtkIdType>(this->LocatorIds[regionLoc + i]);
|
|
ids->InsertNextId(ptId);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkOctreePointLocator::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "MaximumPointsPerRegion: " <<
|
|
this->MaximumPointsPerRegion << endl;
|
|
os << indent << "NumberOfLeafNodes: " << this->NumberOfLeafNodes << endl;
|
|
os << indent << "Top: " << this->Top << endl;
|
|
os << indent << "LeafNodeList: " << this->LeafNodeList << endl;
|
|
os << indent << "LocatorPoints: " << this->LocatorPoints << endl;
|
|
os << indent << "NumberOfLocatorPoints: "
|
|
<< this->NumberOfLocatorPoints << endl;
|
|
os << indent << "LocatorIds: " << this->LocatorIds << endl;
|
|
os << indent << "FudgeFactor: " << this->FudgeFactor << endl;
|
|
os << indent << "MaxWidth: " << this->MaxWidth << endl;
|
|
os << indent << "CreateCubicOctants: " << this->CreateCubicOctants << endl;
|
|
}
|