/*========================================================================= Program: Visualization Toolkit Module: vtkIncrementalOctreeNode.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. =========================================================================*/ // Hide VTK_DEPRECATED_IN_9_1_0() warnings for this class. #define VTK_DEPRECATION_LEVEL 0 #include "vtkIncrementalOctreeNode.h" #include "vtkIdList.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPoints.h" vtkStandardNewMacro(vtkIncrementalOctreeNode); vtkCxxSetObjectMacro(vtkIncrementalOctreeNode, PointIdSet, vtkIdList); vtkCxxSetObjectMacro(vtkIncrementalOctreeNode, Parent, vtkIncrementalOctreeNode); //------------------------------------------------------------------------------ // ----------------------------- Helper functions ---------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // This is an empty function which provides only the point index to the caller // function vtkIncreemntalOctreeNode::InsertPoint(). The caller inserts the // point index to the vtkIdList maintained by a leaf node, without inserting // the point (coordinate) to vtkPoints at all. static void OctreeNodeGetPointId( vtkPoints* vtkNotUsed(points), vtkIdType* vtkNotUsed(pntIdx), const double* vtkNotUsed(coords)) { // the 3D point coordinate is not inserted to vtkPoints at all } //------------------------------------------------------------------------------ // Insert a point, with a specified point index, to a vtkPoints object by // calling vtkPoints::InsertPoint(). static void OctreeNodeInsertPoint(vtkPoints* points, vtkIdType* pntIdx, const double* coords) { points->InsertPoint(*pntIdx, coords); } //------------------------------------------------------------------------------ // Insert a point to a vtkPoints by calling vtkPoints::InsertNextPoint(). static void OctreeNodeInsertNextPoint(vtkPoints* points, vtkIdType* pntIdx, const double* coords) { *pntIdx = points->InsertNextPoint(coords); } //------------------------------------------------------------------------------ // Function pointers in support of three point insertion modes. typedef void (*OCTREENODE_INSERTPOINT_FUNCTION)( vtkPoints* points, vtkIdType* pntIdx, const double* coords); static OCTREENODE_INSERTPOINT_FUNCTION OCTREENODE_INSERTPOINT[3] = { OctreeNodeGetPointId, OctreeNodeInsertPoint, OctreeNodeInsertNextPoint }; //------------------------------------------------------------------------------ // ------------------------- vtkIncrementalOctreeNode ------------------------ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkIncrementalOctreeNode::vtkIncrementalOctreeNode() { this->Parent = nullptr; this->Children = nullptr; this->PointIdSet = nullptr; this->NumberOfPoints = 0; this->ID = 0; // unnecessary to initialize spatial and data bounding boxes here as // SetBounds() are always called by the user for the root node of an // octree and this function is also always called for any descendant // node upon node-subdivison. for now though we'll set them to // something to avoid uninitialized variable warnings for (int i = 0; i < 3; i++) { this->MinBounds[i] = this->MinDataBounds[i] = VTK_DOUBLE_MIN; this->MaxBounds[i] = this->MaxDataBounds[i] = VTK_DOUBLE_MAX; } } //------------------------------------------------------------------------------ vtkIncrementalOctreeNode::~vtkIncrementalOctreeNode() { if (this->Parent) { this->Parent->UnRegister(this); this->Parent = nullptr; } this->DeleteChildNodes(); this->DeletePointIdSet(); } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::DeleteChildNodes() { if (this->Children) { for (int i = 0; i < 8; i++) { this->Children[i]->Delete(); this->Children[i] = nullptr; } delete[] this->Children; this->Children = nullptr; } } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::CreatePointIdSet(int initSize, int growSize) { if (this->PointIdSet == nullptr) { this->PointIdSet = vtkIdList::New(); this->PointIdSet->Allocate(initSize, growSize); } } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::DeletePointIdSet() { if (this->PointIdSet) { this->PointIdSet->Delete(); this->PointIdSet = nullptr; } } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::SetBounds( double x1, double x2, double y1, double y2, double z1, double z2) { this->MinBounds[0] = x1; this->MaxBounds[0] = x2; this->MinBounds[1] = y1; this->MaxBounds[1] = y2; this->MinBounds[2] = z1; this->MaxBounds[2] = z2; this->MinDataBounds[0] = x2; this->MaxDataBounds[0] = x1; this->MinDataBounds[1] = y2; this->MaxDataBounds[1] = y1; this->MinDataBounds[2] = z2; this->MaxDataBounds[2] = z1; } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::GetBounds(double bounds[6]) const { bounds[0] = this->MinBounds[0]; bounds[1] = this->MaxBounds[0]; bounds[2] = this->MinBounds[1]; bounds[3] = this->MaxBounds[1]; bounds[4] = this->MinBounds[2]; bounds[5] = this->MaxBounds[2]; } //------------------------------------------------------------------------------ int vtkIncrementalOctreeNode::UpdateCounterAndDataBounds( const double point[3], int nHits, int updateData) { this->NumberOfPoints += nHits; if (updateData == 0) return 0; int updated = 0; if (point[0] < this->MinDataBounds[0]) { updated = 1; this->MinDataBounds[0] = point[0]; } if (point[0] > this->MaxDataBounds[0]) { updated = 1; this->MaxDataBounds[0] = point[0]; } if (point[1] < this->MinDataBounds[1]) { updated = 1; this->MinDataBounds[1] = point[1]; } if (point[1] > this->MaxDataBounds[1]) { updated = 1; this->MaxDataBounds[1] = point[1]; } if (point[2] < this->MinDataBounds[2]) { updated = 1; this->MinDataBounds[2] = point[2]; } if (point[2] > this->MaxDataBounds[2]) { updated = 1; this->MaxDataBounds[2] = point[2]; } return updated; } //------------------------------------------------------------------------------ // Given the index (0 ~ 7) of a child node, the spatial bounding axis (0 ~ 2 // for x, y, and z), and the value (0 ~ 1 for min and max) to access, this LUT // allows for rapid assignment of its spatial bounding box --- MinBounds[3] // and MaxBounds[3], with each specific value or entry of this LUT pointing to // MinBounds[3] for 0, center point for 1, or MaxBounds[3] for 2. static int OCTREE_CHILD_BOUNDS_LUT[8][3][2] = { { { 0, 1 }, { 0, 1 }, { 0, 1 } }, { { 1, 2 }, { 0, 1 }, { 0, 1 } }, { { 0, 1 }, { 1, 2 }, { 0, 1 } }, { { 1, 2 }, { 1, 2 }, { 0, 1 } }, { { 0, 1 }, { 0, 1 }, { 1, 2 } }, { { 1, 2 }, { 0, 1 }, { 1, 2 } }, { { 0, 1 }, { 1, 2 }, { 1, 2 } }, { { 1, 2 }, { 1, 2 }, { 1, 2 } }, }; //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::SeperateExactlyDuplicatePointsFromNewInsertion(vtkPoints* points, vtkIdList* pntIds, const double newPnt[3], vtkIdType* pntIdx, int maxPts, int ptMode) { // the number of points already maintained in this leaf node // >= maxPts AND all of them are exactly duplicate with one another // BUT the new point is not a duplicate of them any more int i; double dupPnt[3]; double octMin[3]; double octMid[3]; double octMax[3]; double* boxPtr[3] = { nullptr, nullptr, nullptr }; vtkIncrementalOctreeNode* ocNode = nullptr; vtkIncrementalOctreeNode* duplic = this; vtkIncrementalOctreeNode* single = this; // the coordinate of the duplicate points: note pntIds == this->PointIdSet points->GetPoint(pntIds->GetId(0), dupPnt); while (duplic == single) // as long as separation has not been achieved { // update the current (in recursion) node and access the bounding box info ocNode = duplic; octMid[0] = (ocNode->MinBounds[0] + ocNode->MaxBounds[0]) * 0.5; octMid[1] = (ocNode->MinBounds[1] + ocNode->MaxBounds[1]) * 0.5; octMid[2] = (ocNode->MinBounds[2] + ocNode->MaxBounds[2]) * 0.5; boxPtr[0] = ocNode->MinBounds; boxPtr[1] = octMid; boxPtr[2] = ocNode->MaxBounds; // create eight child nodes ocNode->Children = new vtkIncrementalOctreeNode*[8]; for (i = 0; i < 8; i++) { // x-bound: axis 0 octMin[0] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][0][0]][0]; octMax[0] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][0][1]][0]; // y-bound: axis 1 octMin[1] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][1][0]][1]; octMax[1] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][1][1]][1]; // z-bound: axis 2 octMin[2] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][2][0]][2]; octMax[2] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][2][1]][2]; ocNode->Children[i] = vtkIncrementalOctreeNode::New(); ocNode->Children[i]->SetParent(ocNode); ocNode->Children[i]->SetBounds( octMin[0], octMax[0], octMin[1], octMax[1], octMin[2], octMax[2]); } // determine the leaf node of the duplicate points & that of the new point duplic = ocNode->Children[ocNode->GetChildIndex(dupPnt)]; single = ocNode->Children[ocNode->GetChildIndex(newPnt)]; } boxPtr[0] = nullptr; boxPtr[1] = nullptr; boxPtr[2] = nullptr; // Now the duplicate points have been separated from the new point // // create a vtkIdList object for the new point // update the counter and the data bounding box until the root node // (including the root node) OCTREENODE_INSERTPOINT[ptMode](points, pntIdx, newPnt); single->CreatePointIdSet((maxPts >> 2), (maxPts >> 1)); single->GetPointIdSet()->InsertNextId(*pntIdx); single->UpdateCounterAndDataBoundsRecursively(newPnt, 1, 1, nullptr); // We just need to reference pntIds while un-registering it from 'this'. // This avoids deep-copying point ids from pntIds to duplic's PointIdSet. // update the counter and the data bounding box, but until 'this' node // (excluding 'this' node) duplic->SetPointIdSet(pntIds); duplic->UpdateCounterAndDataBoundsRecursively(dupPnt, pntIds->GetNumberOfIds(), 1, this); // handle memory ocNode = nullptr; duplic = nullptr; single = nullptr; } //------------------------------------------------------------------------------ int vtkIncrementalOctreeNode::CreateChildNodes(vtkPoints* points, vtkIdList* pntIds, const double newPnt[3], vtkIdType* pntIdx, int maxPts, int ptMode, int& numberOfNodes) { // There are two scenarios for which this function is invoked. // // (1) the number of points already maintained in this leaf node // == maxPts AND not all of them are exactly duplicate // AND the new point is not a duplicate of them all // (2) the number of points already maintained in this leaf node // >= maxPts AND all of them are exactly duplicate with one another // BUT the new point is not a duplicate of them any more // address case (2) first if necessary double sample[3]; points->GetPoint(pntIds->GetId(0), sample); if (this->ContainsDuplicatePointsOnly(sample) == 1) { this->SeperateExactlyDuplicatePointsFromNewInsertion( points, pntIds, newPnt, pntIdx, maxPts, ptMode); // notify vtkIncrementalOctreeNode::InsertPoint() that pntIds just needs // to be unregistered from 'this', but must NOT be destroyed at all. return 0; } // then address case (1) below int i; int target; int dvidId = -1; // index of the sub-dividing octant, if any int fullId = -1; // index of the full octant, if any int numIds[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; double octMin[3]; double octMax[3]; double tempPt[3]; vtkIdType tempId; double octMid[3] = { (this->MinBounds[0] + this->MaxBounds[0]) * 0.5, (this->MinBounds[1] + this->MaxBounds[1]) * 0.5, (this->MinBounds[2] + this->MaxBounds[2]) * 0.5 }; double* boxPtr[3]; boxPtr[0] = this->MinBounds; boxPtr[1] = octMid; boxPtr[2] = this->MaxBounds; // create eight child nodes this->Children = new vtkIncrementalOctreeNode*[8]; for (i = 0; i < 8; i++) { // x-bound: axis 0 octMin[0] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][0][0]][0]; octMax[0] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][0][1]][0]; // y-bound: axis 1 octMin[1] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][1][0]][1]; octMax[1] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][1][1]][1]; // z-bound: axis 2 octMin[2] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][2][0]][2]; octMax[2] = boxPtr[OCTREE_CHILD_BOUNDS_LUT[i][2][1]][2]; // This call internally sets the cener and default data bounding box, too. this->Children[i] = vtkIncrementalOctreeNode::New(); this->Children[i]->ID = numberOfNodes++; this->Children[i]->SetParent(this); this->Children[i]->SetBounds(octMin[0], octMax[0], octMin[1], octMax[1], octMin[2], octMax[2]); // allocate a list of point-indices (size = 2^n) for index registration this->Children[i]->CreatePointIdSet((maxPts >> 2), (maxPts >> 1)); } boxPtr[0] = nullptr; boxPtr[1] = nullptr; boxPtr[2] = nullptr; // distribute the available point-indices to the eight child nodes for (i = 0; i < maxPts; i++) { tempId = pntIds->GetId(i); points->GetPoint(tempId, tempPt); target = this->GetChildIndex(tempPt); this->Children[target]->GetPointIdSet()->InsertNextId(tempId); this->Children[target]->UpdateCounterAndDataBounds(tempPt); numIds[target]++; } // locate the full child, just if any for (i = 0; i < 8; i++) { if (numIds[i] == maxPts) { fullId = i; break; } } target = this->GetChildIndex(newPnt); if (fullId == target) { // The fact is that we are going to insert the new point to an already // full octant (child node). Thus we need to further divide this child // to avoid the overflow problem. this->Children[target]->CreateChildNodes( points, pntIds, newPnt, pntIdx, maxPts, ptMode, numberOfNodes); dvidId = fullId; } else { // the initial division is a success OCTREENODE_INSERTPOINT[ptMode](points, pntIdx, newPnt); this->Children[target]->GetPointIdSet()->InsertNextId(*pntIdx); this->Children[target]->UpdateCounterAndDataBoundsRecursively(newPnt, 1, 1, nullptr); // NOTE: The counter below might reach the threshold, though we delay the // sub-division of this child node until the next point insertion occurs. numIds[target]++; } // Now it is time to reclaim those un-used vtkIdList objects, of which each // either is empty or still needs to be deleted due to further division of // the child node. This post-deallocation of the un-used vtkIdList objects // (of some child nodes) is based on the assumption that retrieving the // 'maxPts' points from vtkPoints and the associated 'maxPts' point-indices // from vtkIdList is more expensive than reclaiming at most 8 vtkIdList // objects at hand. for (i = 0; i < 8; i++) { if (numIds[i] == 0 || i == dvidId) { this->Children[i]->DeletePointIdSet(); } } // notify vtkIncrementalOctreeNode::InsertPoint() to destroy pntIds return 1; } //------------------------------------------------------------------------------ int vtkIncrementalOctreeNode::InsertPoint( vtkPoints* points, const double newPnt[3], int maxPts, vtkIdType* pntId, int ptMode) { VTK_LEGACY_REPLACED_BODY(vtkIncrementalOctreeNode::InsertPoint(vtkPoints * points, const double newPnt[3], int maxPts, vtkIdType* pntId, int ptMode), "VTK 9.1", vtkIncrementalOctreeNode::InsertPoint(vtkPoints * points, const double newPnt[3], int maxPts, vtkIdType* pntId, int ptMode, int& numberOfNodes)); int numberOfNodes = 0; return InsertPoint(points, newPnt, maxPts, pntId, ptMode, numberOfNodes); } //------------------------------------------------------------------------------ int vtkIncrementalOctreeNode::InsertPoint(vtkPoints* points, const double newPnt[3], int maxPts, vtkIdType* pntId, int ptMode, int& numberOfNodes) { if (this->PointIdSet) { // there has been at least one point index if (this->PointIdSet->GetNumberOfIds() < maxPts || this->ContainsDuplicatePointsOnly(newPnt) == 1) { // this leaf node is not full or // this leaf node is full, but of all exactly duplicate points // and the point under check is another duplicate of these points OCTREENODE_INSERTPOINT[ptMode](points, pntId, newPnt); this->PointIdSet->InsertNextId(*pntId); this->UpdateCounterAndDataBoundsRecursively(newPnt, 1, 1, nullptr); } else { // overflow: divide this node and delete the list of point-indices. // Note that the number of exactly duplicate points might be greater // than or equal to maxPts. if (this->CreateChildNodes( points, this->PointIdSet, newPnt, pntId, maxPts, ptMode, numberOfNodes)) { this->PointIdSet->Delete(); } else { this->PointIdSet->UnRegister(this); } this->PointIdSet = nullptr; } } else { // there has been no any point index registered in this leaf node OCTREENODE_INSERTPOINT[ptMode](points, pntId, newPnt); this->PointIdSet = vtkIdList::New(); this->PointIdSet->Allocate((maxPts >> 2), (maxPts >> 1)); this->PointIdSet->InsertNextId(*pntId); this->UpdateCounterAndDataBoundsRecursively(newPnt, 1, 1, nullptr); } return 1; } //------------------------------------------------------------------------------ double vtkIncrementalOctreeNode::GetDistance2ToBoundary(const double point[3], double closest[3], int innerOnly, vtkIncrementalOctreeNode* rootNode, int checkData) { // It is mandatory that GetMinDataBounds() and GetMaxDataBounds() be used. // Direct access to MinDataBounds and MaxDataBounds might incur problems. double* thisMin = nullptr; double* thisMax = nullptr; double* rootMin = nullptr; double* rootMax = nullptr; double minDist = VTK_DOUBLE_MAX; // minimum distance to the boundaries if (checkData) { thisMin = this->GetMinDataBounds(); thisMax = this->GetMaxDataBounds(); rootMin = rootNode->GetMinDataBounds(); rootMax = rootNode->GetMaxDataBounds(); } else { thisMin = this->MinBounds; thisMax = this->MaxBounds; rootMin = rootNode->GetMinBounds(); rootMax = rootNode->GetMaxBounds(); } int minFace = 0; // index of the face with min distance to the point int beXless = int(point[0] < thisMin[0]); int beXmore = int(point[0] > thisMax[0]); int beYless = int(point[1] < thisMin[1]); int beYmore = int(point[1] > thisMax[1]); int beZless = int(point[2] < thisMin[2]); int beZmore = int(point[2] > thisMax[2]); int withinX = int((!beXless) && (!beXmore)); int withinY = int((!beYless) && (!beYmore)); int withinZ = int((!beZless) && (!beZmore)); int xyzFlag = (withinZ << 2) + (withinY << 1) + withinX; switch (xyzFlag) { case 0: // withinZ = 0; withinY = 0; withinX = 0 // closest to a corner closest[0] = (beXless ? thisMin[0] : thisMax[0]); closest[1] = (beYless ? thisMin[1] : thisMax[1]); closest[2] = (beZless ? thisMin[2] : thisMax[2]); minDist = vtkMath::Distance2BetweenPoints(point, closest); break; case 1: // withinZ = 0; withinY = 0; withinX = 1 // closest to an x-aligned edge closest[0] = point[0]; closest[1] = (beYless ? thisMin[1] : thisMax[1]); closest[2] = (beZless ? thisMin[2] : thisMax[2]); minDist = vtkMath::Distance2BetweenPoints(point, closest); break; case 2: // withinZ = 0; withinY = 1; withinX = 0 // closest to a y-aligned edge closest[0] = (beXless ? thisMin[0] : thisMax[0]); closest[1] = point[1]; closest[2] = (beZless ? thisMin[2] : thisMax[2]); minDist = vtkMath::Distance2BetweenPoints(point, closest); break; case 3: // withinZ = 0; withinY = 1; withinX = 1 // closest to a z-face if (beZless) { minDist = thisMin[2] - point[2]; closest[2] = thisMin[2]; } else { minDist = point[2] - thisMax[2]; closest[2] = thisMax[2]; } minDist *= minDist; closest[0] = point[0]; closest[1] = point[1]; break; case 4: // withinZ = 1; withinY = 0; withinX = 0 // cloest to a z-aligned edge closest[0] = (beXless ? thisMin[0] : thisMax[0]); closest[1] = (beYless ? thisMin[1] : thisMax[1]); closest[2] = point[2]; minDist = vtkMath::Distance2BetweenPoints(point, closest); break; case 5: // withinZ = 1; withinY = 0; withinX = 1 // closest to a y-face if (beYless) { minDist = thisMin[1] - point[1]; closest[1] = thisMin[1]; } else { minDist = point[1] - thisMax[1]; closest[1] = thisMax[1]; } minDist *= minDist; closest[0] = point[0]; closest[2] = point[2]; break; case 6: // withinZ = 1; withinY = 1; withinX = 0 // closest to an x-face if (beXless) { minDist = thisMin[0] - point[0]; closest[0] = thisMin[0]; } else { minDist = point[0] - thisMax[0]; closest[0] = thisMax[0]; } minDist *= minDist; closest[1] = point[1]; closest[2] = point[2]; break; case 7: // withinZ = 1; withinY = 1; withinZ = 1 // point is inside the box if (innerOnly) // check only inner boundaries { double faceDst; faceDst = point[0] - thisMin[0]; // x-min face if (thisMin[0] != rootMin[0] && faceDst < minDist) { minFace = 0; minDist = faceDst; } faceDst = thisMax[0] - point[0]; // x-max face if (thisMax[0] != rootMax[0] && faceDst < minDist) { minFace = 1; minDist = faceDst; } faceDst = point[1] - thisMin[1]; // y-min face if (thisMin[1] != rootMin[1] && faceDst < minDist) { minFace = 2; minDist = faceDst; } faceDst = thisMax[1] - point[1]; // y-max face if (thisMax[1] != rootMax[1] && faceDst < minDist) { minFace = 3; minDist = faceDst; } faceDst = point[2] - thisMin[2]; // z-min face if (thisMin[2] != rootMin[2] && faceDst < minDist) { minFace = 4; minDist = faceDst; } faceDst = thisMax[2] - point[2]; // z-max face if (thisMax[2] != rootMax[2] && faceDst < minDist) { minFace = 5; minDist = faceDst; } } else // check all boundaries { double tmpDist[6]; tmpDist[0] = point[0] - thisMin[0]; tmpDist[1] = thisMax[0] - point[0]; tmpDist[2] = point[1] - thisMin[1]; tmpDist[3] = thisMax[1] - point[1]; tmpDist[4] = point[2] - thisMin[2]; tmpDist[5] = thisMax[2] - point[2]; for (int i = 0; i < 6; i++) { if (tmpDist[i] < minDist) { minFace = i; minDist = tmpDist[i]; } } } // no square operation if no any inner boundary if (minDist != VTK_DOUBLE_MAX) { minDist *= minDist; } closest[0] = point[0]; closest[1] = point[1]; closest[2] = point[2]; // minFace: the quad with the min distance to the point // 0: x-min face ===> xyzIndx = 0: x and minFace & 1 = 0: thisMin // 1: x-max face ===> xyzIndx = 0: x and minFace & 1 = 1: thisMax // 2: y-min face ===> xyzIndx = 1: y and minFace & 1 = 0: thisMin // 3: y-max face ===> xyzIndx = 1: y and minFace & 1 = 1: thisMax // 4: z-min face ===> xyzIndx = 2: z and minFace & 1 = 0: thisMin // 5: z-max face ===> xyzIndx = 2: z and minFace & 1 = 1: thisMax double* pMinMax[2] = { thisMin, thisMax }; int xyzIndx = (minFace >> 1); closest[xyzIndx] = pMinMax[minFace & 1][xyzIndx]; pMinMax[0] = pMinMax[1] = nullptr; break; } return minDist; } //------------------------------------------------------------------------------ double vtkIncrementalOctreeNode::GetDistance2ToBoundary( const double point[3], vtkIncrementalOctreeNode* rootNode, int checkData) { double dumbPnt[3]; return (checkData == 1 && this->GetNumberOfPoints() == 0) ? VTK_DOUBLE_MAX : this->GetDistance2ToBoundary(point, dumbPnt, 0, rootNode, checkData); } //------------------------------------------------------------------------------ double vtkIncrementalOctreeNode::GetDistance2ToBoundary( const double point[3], double closest[3], vtkIncrementalOctreeNode* rootNode, int checkData) { return (checkData == 1 && this->GetNumberOfPoints() == 0) ? VTK_DOUBLE_MAX : this->GetDistance2ToBoundary(point, closest, 0, rootNode, checkData); } //------------------------------------------------------------------------------ double vtkIncrementalOctreeNode::GetDistance2ToInnerBoundary( const double point[3], vtkIncrementalOctreeNode* rootNode) { double dumbPnt[3]; return this->GetDistance2ToBoundary(point, dumbPnt, 1, rootNode, 0); } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::ExportAllPointIdsByInsertion(vtkIdList* idList) { if (this->Children == nullptr) { for (vtkIdType localId = 0; localId < this->NumberOfPoints; localId++) { idList->InsertNextId(this->PointIdSet->GetId(localId)); } } else { for (int i = 0; i < 8; i++) { this->Children[i]->ExportAllPointIdsByInsertion(idList); } } } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::ExportAllPointIdsByDirectSet(vtkIdType* pntIdx, vtkIdList* idList) { if (this->Children == nullptr) { for (vtkIdType localId = 0; localId < this->NumberOfPoints; localId++) { idList->SetId((*pntIdx), this->PointIdSet->GetId(localId)); (*pntIdx)++; } } else { for (int i = 0; i < 8; i++) { this->Children[i]->ExportAllPointIdsByDirectSet(pntIdx, idList); } } } //------------------------------------------------------------------------------ void vtkIncrementalOctreeNode::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Index: " << this->ID << endl; os << indent << "Parent: " << this->Parent << endl; os << indent << "Children: " << this->Children << endl; os << indent << "PointIdSet: " << this->PointIdSet << endl; os << indent << "NumberOfPoints: " << this->NumberOfPoints << endl; os << indent << "MinBounds: " << this->MinBounds[0] << " " << this->MinBounds[1] << " " << this->MinBounds[2] << endl; os << indent << "MaxBounds: " << this->MaxBounds[0] << " " << this->MaxBounds[1] << " " << this->MaxBounds[2] << endl; os << indent << "MinDataBounds: " << this->MinDataBounds[0] << " " << this->MinDataBounds[1] << " " << this->MinDataBounds[2] << endl; os << indent << "MaxDataBounds: " << this->MaxDataBounds[0] << " " << this->MaxDataBounds[1] << " " << this->MaxDataBounds[2] << endl; } //------------------------------------------------------------------------------ int vtkIncrementalOctreeNode::GetNumberOfLevels() const { if (this->Children) { int maxLevel = 0; for (int i = 0; i < 8; i++) { maxLevel = std::max(maxLevel, this->Children[i]->GetNumberOfLevels()); } return maxLevel + 1; } else { return 1; } }