@acransac/vtk.js
Version:
Visualization Toolkit for the Web
217 lines (175 loc) • 6.41 kB
JavaScript
import { vec3, mat4 } from 'gl-matrix';
import macro from 'vtk.js/Sources/macro';
import vtkProp3D from 'vtk.js/Sources/Rendering/Core/Prop3D';
import vtkProperty from 'vtk.js/Sources/Rendering/Core/Property';
const { vtkDebugMacro } = macro;
// ----------------------------------------------------------------------------
// vtkActor methods
// ----------------------------------------------------------------------------
function vtkActor(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkActor');
// Capture 'parentClass' api for internal use
const superClass = { ...publicAPI };
publicAPI.getActors = () => publicAPI;
publicAPI.getIsOpaque = () => {
if (model.forceOpaque) {
return true;
}
if (model.forceTranslucent) {
return false;
}
// make sure we have a property
if (!model.property) {
// force creation of a property
publicAPI.getProperty();
}
let isOpaque = model.property.getOpacity() >= 1.0;
// are we using an opaque texture, if any?
isOpaque = isOpaque && (!model.texture || !model.texture.isTranslucent());
// are we using an opaque scalar array, if any?
isOpaque = isOpaque && (!model.mapper || model.mapper.getIsOpaque());
return isOpaque;
};
publicAPI.hasTranslucentPolygonalGeometry = () => {
if (model.mapper === null) {
return false;
}
// make sure we have a property
if (model.property === null) {
// force creation of a property
publicAPI.setProperty(publicAPI.makeProperty());
}
// is this actor opaque ?
return !publicAPI.getIsOpaque();
};
publicAPI.makeProperty = vtkProperty.newInstance;
publicAPI.getProperty = () => {
if (model.property === null) {
model.property = publicAPI.makeProperty();
}
return model.property;
};
publicAPI.getBounds = () => {
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]) {
model.mapperBounds = bds.concat(); // copy the mapper's bounds
model.bounds = [1, -1, 1, -1, 1, -1];
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[0] !== model.mapperBounds[0] ||
bds[1] !== model.mapperBounds[1] ||
bds[2] !== model.mapperBounds[2] ||
bds[3] !== model.mapperBounds[3] ||
bds[4] !== model.mapperBounds[4] ||
bds[5] !== model.mapperBounds[5] ||
publicAPI.getMTime() > model.boundsMTime.getMTime()
) {
vtkDebugMacro('Recomputing bounds...');
model.mapperBounds = bds.concat(); // copy the mapper's bounds
const bbox = [
vec3.fromValues(bds[1], bds[3], bds[5]),
vec3.fromValues(bds[1], bds[2], bds[5]),
vec3.fromValues(bds[0], bds[2], bds[5]),
vec3.fromValues(bds[0], bds[3], bds[5]),
vec3.fromValues(bds[1], bds[3], bds[4]),
vec3.fromValues(bds[1], bds[2], bds[4]),
vec3.fromValues(bds[0], bds[2], bds[4]),
vec3.fromValues(bds[0], bds[3], bds[4]),
];
publicAPI.computeMatrix();
const tmp4 = mat4.create();
mat4.transpose(tmp4, model.matrix);
bbox.forEach((pt) => vec3.transformMat4(pt, pt, tmp4));
/* eslint-disable no-multi-assign */
model.bounds[0] = model.bounds[2] = model.bounds[4] = Number.MAX_VALUE;
model.bounds[1] = model.bounds[3] = model.bounds[5] = -Number.MAX_VALUE;
/* eslint-enable no-multi-assign */
model.bounds = model.bounds.map((d, i) =>
i % 2 === 0
? bbox.reduce((a, b) => (a > b[i / 2] ? b[i / 2] : a), d)
: bbox.reduce((a, b) => (a < b[(i - 1) / 2] ? b[(i - 1) / 2] : a), d)
);
model.boundsMTime.modified();
}
return model.bounds;
};
publicAPI.getMTime = () => {
let mt = superClass.getMTime();
if (model.property !== null) {
const time = model.property.getMTime();
mt = time > mt ? time : mt;
}
if (model.backfaceProperty !== null) {
const time = model.backfaceProperty.getMTime();
mt = time > mt ? time : mt;
}
return mt;
};
publicAPI.getRedrawMTime = () => {
let mt = model.mtime;
if (model.mapper !== null) {
let time = model.mapper.getMTime();
mt = time > mt ? time : mt;
if (model.mapper.getInput() !== null) {
// FIXME !!! getInputAlgorithm / getInput
model.mapper.getInputAlgorithm().update();
time = model.mapper.getInput().getMTime();
mt = time > mt ? time : mt;
}
}
return mt;
};
publicAPI.getSupportsSelection = () =>
model.mapper ? model.mapper.getSupportsSelection() : false;
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
mapper: null,
property: null,
backfaceProperty: null,
forceOpaque: false,
forceTranslucent: false,
bounds: [1, -1, 1, -1, 1, -1],
};
// ----------------------------------------------------------------------------
export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Inheritance
vtkProp3D.extend(publicAPI, model, initialValues);
// vtkTimeStamp
model.boundsMTime = {};
macro.obj(model.boundsMTime);
// Build VTK API
macro.set(publicAPI, model, ['property']);
macro.setGet(publicAPI, model, [
'backfaceProperty',
'forceOpaque',
'forceTranslucent',
'mapper',
]);
// Object methods
vtkActor(publicAPI, model);
}
// ----------------------------------------------------------------------------
export const newInstance = macro.newInstance(extend, 'vtkActor');
// ----------------------------------------------------------------------------
export default { newInstance, extend };