import { vec3, mat4 } from 'gl-matrix'; import macro from 'vtk.js/Sources/macros'; import vtkCompositeCameraManipulator from 'vtk.js/Sources/Interaction/Manipulators/CompositeCameraManipulator'; import vtkCompositeMouseManipulator from 'vtk.js/Sources/Interaction/Manipulators/CompositeMouseManipulator'; import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
function vtkMouseCameraAxisRotateManipulator(publicAPI, model) { model.classHierarchy.push('vtkMouseCameraAxisRotateManipulator');
const negCameraDir = new Float64Array(3); const newCamPos = new Float64Array(3); const newFp = new Float64Array(3); const newViewUp = new Float64Array(3); const trans = new Float64Array(16); const rotation = new Float64Array(16); const v2 = new Float64Array(3); const centerNeg = new Float64Array(3); const negRotationAxis = new Float64Array(3);
publicAPI.onButtonDown = (interactor, renderer, position) => { model.previousPosition = position; };
publicAPI.onMouseMove = (interactor, renderer, position) => { if (!position) { return; }
const camera = renderer.getActiveCamera(); const cameraPos = camera.getPosition(); const cameraFp = camera.getFocalPoint(); const cameraViewUp = camera.getViewUp(); const cameraDirection = camera.getDirectionOfProjection(); vec3.negate(negCameraDir, cameraDirection);
mat4.identity(trans); mat4.identity(rotation);
const { center, rotationFactor, rotationAxis } = model; vec3.negate(negRotationAxis, rotationAxis);
const dx = model.previousPosition.x - position.x; const dy = model.previousPosition.y - position.y;
const size = interactor.getView().getViewportSize(renderer);
const azimuthDelta = vtkMath.radiansFromDegrees( ((360.0 * dx) / size[0]) * rotationFactor ); mat4.rotate(rotation, rotation, azimuthDelta, rotationAxis);
vtkMath.cross(cameraDirection, cameraViewUp, v2); let elevationDelta = vtkMath.radiansFromDegrees( ((-360.0 * dy) / size[1]) * rotationFactor ); const angleToPosHalf = Math.acos(vec3.dot(negCameraDir, rotationAxis)); const angleToNegHalf = Math.acos(vec3.dot(negCameraDir, negRotationAxis));
const inPosHalf = angleToPosHalf <= angleToNegHalf; const elevationToAxis = Math.min(angleToPosHalf, angleToNegHalf);
if (model.useHalfAxis && !inPosHalf) { elevationDelta = Math.PI / 2 - angleToPosHalf; } else if (inPosHalf && elevationToAxis + elevationDelta < 0) { elevationDelta = -elevationToAxis; } else if (!inPosHalf && angleToPosHalf + elevationDelta > Math.PI) { elevationDelta = elevationToAxis; }
mat4.rotate(rotation, rotation, elevationDelta, v2);
mat4.translate(trans, trans, center);
mat4.multiply(trans, trans, rotation);
vec3.negate(centerNeg, center); mat4.translate(trans, trans, centerNeg);
vec3.transformMat4(newCamPos, cameraPos, trans); vec3.transformMat4(newFp, cameraFp, trans);
vec3.transformMat4(newViewUp, cameraViewUp, rotation);
camera.setPosition(newCamPos[0], newCamPos[1], newCamPos[2]); camera.setFocalPoint(newFp[0], newFp[1], newFp[2]); camera.setViewUp(newViewUp);
renderer.resetCameraClippingRange();
if (interactor.getLightFollowCamera()) { renderer.updateLightsGeometryToFollowCamera(); }
model.previousPosition = position; }; }
const DEFAULT_VALUES = { rotationAxis: [0, 0, 1], useHalfAxis: true, };
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
macro.obj(publicAPI, model); macro.setGet(publicAPI, model, ['rotationAxis', 'useHalfAxis']); vtkCompositeMouseManipulator.extend(publicAPI, model, initialValues); vtkCompositeCameraManipulator.extend(publicAPI, model, initialValues);
vtkMouseCameraAxisRotateManipulator(publicAPI, model); }
export const newInstance = macro.newInstance( extend, 'vtkMouseCameraAxisRotateManipulator' );
export default { newInstance, extend };
|