UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

276 lines (253 loc) 9.69 kB
import { m as macro } from '../../macros2.js'; import vtkRenderer from '../../Rendering/Core/Renderer.js'; import Constants from './OrientationMarkerWidget/Constants.js'; const { vtkErrorMacro } = macro; const { Corners } = Constants; // ---------------------------------------------------------------------------- // vtkOrientationMarkerWidget // ---------------------------------------------------------------------------- function vtkOrientationMarkerWidget(publicAPI, model) { // Set our className model.classHierarchy.push('vtkOrientationMarkerWidget'); const superClass = { ...publicAPI }; // Private variables const previousCameraInput = []; const selfRenderer = vtkRenderer.newInstance(); const resizeObserver = new ResizeObserver(entries => { publicAPI.updateViewport(); }); let onCameraChangedSub = null; let onCameraModifiedSub = null; let onAnimationSub = null; let onEndAnimationSub = null; let selfSubscription = null; function onCameraModified() { // If animating, marker will be updated on Animation event if (!model._interactor.isAnimating()) { publicAPI.updateMarkerOrientation(); } } model._onParentRendererChanged = () => publicAPI.updateViewport(); publicAPI.computeViewport = () => { const parentRen = model.parentRenderer || model._interactor.getCurrentRenderer(); const [xMin, yMin, xMax, yMax] = parentRen.getViewport(); const view = model._interactor.getView(); const canvasSize = view.getSize(); const [viewXSize, viewYSize] = view.getViewportSize(parentRen); const minViewSize = Math.min(viewXSize, viewYSize); let pixelSize = model.viewportSize * minViewSize; // clamp pixel size pixelSize = Math.max(Math.min(model.minPixelSize, minViewSize), Math.min(model.maxPixelSize, pixelSize)); const xFrac = pixelSize / canvasSize[0]; const yFrac = pixelSize / canvasSize[1]; // [left bottom right top] switch (model.viewportCorner) { case Corners.TOP_LEFT: return [xMin, yMax - yFrac, xMin + xFrac, yMax]; case Corners.TOP_RIGHT: return [xMax - xFrac, yMax - yFrac, xMax, yMax]; case Corners.BOTTOM_LEFT: return [xMin, yMin, xMin + xFrac, yMin + yFrac]; case Corners.BOTTOM_RIGHT: return [xMax - xFrac, yMin, xMax, yMin + yFrac]; default: vtkErrorMacro('Invalid widget corner'); return null; } }; publicAPI.updateViewport = () => { if (model.enabled) { selfRenderer.setViewport(...publicAPI.computeViewport()); model._interactor.render(); } }; publicAPI.updateMarkerOrientation = () => { const ren = model.parentRenderer || model._interactor.getCurrentRenderer(); const currentCamera = ren.getActiveCamera(); if (!currentCamera) { return; } const position = currentCamera.getReferenceByName('position'); const focalPoint = currentCamera.getReferenceByName('focalPoint'); const viewUp = currentCamera.getReferenceByName('viewUp'); if (previousCameraInput[0] !== position[0] || previousCameraInput[1] !== position[1] || previousCameraInput[2] !== position[2] || previousCameraInput[3] !== focalPoint[0] || previousCameraInput[4] !== focalPoint[1] || previousCameraInput[5] !== focalPoint[2] || previousCameraInput[6] !== viewUp[0] || previousCameraInput[7] !== viewUp[1] || previousCameraInput[8] !== viewUp[2]) { previousCameraInput[0] = position[0]; previousCameraInput[1] = position[1]; previousCameraInput[2] = position[2]; previousCameraInput[3] = focalPoint[0]; previousCameraInput[4] = focalPoint[1]; previousCameraInput[5] = focalPoint[2]; previousCameraInput[6] = viewUp[0]; previousCameraInput[7] = viewUp[1]; previousCameraInput[8] = viewUp[2]; const activeCamera = selfRenderer.getActiveCamera(); activeCamera.setPosition(position[0], position[1], position[2]); activeCamera.setFocalPoint(focalPoint[0], focalPoint[1], focalPoint[2]); activeCamera.setViewUp(viewUp[0], viewUp[1], viewUp[2]); selfRenderer.resetCamera(); } }; /** * Enables/Disables the orientation marker. */ publicAPI.setEnabled = enabling => { if (enabling) { if (model.enabled) { return; } if (!model.actor) { vtkErrorMacro('Must set actor before enabling orientation marker.'); return; } if (!model._interactor) { vtkErrorMacro('Must set interactor before enabling orientation marker.'); return; } const ren = model.parentRenderer || model._interactor.getCurrentRenderer(); const renderWindow = ren.getRenderWindow(); renderWindow.addRenderer(selfRenderer); if (renderWindow.getNumberOfLayers() < 2) { renderWindow.setNumberOfLayers(2); } // Highest number is foreground selfRenderer.setLayer(renderWindow.getNumberOfLayers() - 1); selfRenderer.setInteractive(model.interactiveRenderer); selfRenderer.addViewProp(model.actor); model.actor.setVisibility(true); onCameraChangedSub = ren.onEvent(event => { if (event.type === 'ActiveCameraEvent') { if (onCameraModifiedSub) { onCameraModifiedSub.unsubscribe(); } onCameraModifiedSub = event.camera.onModified(onCameraModified); } }); onCameraModifiedSub = ren.getActiveCamera().onModified(onCameraModified); onAnimationSub = model._interactor.onAnimation(publicAPI.updateMarkerOrientation); onEndAnimationSub = model._interactor.onEndAnimation(publicAPI.updateMarkerOrientation); resizeObserver.observe(model._interactor.getView().getCanvas()); publicAPI.updateViewport(); publicAPI.updateMarkerOrientation(); model.enabled = true; } else { if (!model.enabled) { return; } model.enabled = false; resizeObserver.disconnect(); onCameraChangedSub.unsubscribe(); onCameraChangedSub = null; onCameraModifiedSub.unsubscribe(); onCameraModifiedSub = null; onAnimationSub.unsubscribe(); onAnimationSub = null; onEndAnimationSub.unsubscribe(); onEndAnimationSub = null; model.actor.setVisibility(false); selfRenderer.removeViewProp(model.actor); const renderWindow = model._interactor?.findPokedRenderer()?.getRenderWindow(); if (renderWindow) { renderWindow.removeRenderer(selfRenderer); } } publicAPI.modified(); }; /** * Sets the viewport corner. */ publicAPI.setViewportCorner = corner => { if (corner === model.viewportCorner) { return; } model.viewportCorner = corner; publicAPI.updateViewport(); }; /** * Sets the viewport size. */ publicAPI.setViewportSize = sizeFactor => { const viewportSize = Math.min(1, Math.max(0, sizeFactor)); if (viewportSize === model.viewportSize) { return; } model.viewportSize = viewportSize; publicAPI.updateViewport(); }; publicAPI.setActor = actor => { const previousState = model.enabled; publicAPI.setEnabled(false); model.actor = actor; publicAPI.setEnabled(previousState); }; publicAPI.getRenderer = () => selfRenderer; publicAPI.delete = () => { superClass.delete(); if (selfSubscription) { selfSubscription.unsubscribe(); selfSubscription = null; } if (onCameraChangedSub) { onCameraChangedSub.unsubscribe(); onCameraChangedSub = null; } if (onCameraModifiedSub) { onCameraModifiedSub.unsubscribe(); onCameraModifiedSub = null; } if (onAnimationSub) { onAnimationSub.unsubscribe(); onAnimationSub = null; } if (onEndAnimationSub) { onEndAnimationSub.unsubscribe(); onEndAnimationSub = null; } resizeObserver.disconnect(); }; // -------------------------------------------------------------------------- // update viewport whenever we are updated selfSubscription = publicAPI.onModified(publicAPI.updateViewport); } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { // actor: null, // _interactor: null, viewportCorner: Constants.Corners.BOTTOM_LEFT, viewportSize: 0.2, minPixelSize: 50, maxPixelSize: 200, parentRenderer: null, interactiveRenderer: false }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API macro.obj(publicAPI, model); macro.get(publicAPI, model, ['enabled', 'viewportCorner', 'viewportSize', 'interactiveRenderer']); // NOTE: setting these while the widget is enabled will // not update the widget. macro.setGet(publicAPI, model, ['_interactor', 'minPixelSize', 'maxPixelSize', 'parentRenderer']); macro.get(publicAPI, model, ['actor']); macro.moveToProtected(publicAPI, model, ['interactor']); // Object methods vtkOrientationMarkerWidget(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkOrientationMarkerWidget'); // ---------------------------------------------------------------------------- var vtkOrientationMarkerWidget$1 = { newInstance, extend, ...Constants }; export { DEFAULT_VALUES, vtkOrientationMarkerWidget$1 as default, extend, newInstance };