@kitware/vtk.js
Version:
Visualization Toolkit for the Web
123 lines (108 loc) • 4.62 kB
JavaScript
import { m as macro } from '../../macros2.js';
import vtkPlane from '../../Common/DataModel/Plane.js';
import vtkAbstractManipulator from './AbstractManipulator.js';
import { mat4, vec3, mat3 } from 'gl-matrix';
function intersectDisplayWithPlane(x, y, planeOrigin, planeNormal, renderer, glRenderWindow) {
const near = glRenderWindow.displayToWorld(x, y, 0, renderer);
const far = glRenderWindow.displayToWorld(x, y, 1, renderer);
return vtkPlane.intersectWithLine(near, far, planeOrigin, planeNormal).x;
}
// ----------------------------------------------------------------------------
// vtkCPRManipulator methods
// ----------------------------------------------------------------------------
function vtkCPRManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkCPRManipulator');
publicAPI.handleEvent = (callData, glRenderWindow) => {
const mapper = model.cprActor?.getMapper();
if (!mapper) {
return model._addWorldDeltas({
worldCoords: null
});
}
// Get normal and origin of the picking plane from the actor matrix
const cprActorMatrix = [];
mat4.transpose(cprActorMatrix, model.cprActor.getMatrix());
const worldPlaneNormal = cprActorMatrix.slice(8, 11); // 3rd column
const worldPlaneOrigin = cprActorMatrix.slice(12, 15); // 4th column
// Convert world plane position to 2D position in the plane
const inversecprActorMatrix = [];
mat4.invert(inversecprActorMatrix, cprActorMatrix);
const worldPlanePicking = intersectDisplayWithPlane(callData.position.x, callData.position.y, worldPlaneOrigin, worldPlaneNormal, callData.pokedRenderer, glRenderWindow);
const modelPlanePicking = []; // (x, height - distance, 0)
vec3.transformMat4(modelPlanePicking, worldPlanePicking, inversecprActorMatrix);
const height = mapper.getHeight();
const distance = height - modelPlanePicking[1];
return model._addWorldDeltas(publicAPI.distanceEvent(distance));
};
publicAPI.distanceEvent = distance => {
const mapper = model.cprActor?.getMapper();
if (!mapper) {
return {
worldCoords: null
};
}
const height = mapper.getHeight();
const clampedDistance = Math.max(0, Math.min(height, distance));
const {
position,
orientation
} = mapper.getCenterlinePositionAndOrientation(clampedDistance);
let worldDirection;
if (orientation) {
const modelDirections = mat3.fromQuat([], orientation);
const baseDirections = mapper.getDirectionMatrix();
worldDirection = mat3.mul([], modelDirections, baseDirections);
}
model.currentDistance = clampedDistance;
return {
worldCoords: position,
worldDirection
};
};
publicAPI.handleScroll = nbSteps => {
const distance = model.currentDistance + publicAPI.getDistanceStep() * nbSteps;
return publicAPI.distanceEvent(distance);
};
publicAPI.getDistanceStep = () => {
// Find default distanceStep from image spacing
// This only works if the mapper in the actor already has an ImageData
if (!model.distanceStep) {
const imageSpacing = model.cprActor?.getMapper()?.getInputData(0)?.getSpacing?.();
if (imageSpacing) {
return Math.min(...imageSpacing);
}
}
return model.distanceStep;
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
// currentDistance is the distance from the first point of the centerline
// cprActor.getMapper() should be a vtkImageCPRMapper
function defaultValues(initialValues) {
return {
distanceStep: 0,
currentDistance: 0,
cprActor: null,
...initialValues
};
}
// ----------------------------------------------------------------------------
function extend(publicAPI, model) {
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
vtkAbstractManipulator.extend(publicAPI, model, defaultValues(initialValues));
macro.setGet(publicAPI, model, ['distance', 'currentDistance', 'cprActor']);
macro.set(publicAPI, model, ['distanceStep']);
vtkCPRManipulator(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkCPRManipulator');
// ----------------------------------------------------------------------------
var index = {
intersectDisplayWithPlane,
extend,
newInstance
};
export { index as default, extend, intersectDisplayWithPlane, newInstance };