@kitware/vtk.js
Version:
Visualization Toolkit for the Web
310 lines (285 loc) • 10.4 kB
JavaScript
import { m as macro } from '../../macros2.js';
import vtkProp from '../../Rendering/Core/Prop.js';
import vtkCellArray from '../../Common/Core/CellArray.js';
import vtkDataArray from '../../Common/Core/DataArray.js';
import vtkPoints from '../../Common/Core/Points.js';
import { Behavior } from './WidgetRepresentation/Constants.js';
import { RenderingTypes } from '../Core/WidgetManager/Constants.js';
import { CATEGORIES } from '../../Rendering/Core/Mapper/CoincidentTopologyHelper.js';
import { POLYDATA_FIELDS } from '../../Common/DataModel/PolyData/Constants.js';
const {
vtkErrorMacro,
vtkWarningMacro
} = macro;
// ----------------------------------------------------------------------------
const STYLE_CATEGORIES = ['active', 'inactive', 'static'];
function applyCoincidentTopologyParametersToMapper(mapper, parameters) {
if (mapper && mapper.setResolveCoincidentTopologyToPolygonOffset) {
mapper.setResolveCoincidentTopologyToPolygonOffset();
CATEGORIES.forEach(category => {
if (parameters[category]) {
const methodName = `setRelativeCoincidentTopology${category}OffsetParameters`;
if (mapper[methodName]) {
const {
factor,
offset
} = parameters[category];
mapper[methodName](factor, offset);
}
}
});
}
}
function mergeStyles(elementNames, ...stylesToMerge) {
const newStyleObject = {
active: {},
inactive: {},
static: {}
};
STYLE_CATEGORIES.forEach(category => {
const cat = newStyleObject[category];
elementNames.forEach(name => {
if (!cat[name]) {
cat[name] = {};
}
stylesToMerge.filter(s => s && s[category] && s[category][name]).forEach(s => Object.assign(cat[name], s[category][name]));
});
});
return newStyleObject;
}
// ----------------------------------------------------------------------------
function applyStyles(pipelines, styles, activeActor) {
if (!activeActor) {
// static
Object.keys(styles.static).forEach(name => {
if (pipelines[name]) {
pipelines[name].actor.getProperty().set(styles.static[name]);
}
});
// inactive
Object.keys(styles.inactive).forEach(name => {
if (pipelines[name]) {
pipelines[name].actor.getProperty().set(styles.inactive[name]);
}
});
} else {
Object.keys(pipelines).forEach(name => {
const style = pipelines[name].actor === activeActor ? styles.active[name] : styles.inactive[name];
if (style) {
pipelines[name].actor.getProperty().set(style);
}
});
}
}
// ----------------------------------------------------------------------------
function connectPipeline(pipeline) {
let source = pipeline.source;
if (pipeline.filter) {
if (source.isA('vtkDataSet')) {
pipeline.filter.setInputData(source);
} else {
pipeline.filter.setInputConnection(source.getOutputPort());
}
source = pipeline.filter;
}
if (source) {
if (source.isA('vtkDataSet')) {
pipeline.mapper.setInputData(source);
} else {
pipeline.mapper.setInputConnection(source.getOutputPort());
}
}
if (pipeline.glyph) {
pipeline.mapper.setInputConnection(pipeline.glyph.getOutputPort(), 1);
}
pipeline.actor.setMapper(pipeline.mapper);
}
// Internal convenient function to create a data array:
function allocateArray(polyData, name, numberOfTuples, dataType, numberOfComponents) {
// Check first whether name is points, verts, lines, polys, otherwise it is a point data array.
let dataArray = polyData[`get${macro.capitalize(name)}`]?.() || polyData.getPointData().getArrayByName(name);
if (!dataArray || dataType !== undefined && dataArray.getDataType() !== dataType || numberOfComponents !== undefined && dataArray.getNumberOfComponents() !== numberOfComponents) {
let arrayType = vtkDataArray;
let arrayDataType = dataType;
let arrayNumberOfComponents = numberOfComponents;
if (name === 'points') {
arrayType = vtkPoints;
arrayDataType = arrayDataType ?? 'Float32Array';
arrayNumberOfComponents = numberOfComponents ?? 3;
} else if (POLYDATA_FIELDS.includes(name)) {
arrayType = vtkCellArray;
arrayDataType = arrayDataType ?? 'Uint16Array';
arrayNumberOfComponents = numberOfComponents ?? 1;
} else {
// data array
arrayDataType = arrayDataType ?? 'Float32Array';
arrayNumberOfComponents = numberOfComponents ?? 1;
}
dataArray = arrayType.newInstance({
name,
dataType: arrayDataType,
numberOfComponents: arrayNumberOfComponents,
size: arrayNumberOfComponents * numberOfTuples,
empty: numberOfTuples === 0
});
if (name === 'points' || POLYDATA_FIELDS.includes(name)) {
polyData[`set${macro.capitalize(name)}`](dataArray);
} else {
polyData.getPointData().addArray(dataArray);
}
} else if (dataArray.getNumberOfTuples() !== numberOfTuples) {
dataArray.resize(numberOfTuples);
}
return dataArray;
}
// ----------------------------------------------------------------------------
// vtkWidgetRepresentation
// ----------------------------------------------------------------------------
function vtkWidgetRepresentation(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkWidgetRepresentation');
// Internal cache
const cache = {
mtimes: {},
states: []
};
model._onCoincidentTopologyParametersChanged = () => {
publicAPI.getActors().forEach(actor => {
applyCoincidentTopologyParametersToMapper(actor.getMapper(), model.coincidentTopologyParameters);
});
};
// --------------------------------------------------------------------------
publicAPI.getActors = () => model.actors;
publicAPI.getNestedProps = publicAPI.getActors;
// --------------------------------------------------------------------------
publicAPI.setLabels = (...labels) => {
if (labels.length === 1) {
model.labels = [].concat(labels[0]);
} else {
model.labels = labels;
}
publicAPI.modified();
};
publicAPI.getRepresentationStates = (input = model.inputData[0]) => {
if (cache.mtimes.representation === publicAPI.getMTime() && cache.mtimes.input === input.getMTime()) {
return cache.states;
}
// Reinitialize cache
cache.mtimes.representation = publicAPI.getMTime();
cache.mtimes.input = input.getMTime();
cache.states = [];
// Fill states that are going to be used in the representation
model.labels.forEach(name => {
cache.states = cache.states.concat(input.getStatesWithLabel(name) || []);
});
return cache.states;
};
publicAPI.getSelectedState = (prop, compositeID) => {
const representationStates = publicAPI.getRepresentationStates();
if (compositeID < representationStates.length) {
return representationStates[compositeID];
}
vtkErrorMacro(`Representation ${publicAPI.getClassName()} should implement getSelectedState(prop, compositeID) method.`);
return null;
};
publicAPI.updateActorVisibility = (renderingType = RenderingTypes.FRONT_BUFFER, ctxVisible = true, handleVisible = true) => {
let otherFlag = true;
switch (model.behavior) {
case Behavior.HANDLE:
otherFlag = renderingType === RenderingTypes.PICKING_BUFFER || handleVisible;
break;
case Behavior.CONTEXT:
otherFlag = ctxVisible;
break;
default:
otherFlag = true;
break;
}
const visibilityFlag = otherFlag;
for (let i = 0; i < model.actors.length; i++) {
if (model.visibilityFlagArray) {
model.actors[i].setVisibility(visibilityFlag && model.visibilityFlagArray[i]);
} else {
model.actors[i].setVisibility(visibilityFlag);
}
}
if (model.alwaysVisibleActors) {
for (let i = 0; i < model.alwaysVisibleActors.length; i++) {
model.alwaysVisibleActors[i].setVisibility(true);
}
}
};
// Add warning to model.actors.push
model.actors.push = (...args) => {
vtkWarningMacro('You should use publicAPI.addActor() to initialize the actor properly');
args.forEach(actor => publicAPI.addActor(actor));
};
publicAPI.addActor = actor => {
applyCoincidentTopologyParametersToMapper(actor.getMapper(), model.coincidentTopologyParameters);
Array.prototype.push.apply(model.actors, [actor]);
};
// Make sure setting the labels at build time works with string/array...
publicAPI.setLabels(model.labels);
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
function defaultValues(initialValues) {
return {
activeScaleFactor: 1.2,
activeColor: 1,
useActiveColor: true,
actors: [],
labels: [],
behavior: Behavior.CONTEXT,
coincidentTopologyParameters: {
Point: {
factor: -1.0,
offset: -1.0
},
Line: {
factor: -1.0,
offset: -1.0
},
Polygon: {
factor: -1.0,
offset: -1.0
}
},
scaleInPixels: false,
displayScaleParams: {
dispHeightFactor: 1,
cameraPosition: [0, 0, 0],
cameraDir: [1, 0, 0],
isParallel: false,
rendererPixelDims: [1, 1]
},
_internalArrays: {},
...initialValues
};
}
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
// Object methods
vtkProp.extend(publicAPI, model, defaultValues(initialValues));
macro.algo(publicAPI, model, 1, 1);
macro.get(publicAPI, model, ['labels', 'displayScaleParams', 'coincidentTopologyParameters']);
macro.set(publicAPI, model, [{
type: 'object',
name: 'displayScaleParams'
}, {
type: 'object',
name: 'coincidentTopologyParameters'
}]);
macro.setGet(publicAPI, model, ['scaleInPixels', 'activeScaleFactor', 'activeColor', 'useActiveColor']);
// Object specific methods
vtkWidgetRepresentation(publicAPI, model);
}
// ----------------------------------------------------------------------------
var vtkWidgetRepresentation$1 = {
extend,
mergeStyles,
applyStyles,
connectPipeline
};
export { allocateArray, applyStyles, connectPipeline, vtkWidgetRepresentation$1 as default, extend, mergeStyles };