@kitware/vtk.js
Version:
Visualization Toolkit for the Web
349 lines (308 loc) • 12.4 kB
JavaScript
import { m as macro } from '../../macros2.js';
import vtkActor from '../../Rendering/Core/Actor.js';
import vtkClosedPolyLineToSurfaceFilter from '../../Filters/General/ClosedPolyLineToSurfaceFilter.js';
import vtkCubeSource from '../../Filters/Sources/CubeSource.js';
import vtkCutter from '../../Filters/Core/Cutter.js';
import vtkCylinderSource from '../../Filters/Sources/CylinderSource.js';
import vtkMapper from '../../Rendering/Core/Mapper.js';
import vtkMatrixBuilder from '../../Common/Core/MatrixBuilder.js';
import vtkPixelSpaceCallbackMapper from '../../Rendering/Core/PixelSpaceCallbackMapper.js';
import vtkPlane from '../../Common/DataModel/Plane.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';
import vtkSphereSource from '../../Filters/Sources/SphereSource.js';
import vtkStateBuilder from '../Core/StateBuilder.js';
import { getPixelWorldHeightAtCoord } from '../Core/WidgetManager.js';
import vtkWidgetRepresentation from './WidgetRepresentation.js';
import WidgetManagerConst from '../Core/WidgetManager/Constants.js';
import PropertyConst from '../../Rendering/Core/Property/Constants.js';
const {
RenderingTypes
} = WidgetManagerConst;
const {
Interpolation,
Representation
} = PropertyConst;
// ----------------------------------------------------------------------------
// Static methods to build state
// ----------------------------------------------------------------------------
function generateState() {
return vtkStateBuilder.createBuilder().addField({
name: 'origin',
initialValue: [0, 0, 0]
}).addField({
name: 'normal',
initialValue: [0, 0, 1]
}).addField({
name: 'activeHandle',
initialValue: null
}).addField({
name: 'updateMethodName'
}).build();
}
// ----------------------------------------------------------------------------
// Representation style
// ----------------------------------------------------------------------------
const STYLE_PIPELINE_NAMES = ['plane', 'outline', 'normal', 'origin', 'display2D'];
const STYLE_DEFAULT = {
active: {
plane: {
opacity: 1,
color: [0, 0.9, 0]
},
normal: {
opacity: 1,
color: [0, 0.9, 0]
},
origin: {
opacity: 1,
color: [0, 0.9, 0]
}
},
inactive: {
plane: {
opacity: 0.6,
color: [1, 1, 1]
},
normal: {
opacity: 1,
color: [0.9, 0, 0]
},
origin: {
opacity: 1,
color: [1, 0, 0]
}
},
static: {
display2D: {
representation: Representation.POINT
},
outline: {
color: [1, 1, 1],
opacity: 1,
representation: Representation.WIREFRAME,
interpolation: Interpolation.FLAT
}
}
};
// ----------------------------------------------------------------------------
// vtkImplicitPlaneRepresentation methods
// ----------------------------------------------------------------------------
function vtkImplicitPlaneRepresentation(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkImplicitPlaneRepresentation');
// --------------------------------------------------------------------------
// Internal polydata dataset
// --------------------------------------------------------------------------
model.plane = vtkPlane.newInstance();
model.matrix = vtkMatrixBuilder.buildFromDegree();
model._pipelines = {};
model._pipelines.outline = {
source: vtkCubeSource.newInstance(),
mapper: vtkMapper.newInstance(),
actor: vtkActor.newInstance({
pickable: false,
_parentProp: publicAPI
})
};
model._pipelines.plane = {
source: vtkCutter.newInstance({
cutFunction: model.plane
}),
filter: vtkClosedPolyLineToSurfaceFilter.newInstance(),
mapper: vtkMapper.newInstance(),
actor: vtkActor.newInstance({
pickable: true,
_parentProp: publicAPI
})
};
model._pipelines.origin = {
source: vtkSphereSource.newInstance(),
mapper: vtkMapper.newInstance(),
actor: vtkActor.newInstance({
pickable: true,
_parentProp: publicAPI
})
};
model._pipelines.normal = {
source: vtkCylinderSource.newInstance(),
mapper: vtkMapper.newInstance(),
actor: vtkActor.newInstance({
pickable: true,
_parentProp: publicAPI
})
};
model._pipelines.display2D = {
source: publicAPI,
mapper: vtkPixelSpaceCallbackMapper.newInstance(),
actor: vtkActor.newInstance({
pickable: false,
_parentProp: publicAPI
})
};
// Plane generation pipeline
model._pipelines.plane.source.setInputConnection(model._pipelines.outline.source.getOutputPort());
vtkWidgetRepresentation.connectPipeline(model._pipelines.outline);
vtkWidgetRepresentation.connectPipeline(model._pipelines.plane);
vtkWidgetRepresentation.connectPipeline(model._pipelines.origin);
vtkWidgetRepresentation.connectPipeline(model._pipelines.normal);
vtkWidgetRepresentation.connectPipeline(model._pipelines.display2D);
publicAPI.addActor(model._pipelines.outline.actor);
publicAPI.addActor(model._pipelines.plane.actor);
publicAPI.addActor(model._pipelines.origin.actor);
publicAPI.addActor(model._pipelines.normal.actor);
publicAPI.addActor(model._pipelines.display2D.actor);
// --------------------------------------------------------------------------
publicAPI.requestData = (inData, outData) => {
const state = inData[0];
const origin = state.getOrigin();
if (!origin) {
return;
}
const normal = state.getNormal();
const bounds = state.getBounds();
model.plane.setOrigin(origin);
model.plane.setNormal(normal);
// --------------------------------
// Update cube parameters
// --------------------------------
model._pipelines.outline.source.setCenter((bounds[0] + bounds[1]) * 0.5, (bounds[2] + bounds[3]) * 0.5, (bounds[4] + bounds[5]) * 0.5);
const xRange = bounds[1] - bounds[0];
const yRange = bounds[3] - bounds[2];
const zRange = bounds[5] - bounds[4];
model._pipelines.outline.source.setXLength(xRange);
model._pipelines.outline.source.setYLength(yRange);
model._pipelines.outline.source.setZLength(zRange);
// --------------------------------
// Update normal parameters
// --------------------------------
let pixelScale = 1;
if (model.scaleInPixels) {
pixelScale = getPixelWorldHeightAtCoord(origin, model.displayScaleParams);
}
model._pipelines.normal.source.set({
height: Math.max(xRange, yRange, zRange),
radius: model.handleSizeRatio * Math.min(xRange, yRange, zRange) * model.axisScale * pixelScale,
resolution: model.sphereResolution
});
const yAxis = model._pipelines.normal.source.getOutputData();
const newAxis = vtkPolyData.newInstance();
newAxis.shallowCopy(yAxis);
newAxis.getPoints().setData(Float32Array.from(yAxis.getPoints().getData()), 3);
newAxis.getPointData().removeAllArrays();
model.matrix.identity().translate(origin[0], origin[1], origin[2]).rotateFromDirections([0, 1, 0], normal).apply(newAxis.getPoints().getData());
model._pipelines.normal.mapper.setInputData(newAxis);
// --------------------------------
// Update origin parameters
// --------------------------------
model._pipelines.origin.actor.setPosition(origin);
const handleScale = model.handleSizeRatio * Math.min(xRange, yRange, zRange) * pixelScale;
model._pipelines.origin.actor.setScale(handleScale, handleScale, handleScale);
// --------------------------------
// Update style since state changed
// --------------------------------
vtkWidgetRepresentation.applyStyles(model._pipelines, model.representationStyle, state.getActive() && state.getActiveHandle());
const output = outData[0]?.initialize() || vtkPolyData.newInstance();
output.shallowCopy(model._pipelines.plane.filter.getOutputData());
outData[0] = output;
};
// --------------------------------------------------------------------------
// Set/Get Forwarding
// --------------------------------------------------------------------------
publicAPI.setSphereResolution = res => {
model.sphereResolution = res;
return model._pipelines.origin.source.setPhiResolution(res) && model._pipelines.origin.source.setThetaResolution(res);
};
publicAPI.setRepresentationStyle = style => {
model.representationStyle = vtkWidgetRepresentation.mergeStyles(STYLE_PIPELINE_NAMES, model.representationStyle, style);
// Apply static and inactive
vtkWidgetRepresentation.applyStyles(model._pipelines, model.representationStyle);
// Force requestData to execute
publicAPI.modified();
};
// --------------------------------------------------------------------------
// WidgetRepresentation API
// --------------------------------------------------------------------------
publicAPI.updateActorVisibility = (renderingType, ctxVisible, hVisible) => {
const {
planeVisible,
originVisible,
normalVisible,
outlineVisible
} = model;
if (renderingType === RenderingTypes.PICKING_BUFFER) {
model._pipelines.plane.actor.setVisibility(planeVisible);
model._pipelines.origin.actor.setVisibility(originVisible);
model._pipelines.normal.actor.setVisibility(normalVisible);
//
model._pipelines.plane.actor.getProperty().setOpacity(1);
} else {
model._pipelines.outline.actor.setVisibility(outlineVisible && ctxVisible);
model._pipelines.plane.actor.setVisibility(planeVisible && hVisible);
model._pipelines.origin.actor.setVisibility(originVisible && hVisible);
model._pipelines.normal.actor.setVisibility(normalVisible && hVisible);
//
const state = model.inputData[0];
if (state) {
vtkWidgetRepresentation.applyStyles(model._pipelines, model.representationStyle, state.getActive() && state.getActiveHandle());
}
}
};
// --------------------------------------------------------------------------
publicAPI.getSelectedState = (prop, compositeID) => {
// We only have one state to control us
// we may want to update some field on the state to highlight the
// selected handle later on...
const state = model.inputData[0];
state.setActiveHandle(prop);
switch (prop) {
case model._pipelines.plane.actor:
state.setUpdateMethodName('updateFromPlane');
break;
case model._pipelines.origin.actor:
state.setUpdateMethodName('updateFromOrigin');
break;
case model._pipelines.normal.actor:
state.setUpdateMethodName('updateFromNormal');
break;
default:
state.setUpdateMethodName('updateFromPlane');
break;
}
return state;
};
// --------------------------------------------------------------------------
// Initialization
// --------------------------------------------------------------------------
publicAPI.setRepresentationStyle(STYLE_DEFAULT);
publicAPI.setSphereResolution(model.sphereResolution);
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
sphereResolution: 24,
handleSizeRatio: 0.05,
axisScale: 0.1,
normalVisible: true,
originVisible: true,
planeVisible: true,
outlineVisible: true
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
vtkWidgetRepresentation.extend(publicAPI, model, initialValues);
macro.get(publicAPI, model, ['sphereResolution', 'representationStyle']);
macro.setGet(publicAPI, model, ['handleSizeRatio', 'axisScale', 'normalVisible', 'originVisible', 'planeVisible', 'outlineVisible']);
// Object specific methods
vtkImplicitPlaneRepresentation(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkImplicitPlaneRepresentation');
// ----------------------------------------------------------------------------
var vtkImplicitPlaneRepresentation$1 = {
newInstance,
extend,
generateState
};
export { vtkImplicitPlaneRepresentation$1 as default, extend, newInstance };