import macro from 'vtk.js/Sources/macros'; import vtkMath from 'vtk.js/Sources/Common/Core/Math'; import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'; import vtkIncrementalOctreeNode from 'vtk.js/Sources/Common/DataModel/IncrementalOctreeNode'; import vtkAbstractPointLocator from 'vtk.js/Sources/Common/DataModel/AbstractPointLocator'; import { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants';
const { vtkErrorMacro } = macro;
function vtkIncrementalOctreePointLocator(publicAPI, model) { model.classHierarchy.push('vtkIncrementalOctreePointLocator');
function getLeafContainer(node, pnt) { return node.isLeaf() ? node : getLeafContainer(node.getChild(node.getChildIndex(pnt)), pnt); }
publicAPI.freeSearchStructure = () => { model.octreeRootNode = null; model.numberOfNodes = 0; model.locatorPoints = null; };
publicAPI.findClosestPointInLeafNode = (leafNode, point) => { let dist2 = Number.MAX_VALUE;
if (leafNode.getPointIdSet() == null) { return [-1, dist2]; }
let numPts = 0; let tmpDst = 0.0; const tmpPnt = []; let tmpIdx = -1; let pntIdx = -1; let idList = leafNode.getPointIdSet(); numPts = idList.length;
for (let i = 0; i < numPts; i++) { tmpIdx = idList[i]; model.locatorPoints.getPoint(tmpIdx, tmpPnt); tmpDst = vtkMath.distance2BetweenPoints(tmpPnt, point); if (tmpDst < dist2) { dist2 = tmpDst; pntIdx = tmpIdx; }
if (dist2 === 0.0) { break; } }
idList = null;
return [pntIdx, dist2]; };
publicAPI.findClosestPointInSphere = (point, radius2, maskNode, refDist2) => { let pointIndx = -1; let minDist2 = Number.MAX_VALUE;
const nodesBase = []; nodesBase.push(model.octreeRootNode);
let checkNode; let childNode; let distToData; let tempDist2; let tempPntId;
while (!nodesBase.length === 0 && minDist2 > 0.0) { checkNode = nodesBase.top(); nodesBase.pop();
if (!checkNode.isLeaf()) { for (let i = 0; i < 8; i++) { childNode = checkNode.getChild(i);
distToData = childNode.getNumberOfPoints() ? childNode.getDistance2ToBoundary(point, model.octreeRootNode, 1) : radius2 + radius2;
if ( childNode !== maskNode && (distToData <= refDist2 || childNode.containsPoint(point) === 1) ) { nodesBase.push(childNode); }
childNode = null; } } else {
[tempPntId, tempDist2] = publicAPI.findClosestPointInLeafNode( checkNode, point );
if (tempDist2 < minDist2) { minDist2 = tempDist2; pointIndx = tempPntId; } }
checkNode = null; }
return [minDist2 <= radius2 ? pointIndx : -1, minDist2]; };
publicAPI.initPointInsertion = (points, bounds, estNumPts = 0) => { let i = 0; let bbIndex = 0;
if (points == null) { vtkErrorMacro('a valid vtkPoints object required for point insertion'); return false; }
publicAPI.freeSearchStructure(); model.locatorPoints = points;
model.insertTolerance2 = model.tolerance * model.tolerance;
model.octreeMaxDimSize = 0.0; const tmpBbox = [...bounds]; const dimDiff = vtkBoundingBox.getLengths(bounds); model.octreeMaxDimSize = Math.max(...dimDiff);
if (model.buildCubicOctree) { for (i = 0; i < 3; i++) { if (dimDiff[i] !== model.octreeMaxDimSize) { const delta = model.octreeMaxDimSize - dimDiff[i]; tmpBbox[2 * i] -= 0.5 * delta; tmpBbox[2 * i + 1] += 0.5 * delta; dimDiff[i] = model.octreeMaxDimSize; } } }
model.fudgeFactor = model.octreeMaxDimSize * 10e-6; const minSideSize = model.octreeMaxDimSize * 10e-2;
for (i = 0; i < 3; i++) { if (dimDiff[i] < minSideSize) { bbIndex = 2 * i; const tempVal = tmpBbox[bbIndex]; tmpBbox[bbIndex] = tmpBbox[bbIndex + 1] - minSideSize; tmpBbox[bbIndex + 1] = tempVal + minSideSize; } else { tmpBbox[2 * i] -= model.fudgeFactor; } }
model.octreeRootNode = vtkIncrementalOctreeNode.newInstance(); ++model.numberOfNodes;
model.octreeRootNode.setBounds(...tmpBbox);
return true; };
publicAPI.findClosestPointInSphereWithTolerance = ( point, radius2, maskNode ) => publicAPI.findClosestPointInSphere( point, radius2, maskNode, model.octreeMaxDimSize * model.octreeMaxDimSize * 4.0, radius2 );
publicAPI.findDuplicateFloatTypePointInVisitedLeafNode = ( leafNode, point ) => { let tmpPnt; let tmpIdx = -1; let pntIdx = -1;
const idList = leafNode.getPointIdSet(); const values = model.locatorPoints.getData();
for (let i = 0; i < idList.length; i++) { tmpIdx = idList[i]; tmpPnt = (tmpIdx << 1) + tmpIdx;
if ( point[0] === values[tmpPnt] && point[1] === values[tmpPnt + 1] && point[2] === values[tmpPnt + 2] ) { pntIdx = tmpIdx; break; } }
return pntIdx; };
publicAPI.findDuplicateDoubleTypePointInVisitedLeafNode = ( leafNode, point ) => { let tmpPnt; let tmpIdx = -1; let pntIdx = -1; const idList = leafNode.getPointIdSet();
const values = model.locatorPoints.getData();
for (let i = 0; i < idList.length; i++) { tmpIdx = idList[i]; tmpPnt = (tmpIdx << 1) + tmpIdx;
if ( point[0] === values[tmpPnt] && point[1] === values[tmpPnt + 1] && point[2] === values[tmpPnt + 2] ) { pntIdx = tmpIdx; break; } }
return pntIdx; };
publicAPI.findDuplicatePointInLeafNode = (leafNode, point) => { if (leafNode.getPointIdSet() == null) { return -1; }
return model.locatorPoints.getDataType() === VtkDataTypes.FLOAT ? publicAPI.findDuplicateFloatTypePointInVisitedLeafNode(leafNode, point) : publicAPI.findDuplicateDoubleTypePointInVisitedLeafNode( leafNode, point ); };
publicAPI.insertPoint = (ptId, x) => { const leafcontainer = getLeafContainer(model.octreeRootNode, x); ({ numberOfNodes: model.numberOfNodes } = leafcontainer.insertPoint( model.locatorPoints, x, model.maxPointsPerLeaf, ptId, 1, model.numberOfNodes )); };
publicAPI.insertUniquePoint = (point) => { let { pointIdx, leafContainer } = publicAPI.isInsertedPoint(point); if (pointIdx > -1) { return { success: false, idx: pointIdx }; } let numberOfNodes; ({ numberOfNodes, pointIdx } = leafContainer.insertPoint( model.locatorPoints, point, model.maxPointsPerLeaf, pointIdx, 2, model.numberOfNodes )); model.numberOfNodes = numberOfNodes; return { success: true, idx: pointIdx }; };
publicAPI.insertNextPoint = (x) => { const leafContainer = getLeafContainer(model.octreeRootNode, x); const { numberOfNodes, pointIdx } = leafContainer.insertPoint( model.locatorPoints, x, model.maxPointsPerLeaf, -1, 2, model.numberOfNodes ); model.numberOfNodes = numberOfNodes; return pointIdx; };
publicAPI.isInsertedPointForZeroTolerance = (x) => { const leafContainer = getLeafContainer(model.octreeRootNode, x); const pointIdx = publicAPI.findDuplicatePointInLeafNode(leafContainer, x); return { pointIdx, leafContainer }; };
publicAPI.isInsertedPointForNonZeroTolerance = (x) => { let dist2Ext; let pntIdExt;
const leafContainer = getLeafContainer(model.octreeRootNode, x); let [pointIdx, minDist2] = publicAPI.findClosestPointInLeafNode( leafContainer, x );
if (minDist2 === 0.0) { return { pointIdx, leafContainer }; }
const elseDst2 = leafContainer.getDistance2ToInnerBoundary( x, model.octreeRootNode );
if (elseDst2 < model.insertTolerance2) { pntIdExt = publicAPI.findClosestPointInSphereWithTolerance( x, model.insertTolerance2, leafContainer, dist2Ext );
if (dist2Ext < minDist2) { minDist2 = dist2Ext; pointIdx = pntIdExt; } } pointIdx = minDist2 <= model.insertTolerance2 ? pointIdx : -1; return { pointIdx, leafContainer }; };
publicAPI.isInsertedPoint = (x, leafContainer) => model.insertTolerance2 === 0.0 ? publicAPI.isInsertedPointForZeroTolerance(x, leafContainer) : publicAPI.isInsertedPointForNonZeroTolerance(x, leafContainer); }
function defaultValues(initialValues) { return { fudgeFactor: 0, octreeMaxDimSize: 0, buildCubicOctree: false, maxPointsPerLeaf: 128, insertTolerance2: 0.000001, locatorPoints: null, octreeRootNode: null, numberOfNodes: 0, ...initialValues, }; }
export function extend(publicAPI, model, initialValues = {}) { vtkAbstractPointLocator.extend( publicAPI, model, defaultValues(initialValues) );
macro.obj(publicAPI, model);
macro.setGet(publicAPI, model, [ 'fudgeFactor', 'octreeMaxDimSize', 'buildCubicOctree', 'maxPointsPerLeaf', 'insertTolerance2', 'locatorPoints', 'octreeRootNode', 'numberOfNodes', ]);
vtkIncrementalOctreePointLocator(publicAPI, model); }
export const newInstance = macro.newInstance( extend, 'vtkIncrementalOctreePointLocator' );
export default { newInstance, extend };
|