@kitware/vtk.js
Version:
Visualization Toolkit for the Web
287 lines (264 loc) • 9.79 kB
JavaScript
import { mat4, quat } from 'gl-matrix';
import { m as macro } from '../../macros2.js';
import vtkBoundingBox from '../../Common/DataModel/BoundingBox.js';
import { B as degreesFromRadians, r as radiansFromDegrees, a as areMatricesEqual } from '../../Common/Core/Math/index.js';
import vtkProp from './Prop.js';
const VTK_EPSILON = 1e-6;
// ----------------------------------------------------------------------------
// vtkProp3D methods
// ----------------------------------------------------------------------------
function vtkProp3D(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkProp3D');
publicAPI.addPosition = deltaXYZ => {
model.position = model.position.map((value, index) => value + deltaXYZ[index]);
publicAPI.modified();
};
publicAPI.getOrientationWXYZ = () => {
const q = quat.create();
mat4.getRotation(q, model.rotation);
const oaxis = new Float64Array(3);
const w = quat.getAxisAngle(oaxis, q);
return [degreesFromRadians(w), oaxis[0], oaxis[1], oaxis[2]];
};
publicAPI.getOrientationQuaternion = function () {
let out = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return mat4.getRotation(out, model.rotation);
};
publicAPI.rotateX = val => {
if (val === 0.0) {
return;
}
mat4.rotateX(model.rotation, model.rotation, radiansFromDegrees(val));
publicAPI.modified();
};
publicAPI.rotateY = val => {
if (val === 0.0) {
return;
}
mat4.rotateY(model.rotation, model.rotation, radiansFromDegrees(val));
publicAPI.modified();
};
publicAPI.rotateZ = val => {
if (val === 0.0) {
return;
}
mat4.rotateZ(model.rotation, model.rotation, radiansFromDegrees(val));
publicAPI.modified();
};
publicAPI.rotateWXYZ = (degrees, x, y, z) => {
if (degrees === 0.0 || x === 0.0 && y === 0.0 && z === 0.0) {
return;
}
// convert to radians
const angle = radiansFromDegrees(degrees);
const q = quat.create();
quat.setAxisAngle(q, [x, y, z], angle);
const quatMat = new Float64Array(16);
mat4.fromQuat(quatMat, q);
mat4.multiply(model.rotation, model.rotation, quatMat);
publicAPI.modified();
};
publicAPI.rotateQuaternion = orientationQuaternion => {
if (Math.abs(orientationQuaternion[3]) >= 1 - VTK_EPSILON) {
return;
}
const oriQuatMat = mat4.fromQuat(new Float64Array(16), orientationQuaternion);
mat4.multiply(model.rotation, model.rotation, oriQuatMat);
publicAPI.modified();
};
publicAPI.setOrientation = (x, y, z) => {
if (x === model.orientation[0] && y === model.orientation[1] && z === model.orientation[2]) {
return false;
}
model.orientation = [x, y, z];
mat4.identity(model.rotation);
publicAPI.rotateZ(z);
publicAPI.rotateX(x);
publicAPI.rotateY(y);
publicAPI.modified();
return true;
};
publicAPI.setOrientationFromQuaternion = q => {
const rotation = mat4.create();
mat4.fromQuat(rotation, q);
if (!areMatricesEqual(rotation, model.rotation)) {
model.rotation = rotation;
publicAPI.modified();
return true;
}
return false;
};
publicAPI.setUserMatrix = matrix => {
if (areMatricesEqual(model.userMatrix, matrix)) {
return false;
}
mat4.copy(model.userMatrix, matrix);
publicAPI.modified();
return true;
};
publicAPI.getMatrix = () => {
publicAPI.computeMatrix();
return model.matrix;
};
publicAPI.computeMatrix = () => {
// check whether or not need to rebuild the matrix
if (publicAPI.getMTime() > model.matrixMTime.getMTime()) {
mat4.identity(model.matrix);
if (model.userMatrix) {
mat4.multiply(model.matrix, model.matrix, model.userMatrix);
}
mat4.translate(model.matrix, model.matrix, model.origin);
mat4.translate(model.matrix, model.matrix, model.position);
mat4.multiply(model.matrix, model.matrix, model.rotation);
mat4.scale(model.matrix, model.matrix, model.scale);
mat4.translate(model.matrix, model.matrix, [-model.origin[0], -model.origin[1], -model.origin[2]]);
mat4.transpose(model.matrix, model.matrix);
// check for identity
model.isIdentity = true;
for (let i = 0; i < 4; ++i) {
for (let j = 0; j < 4; ++j) {
if ((i === j ? 1.0 : 0.0) !== model.matrix[i + j * 4]) {
model.isIdentity = false;
}
}
}
model.matrixMTime.modified();
}
};
publicAPI.getBoundsByReference = () => {
if (model.mapper === null) {
return model.bounds;
}
// Check for the special case when the mapper's bounds are unknown
const bds = model.mapper.getBounds();
if (!bds || bds.length !== 6) {
return bds;
}
// Check for the special case when the actor is empty.
if (bds[0] > bds[1]) {
// No need to copy bds, a new array is created when calling getBounds()
model.mapperBounds = bds;
model.bounds = [...vtkBoundingBox.INIT_BOUNDS];
model.boundsMTime.modified();
return bds;
}
// Check if we have cached values for these bounds - we cache the
// values returned by model.mapper.getBounds() and we store the time
// of caching. If the values returned this time are different, or
// the modified time of this class is newer than the cached time,
// then we need to rebuild.
if (!model.mapperBounds || !bds.every((_, i) => bds[i] === model.mapperBounds[i]) || publicAPI.getMTime() > model.boundsMTime.getMTime()) {
macro.vtkDebugMacro('Recomputing bounds...');
// No need to copy bds, a new array is created when calling getBounds()
model.mapperBounds = bds;
// Compute actor bounds from matrix and mapper bounds
publicAPI.computeMatrix();
const transposedMatrix = new Float64Array(16);
mat4.transpose(transposedMatrix, model.matrix);
vtkBoundingBox.transformBounds(bds, transposedMatrix, model.bounds);
model.boundsMTime.modified();
}
return model.bounds;
};
publicAPI.getBounds = () => {
const bounds = publicAPI.getBoundsByReference();
// Handle case when bounds are not iterable (for example null or undefined)
try {
return [...bounds];
} catch {
return bounds;
}
};
publicAPI.getCenter = () => vtkBoundingBox.getCenter(model.bounds);
publicAPI.getLength = () => vtkBoundingBox.getLength(model.bounds);
publicAPI.getXRange = () => vtkBoundingBox.getXRange(model.bounds);
publicAPI.getYRange = () => vtkBoundingBox.getYRange(model.bounds);
publicAPI.getZRange = () => vtkBoundingBox.getZRange(model.bounds);
publicAPI.getUserMatrix = () => model.userMatrix;
function updateIdentityFlag() {
publicAPI.computeMatrix();
}
publicAPI.onModified(updateIdentityFlag);
publicAPI.getProperty = function () {
let mapperInputPort = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
if (model.properties[mapperInputPort] == null) {
model.properties[mapperInputPort] = publicAPI.makeProperty?.();
}
return model.properties[mapperInputPort];
};
publicAPI.getProperties = () => {
if (model.properties.length === 0) {
model.properties[0] = publicAPI.makeProperty?.();
}
return model.properties;
};
publicAPI.setProperty = (firstArg, secondArg) => {
// Two options for argument layout:
// - (mapperInputPort, property)
// - (property)
const useInputPortArgument = Number.isInteger(firstArg);
const [mapperInputPort, property] = useInputPortArgument ? [firstArg, secondArg] : [0, firstArg];
if (model.properties[mapperInputPort] === property) {
return false;
}
model.properties[mapperInputPort] = property;
return true;
};
publicAPI.getMTime = () => {
let mt = model.mtime;
model.properties.forEach(property => {
if (property !== null) {
const time = property.getMTime();
mt = time > mt ? time : mt;
}
});
return mt;
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
origin: [0, 0, 0],
position: [0, 0, 0],
orientation: [0, 0, 0],
rotation: null,
scale: [1, 1, 1],
bounds: [...vtkBoundingBox.INIT_BOUNDS],
properties: [],
userMatrix: null,
userMatrixMTime: null,
cachedProp3D: null,
isIdentity: true,
matrixMTime: null
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model) {
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues);
// Inheritance
vtkProp.extend(publicAPI, model, initialValues);
model.matrixMTime = {};
macro.obj(model.matrixMTime);
// Build VTK API
macro.get(publicAPI, model, ['isIdentity']);
macro.getArray(publicAPI, model, ['orientation']);
macro.setGetArray(publicAPI, model, ['origin', 'position', 'scale'], 3);
macro.setGet(publicAPI, model, ['properties']);
// Object internal instance
model.matrix = mat4.identity(new Float64Array(16));
model.rotation = mat4.identity(new Float64Array(16));
model.userMatrix = mat4.identity(new Float64Array(16));
model.transform = null; // FIXME
// Object methods
vtkProp3D(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkProp3D');
// ----------------------------------------------------------------------------
var vtkProp3D$1 = {
newInstance,
extend
};
export { vtkProp3D$1 as default, extend, newInstance };