import { mat4, quat, vec3 } from 'gl-matrix'; import CoincidentTopologyHelper from 'vtk.js/Sources/Rendering/Core/Mapper/CoincidentTopologyHelper'; import vtkAbstractImageMapper from 'vtk.js/Sources/Rendering/Core/AbstractImageMapper'; import macro from 'vtk.js/Sources/macros'; import vtkPoints from 'vtk.js/Sources/Common/Core/Points'; import vtkPolyLine from 'vtk.js/Sources/Common/DataModel/PolyLine'; import { ProjectionMode } from './Constants';
const { vtkErrorMacro } = macro;
const { staticOffsetAPI, otherStaticMethods } = CoincidentTopologyHelper;
function vtkImageCPRMapper(publicAPI, model) { model.classHierarchy.push('vtkImageCPRMapper');
const superClass = { ...publicAPI };
publicAPI.getBounds = () => { const imageWidth = publicAPI.getWidth(); const imageHeight = publicAPI.getHeight(); return [0, imageWidth, 0, imageHeight, 0, 0]; };
publicAPI.getOrientationDataArray = () => { const pointData = publicAPI.getInputData(1)?.getPointData(); if (!pointData) { return null; } if (model.orientationArrayName !== null) { return pointData.getArrayByName(model.orientationArrayName) || null; } return ( pointData.getArrayByName('Orientation') || pointData.getArrayByName('Direction') || pointData.getVectors() || pointData.getTensors() || pointData.getNormals() || null ); };
publicAPI.getOrientedCenterline = () => { const inputPolydata = publicAPI.getInputData(1); if (!inputPolydata) { return model._orientedCenterline; }
const orientationDataArray = publicAPI.getOrientationDataArray(); const linesDataArray = inputPolydata.getLines(); const pointsDataArray = inputPolydata.getPoints();
if (!model.useUniformOrientation && !orientationDataArray) { vtkErrorMacro( 'Failed to create oriented centerline from polydata: no orientation' ); publicAPI._resetOrientedCenterline(); return model._orientedCenterline; }
const centerlineTime = model._orientedCenterline.getMTime(); if ( centerlineTime >= publicAPI.getMTime() && centerlineTime > linesDataArray.getMTime() && centerlineTime > pointsDataArray.getMTime() && (model.useUniformOrientation || centerlineTime > orientationDataArray.getMTime()) ) { return model._orientedCenterline; }
const linesData = linesDataArray.getData(); if (linesData.length <= 0) { publicAPI._resetOrientedCenterline(); return model._orientedCenterline; } const nPoints = linesData[0]; if (nPoints <= 1) { publicAPI._resetOrientedCenterline(); return model._orientedCenterline; } const pointIndices = linesData.subarray(1, 1 + nPoints);
const orientations = new Array(nPoints); let convert = () => null; const numComps = model.useUniformOrientation ? model.uniformOrientation.length : orientationDataArray.getNumberOfComponents(); switch (numComps) { case 16: convert = (outQuat, inMat) => { mat4.getRotation(outQuat, inMat); quat.normalize(outQuat, outQuat); }; break; case 9: convert = (outQuat, inMat) => { quat.fromMat3(outQuat, inMat); quat.normalize(outQuat, outQuat); }; break; case 4: convert = quat.copy; break; case 3: convert = (a, b) => quat.rotationTo(a, model.tangentDirection, b); break; default: vtkErrorMacro('Orientation doesnt match mat4, mat3, quat or vec3'); publicAPI._resetOrientedCenterline(); return model._orientedCenterline; } let getOrientation = () => null; if (model.useUniformOrientation) { const outQuat = new Float64Array(4); convert(outQuat, model.uniformOrientation); getOrientation = () => outQuat; } else { const temp = new Float64Array(16); getOrientation = (i) => { const outQuat = new Float64Array(4); orientationDataArray.getTuple(i, temp); convert(outQuat, temp); return outQuat; }; } for (let i = 0; i < nPoints; ++i) { const pointIdx = pointIndices[i]; orientations[i] = getOrientation(pointIdx); }
model._orientedCenterline.initialize(pointsDataArray, pointIndices); model._orientedCenterline.setOrientations(orientations); return model._orientedCenterline; };
publicAPI.setOrientedCenterline = (centerline) => { if (model._orientedCenterline !== centerline) { model._orientedCenterline = centerline; return true; } return false; };
publicAPI._resetOrientedCenterline = () => { model._orientedCenterline.initialize(vtkPoints.newInstance()); model._orientedCenterline.setOrientations([]); };
publicAPI.getMTime = () => { let mTime = superClass.getMTime(); if (!model._orientedCenterline) { return mTime; }
mTime = Math.max(mTime, model._orientedCenterline.getMTime()); return mTime; };
publicAPI.getHeight = () => { const accHeights = publicAPI .getOrientedCenterline() .getDistancesToFirstPoint(); if (accHeights.length === 0) { return 0; } return accHeights[accHeights.length - 1]; };
publicAPI.getCenterlinePositionAndOrientation = (distance) => { const centerline = publicAPI.getOrientedCenterline(); const subId = centerline.findPointIdAtDistanceFromFirstPoint(distance); if (subId < 0) { return {}; } const distances = centerline.getDistancesToFirstPoint(); const pcoords = [ (distance - distances[subId]) / (distances[subId + 1] - distances[subId]), ]; const weights = new Array(2);
const position = new Array(3); centerline.evaluateLocation(subId, pcoords, position, weights);
const orientation = new Array(4); if (!centerline.evaluateOrientation(subId, pcoords, orientation, weights)) { return { position }; } return { position, orientation }; };
publicAPI.getCenterlineTangentDirections = () => { const centerline = publicAPI.getOrientedCenterline(); const directionsTime = model._centerlineTangentDirectionsTime.getMTime(); if (directionsTime < centerline.getMTime()) { const orientations = centerline.getOrientations(); model._centerlineTangentDirections = new Float32Array( 3 * orientations.length ); const localDirection = new Array(3); for (let i = 0; i < orientations.length; ++i) { vec3.transformQuat( localDirection, model.tangentDirection, orientations[i] ); model._centerlineTangentDirections.set(localDirection, 3 * i); } model._centerlineTangentDirectionsTime.modified(); } return model._centerlineTangentDirections; };
publicAPI.getUniformDirection = () => vec3.transformQuat( new Array(3), model.tangentDirection, model.uniformOrientation );
publicAPI.getDirectionMatrix = () => { const tangent = model.tangentDirection; const bitangent = model.bitangentDirection; const normal = model.normalDirection; return new Float64Array([ tangent[0], tangent[1], tangent[2], bitangent[0], bitangent[1], bitangent[2], normal[0], normal[1], normal[2], ]); };
publicAPI.setDirectionMatrix = (mat) => { if (mat4.equals(mat, publicAPI.getDirectionMatrix())) { return false; } model.tangentDirection = [mat[0], mat[1], mat[2]]; model.bitangentDirection = [mat[3], mat[4], mat[5]]; model.normalDirection = [mat[6], mat[7], mat[8]]; publicAPI.modified(); return true; };
publicAPI.preRenderCheck = () => { if (!publicAPI.getInputData(0)) { vtkErrorMacro('No image data input'); return false; } return true; };
publicAPI.useStraightenedMode = () => { publicAPI.setCenterPoint(null); publicAPI.setUseUniformOrientation(false); publicAPI.getOrientedCenterline().setDistanceFunction(vec3.dist); };
publicAPI.useStretchedMode = (centerPoint) => { const centerline = publicAPI.getOrientedCenterline(); if (!centerPoint) { const centerlinePoints = centerline.getPoints(); const newCenterPoint = centerlinePoints.getNumberOfTuples() > 0 ? centerlinePoints.getPoint(0) : [0, 0, 0]; publicAPI.setCenterPoint(newCenterPoint); } else { publicAPI.setCenterPoint(centerPoint); } publicAPI.setUseUniformOrientation(true); centerline.setDistanceFunction((a, b) => { const direction = publicAPI.getUniformDirection(); const vec = vec3.subtract([], a, b); const d2 = vec3.squaredLength(vec); const x = vec3.dot(direction, vec); return Math.sqrt(d2 - x * x); }); };
publicAPI.isProjectionEnabled = () => model.projectionSlabNumberOfSamples > 1;
publicAPI.setCenterlineData = (centerlineData) => publicAPI.setInputData(centerlineData, 1);
publicAPI.setCenterlineConnection = (centerlineConnection) => publicAPI.setInputConnection(centerlineConnection, 1);
publicAPI.setImageData = (imageData) => publicAPI.setInputData(imageData, 0);
publicAPI.setImageConnection = (imageData) => publicAPI.setInputConnection(imageData, 0);
publicAPI.getIsOpaque = () => true;
model._orientedCenterline = vtkPolyLine.newInstance(); publicAPI._resetOrientedCenterline(); }
const DEFAULT_VALUES = { width: 10, uniformOrientation: [0, 0, 0, 1], useUniformOrientation: false, centerPoint: null, preferSizeOverAccuracy: false, orientationArrayName: null, tangentDirection: [1, 0, 0], bitangentDirection: [0, 1, 0], normalDirection: [0, 0, 1], projectionSlabThickness: 1, projectionSlabNumberOfSamples: 1, projectionMode: ProjectionMode.MAX, };
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
vtkAbstractImageMapper.extend(publicAPI, model, initialValues);
macro.algo(publicAPI, model, 2, 0);
model._centerlineTangentDirectionsTime = {}; macro.obj(model._centerlineTangentDirectionsTime, { mtime: 0 });
macro.setGet(publicAPI, model, [ 'width', 'uniformOrientation', 'useUniformOrientation', 'centerPoint', 'preferSizeOverAccuracy', 'orientationArrayName', 'tangentDirection', 'bitangentDirection', 'normalDirection', 'projectionSlabThickness', 'projectionSlabNumberOfSamples', 'projectionMode', ]); CoincidentTopologyHelper.implementCoincidentTopologyMethods(publicAPI, model);
vtkImageCPRMapper(publicAPI, model); }
export const newInstance = macro.newInstance(extend, 'vtkImageCPRMapper');
export default { newInstance, extend, ...staticOffsetAPI, ...otherStaticMethods, };
|