@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
372 lines (298 loc) • 15.5 kB
JavaScript
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import vtkActor from '../../Rendering/Core/Actor.js';
import vtkCompositeCameraManipulator from './CompositeCameraManipulator.js';
import vtkCompositeMouseManipulator from './CompositeMouseManipulator.js';
import vtkInteractorStyleConstants from '../../Rendering/Core/InteractorStyle/Constants.js';
import vtkMapper from '../../Rendering/Core/Mapper.js';
import vtkPointPicker from '../../Rendering/Core/PointPicker.js';
import vtkSphereSource from '../../Filters/Sources/SphereSource.js';
import { FieldAssociations } from '../../Common/DataModel/DataSet/Constants.js';
import macro from '../../macro.js';
import { z as areEquals, l as normalize, d as dot, A as clampValue, g as subtract, j as cross, t as multiplyScalar, f as distance2BetweenPoints } from '../../Common/Core/Math/index.js';
import { i as identity, t as translate, r as rotate } from '../../vendor/gl-matrix/esm/mat4.js';
import { t as transformMat4 } from '../../vendor/gl-matrix/esm/vec3.js';
var States = vtkInteractorStyleConstants.States; // ----------------------------------------------------------------------------
// vtkMouseCameraUnicamRotateManipulator methods
// ----------------------------------------------------------------------------
function vtkMouseCameraUnicamRotateManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkMouseCameraUnicamRotateManipulator'); // Setup Picker to pick points
model.picker = vtkPointPicker.newInstance();
model.downPoint = [0, 0, 0];
model.isDot = false;
model.state = States.IS_NONE; // Setup focus dot
var sphereSource = vtkSphereSource.newInstance();
sphereSource.setThetaResolution(6);
sphereSource.setPhiResolution(6);
var sphereMapper = vtkMapper.newInstance();
sphereMapper.setInputConnection(sphereSource.getOutputPort());
model.focusSphere = vtkActor.newInstance();
model.focusSphere.setMapper(sphereMapper);
model.focusSphere.getProperty().setColor(0.89, 0.66, 0.41);
model.focusSphere.getProperty().setAmbient(1);
model.focusSphere.getProperty().setDiffuse(0);
model.focusSphere.getProperty().setRepresentationToWireframe(); //----------------------------------------------------------------------------
var updateAndRender = function updateAndRender(interactor) {
if (!interactor) {
return;
}
if (model.useWorldUpVec) {
var camera = interactor.findPokedRenderer().getActiveCamera();
if (!areEquals(model.worldUpVec, camera.getViewPlaneNormal())) {
camera.setViewUp(model.worldUpVec);
}
}
interactor.render();
}; //----------------------------------------------------------------------------
var normalize$1 = function normalize(position, interactor) {
var _interactor$getView$g = interactor.getView().getSize(),
_interactor$getView$g2 = _slicedToArray(_interactor$getView$g, 2),
width = _interactor$getView$g2[0],
height = _interactor$getView$g2[1];
var nx = -1.0 + 2.0 * position.x / width;
var ny = -1.0 + 2.0 * position.y / height;
return {
x: nx,
y: ny
};
}; //----------------------------------------------------------------------------
// Rotate the camera by 'angle' degrees about the point <cx, cy, cz>
// and around the vector/axis <ax, ay, az>.
var rotateCamera = function rotateCamera(camera, cx, cy, cz, ax, ay, az, angle) {
var cameraPosition = camera.getPosition();
var cameraFocalPoint = camera.getFocalPoint();
var cameraViewUp = camera.getViewUp();
cameraPosition[3] = 1.0;
cameraFocalPoint[3] = 1.0;
cameraViewUp[3] = 0.0;
var transform = identity(new Float64Array(16));
translate(transform, transform, [cx, cy, cz]);
rotate(transform, transform, angle, [ax, ay, az]);
translate(transform, transform, [-cx, -cy, -cz]);
var newCameraPosition = [];
var newCameraFocalPoint = [];
transformMat4(newCameraPosition, cameraPosition, transform);
transformMat4(newCameraFocalPoint, cameraFocalPoint, transform);
identity(transform);
rotate(transform, transform, angle, [ax, ay, az]);
var newCameraViewUp = [];
transformMat4(newCameraViewUp, cameraViewUp, transform);
camera.setPosition.apply(camera, newCameraPosition);
camera.setFocalPoint.apply(camera, newCameraFocalPoint);
camera.setViewUp.apply(camera, newCameraViewUp);
}; //----------------------------------------------------------------------------
var rotate$1 = function rotate(interactor, position) {
var _interactor$getView;
var renderer = interactor.findPokedRenderer();
var normalizedPosition = normalize$1(position, interactor);
var normalizedPreviousPosition = normalize$1(model.previousPosition, interactor);
var center = model.focusSphere.getPosition();
var normalizedCenter = (_interactor$getView = interactor.getView()).worldToDisplay.apply(_interactor$getView, _toConsumableArray(center).concat([renderer])); // let normalizedCenter = publicAPI.computeWorldToDisplay(renderer, ...center);
normalizedCenter = normalize$1({
x: center[0],
y: center[1]
}, interactor);
normalizedCenter = [normalizedCenter.x, normalizedCenter.y, center[2]]; // Squared rad of virtual cylinder
var radsq = Math.pow(1.0 + Math.abs(normalizedCenter[0]), 2.0);
var op = [normalizedPreviousPosition.x, 0, 0];
var oe = [normalizedPosition.x, 0, 0];
var opsq = Math.pow(op[0], 2);
var oesq = Math.pow(oe[0], 2);
var lop = opsq > radsq ? 0 : Math.sqrt(radsq - opsq);
var loe = oesq > radsq ? 0 : Math.sqrt(radsq - oesq);
var nop = [op[0], 0, lop];
normalize(nop);
var noe = [oe[0], 0, loe];
normalize(noe);
var dot$1 = dot(nop, noe);
if (Math.abs(dot$1) > 0.0001) {
var angle = -2 * Math.acos(clampValue(dot$1, -1.0, 1.0)) * Math.sign(normalizedPosition.x - normalizedPreviousPosition.x) * publicAPI.getRotationFactor();
var camera = renderer.getActiveCamera();
var upVec = model.useWorldUpVec ? model.worldUpVec : camera.getViewUp();
normalize(upVec);
rotateCamera.apply(void 0, [camera].concat(_toConsumableArray(center), _toConsumableArray(upVec), [angle]));
var dVec = [];
var cameraPosition = camera.getPosition();
subtract(cameraPosition, position, dVec);
var rDist = (normalizedPosition.y - normalizedPreviousPosition.y) * publicAPI.getRotationFactor();
normalize(dVec);
var atV = camera.getViewPlaneNormal();
var upV = camera.getViewUp();
var rightV = [];
cross(upV, atV, rightV);
normalize(rightV); //
// The following two tests try to prevent chaotic camera movement
// that results from rotating over the poles defined by the
// "WorldUpVector". The problem is the constraint to keep the
// camera's up vector in line w/ the WorldUpVector is at odds with
// the action of rotating over the top of the virtual sphere used
// for rotation. The solution here is to prevent the user from
// rotating the last bit required to "go over the top"-- as a
// consequence, you can never look directly down on the poles.
//
// The "0.99" value is somewhat arbitrary, but seems to produce
// reasonable results. (Theoretically, some sort of clamping
// function could probably be used rather than a hard cutoff, but
// time constraints prevent figuring that out right now.)
//
if (model.useWorldUpVec) {
var OVER_THE_TOP_THRESHOLD = 0.99;
if (dot(upVec, atV) > OVER_THE_TOP_THRESHOLD && rDist < 0) {
rDist = 0;
}
if (dot(upVec, atV) < -OVER_THE_TOP_THRESHOLD && rDist > 0) {
rDist = 0;
}
}
rotateCamera.apply(void 0, [camera].concat(_toConsumableArray(center), rightV, [rDist]));
if (model.useWorldUpVec && !areEquals(upVec, camera.getViewPlaneNormal())) {
camera.setViewUp.apply(camera, _toConsumableArray(upVec));
}
model.previousPosition = position;
renderer.resetCameraClippingRange();
updateAndRender(interactor);
}
}; //----------------------------------------------------------------------------
var placeFocusSphere = function placeFocusSphere(interactor) {
var _model$focusSphere;
var renderer = interactor.findPokedRenderer();
(_model$focusSphere = model.focusSphere).setPosition.apply(_model$focusSphere, _toConsumableArray(model.downPoint));
var camera = renderer.getActiveCamera();
var cameraPosition = camera.getPosition();
var cameraToPointVec = [];
subtract(model.downPoint, cameraPosition, cameraToPointVec);
if (camera.getParallelProjection()) {
multiplyScalar(cameraToPointVec, camera.getParallelScale());
}
var atV = camera.getDirectionOfProjection();
normalize(atV); // Scales the focus dot so it always appears the same size
var scale = 0.02 * dot(atV, cameraToPointVec) * model.focusSphereRadiusFactor;
model.focusSphere.setScale(scale, scale, scale);
};
var placeAndDisplayFocusSphere = function placeAndDisplayFocusSphere(interactor) {
placeFocusSphere(interactor);
interactor.findPokedRenderer().addActor(model.focusSphere);
model.isDot = true;
};
var hideFocusSphere = function hideFocusSphere(interactor) {
interactor.findPokedRenderer().removeActor(model.focusSphere);
model.isDot = false;
}; //----------------------------------------------------------------------------
var pickWithPointPicker = function pickWithPointPicker(interactor, position) {
var renderer = interactor.findPokedRenderer();
model.picker.pick([position.x, position.y, position.z], renderer);
var pickedPositions = model.picker.getPickedPositions();
if (pickedPositions.length === 0) {
return model.picker.getPickPosition();
}
var cameraPosition = renderer.getActiveCamera().getPosition();
pickedPositions.sort(function (pointA, pointB) {
return distance2BetweenPoints(pointA, cameraPosition) - distance2BetweenPoints(pointB, cameraPosition);
});
return pickedPositions[0];
}; //----------------------------------------------------------------------------
var pickPoint = function pickPoint(interactor, position) {
var renderer = interactor.findPokedRenderer(); // Finds the point under the cursor.
// Note: If no object has been rendered to the pixel (X, Y), then
// vtkPicker will return a z-value with depth equal
// to the distance from the camera's position to the focal point.
// This seems like an arbitrary, but perhaps reasonable, default value.
var selections = null;
if (model.useHardwareSelector) {
var selector = interactor.getView().getSelector();
selector.setCaptureZValues(true);
selector.setFieldAssociation(FieldAssociations.FIELD_ASSOCIATION_POINTS);
selector.attach(interactor.getView(), renderer);
selector.setArea(position.x, position.y, position.x, position.y);
selections = selector.select();
}
if (selections && selections.length !== 0) {
// convert Float64Array to regular array
return Array.from(selections[0].getProperties().worldPosition);
}
return pickWithPointPicker(interactor, position);
}; //----------------------------------------------------------------------------
// Public API methods
//----------------------------------------------------------------------------
publicAPI.onButtonDown = function (interactor, renderer, position) {
model.buttonPressed = true;
model.startPosition = position;
model.previousPosition = position;
var normalizedPosition = normalize$1(position, interactor); // borderRatio defines the percentage of the screen size that is considered to be
// the border of the screen on each side
var borderRatio = 0.1; // If the user is clicking on the perimeter of the screen,
// then we want to go into rotation mode, and there is no need to determine the downPoint
if (Math.abs(normalizedPosition.x) > 1 - borderRatio || Math.abs(normalizedPosition.y) > 1 - borderRatio) {
model.state = States.IS_ROTATE;
placeAndDisplayFocusSphere(interactor);
return;
}
model.downPoint = pickPoint(interactor, position);
if (model.isDot) {
model.state = States.IS_ROTATE;
} else {
model.state = States.IS_NONE;
if (model.displayFocusSphereOnButtonDown) {
placeAndDisplayFocusSphere(interactor);
}
}
}; //----------------------------------------------------------------------------
publicAPI.onMouseMove = function (interactor, renderer, position) {
if (!model.buttonPressed) {
return;
}
model.state = States.IS_ROTATE;
rotate$1(interactor, position);
model.previousPosition = position;
}; //--------------------------------------------------------------------------
publicAPI.onButtonUp = function (interactor) {
var renderer = interactor.findPokedRenderer();
model.buttonPressed = false; // If rotation without a focus sphere, nothing to do
if (model.state === States.IS_ROTATE && !model.isDot) {
return;
}
if (model.state === States.IS_ROTATE) {
hideFocusSphere(interactor);
} else if (model.state === States.IS_NONE) {
placeAndDisplayFocusSphere(interactor);
}
renderer.resetCameraClippingRange();
updateAndRender(interactor);
};
publicAPI.getFocusSphereColor = function () {
model.focusSphere.getProperty().getColor();
};
publicAPI.setFocusSphereColor = function (r, g, b) {
model.focusSphere.getProperty().setColor(r, g, b);
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
focusSphereRadiusFactor: 1,
displayFocusSphereOnButtonDown: true,
useHardwareSelector: true,
useWorldUpVec: true,
// set WorldUpVector to be z-axis by default
worldUpVec: [0, 0, 1]
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
macro.obj(publicAPI, model);
vtkCompositeCameraManipulator.extend(publicAPI, model, initialValues);
vtkCompositeMouseManipulator.extend(publicAPI, model, initialValues); // Create get-set macros
macro.setGet(publicAPI, model, ['focusSphereRadiusFactor', 'displayFocusSphereOnButtonDown', 'useHardwareSelector', 'useWorldUpVec']);
macro.get(publicAPI, model, ['state']);
macro.getArray(publicAPI, model, ['downPoint'], 3);
macro.setGetArray(publicAPI, model, ['worldUpVec'], 3); // Object specific methods
vtkMouseCameraUnicamRotateManipulator(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend, 'vtkMouseCameraUnicamRotateManipulator'); // ----------------------------------------------------------------------------
var vtkMouseCameraUnicamRotateManipulator$1 = {
newInstance: newInstance,
extend: extend
};
export default vtkMouseCameraUnicamRotateManipulator$1;
export { extend, newInstance };