import macro from 'vtk.js/Sources/macros'; import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'; import vtkClosedPolyLineToSurfaceFilter from 'vtk.js/Sources/Filters/General/ClosedPolyLineToSurfaceFilter'; import vtkCubeSource from 'vtk.js/Sources/Filters/Sources/CubeSource'; import vtkCutter from 'vtk.js/Sources/Filters/Core/Cutter'; import vtkCylinderSource from 'vtk.js/Sources/Filters/Sources/CylinderSource'; import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'; import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder'; import vtkPixelSpaceCallbackMapper from 'vtk.js/Sources/Rendering/Core/PixelSpaceCallbackMapper'; import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane'; import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'; import vtkSphereSource from 'vtk.js/Sources/Filters/Sources/SphereSource'; import vtkStateBuilder from 'vtk.js/Sources/Widgets/Core/StateBuilder'; import { getPixelWorldHeightAtCoord } from 'vtk.js/Sources/Widgets/Core/WidgetManager'; import vtkWidgetRepresentation from 'vtk.js/Sources/Widgets/Representations/WidgetRepresentation';
import WidgetManagerConst from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; import PropertyConst from 'vtk.js/Sources/Rendering/Core/Property/Constants';
const { RenderingTypes } = WidgetManagerConst; const { Interpolation, Representation } = PropertyConst;
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(); }
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, }, }, };
function vtkImplicitPlaneRepresentation(publicAPI, model) { model.classHierarchy.push('vtkImplicitPlaneRepresentation');
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 }), };
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);
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);
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);
model._pipelines.origin.actor.setPosition(origin); const handleScale = model.handleSizeRatio * Math.min(xRange, yRange, zRange) * pixelScale; model._pipelines.origin.actor.setScale( handleScale, handleScale, handleScale );
vtkWidgetRepresentation.applyStyles( model._pipelines, model.representationStyle, state.getActive() && state.getActiveHandle() );
const output = vtkPolyData.newInstance(); output.shallowCopy(model._pipelines.plane.filter.getOutputData()); outData[0] = output; };
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 );
vtkWidgetRepresentation.applyStyles( model._pipelines, model.representationStyle );
publicAPI.modified(); };
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) => { 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; };
publicAPI.setRepresentationStyle(STYLE_DEFAULT); publicAPI.setSphereResolution(model.sphereResolution); }
const DEFAULT_VALUES = { sphereResolution: 24, handleSizeRatio: 0.05, axisScale: 0.1, normalVisible: true, originVisible: true, planeVisible: true, outlineVisible: true, };
export 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', ]);
vtkImplicitPlaneRepresentation(publicAPI, model); }
export const newInstance = macro.newInstance( extend, 'vtkImplicitPlaneRepresentation' );
export default { newInstance, extend, generateState };
|