UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

302 lines (273 loc) 9.74 kB
import { m as macro } from '../../macros2.js'; import vtkImageSlice from '../../Rendering/Core/ImageSlice.js'; import vtkImageMapper from '../../Rendering/Core/ImageMapper.js'; import vtkAbstractRepresentationProxy from '../Core/AbstractRepresentationProxy.js'; // ---------------------------------------------------------------------------- function sum(a, b) { return a + b; } // ---------------------------------------------------------------------------- function mean() { for (var _len = arguments.length, array = new Array(_len), _key = 0; _key < _len; _key++) { array[_key] = arguments[_key]; } return array.reduce(sum, 0) / array.length; } // ---------------------------------------------------------------------------- function updateDomains(dataset, dataArray, model, updateProp) { const dataRange = dataArray.getRange(); const spacing = dataset.getSpacing(); const bounds = dataset.getBounds(); const extent = dataset.getExtent(); let sliceMin; let sliceMax; let stepVal; let axisIndex; const sliceMode = model.mapper.getSlicingMode(); const sliceModeLabel = 'IJKXYZ'[sliceMode]; switch (sliceMode) { case vtkImageMapper.SlicingMode.I: case vtkImageMapper.SlicingMode.J: case vtkImageMapper.SlicingMode.K: axisIndex = 'IJK'.indexOf(sliceModeLabel); sliceMin = extent[axisIndex * 2]; sliceMax = extent[axisIndex * 2 + 1]; stepVal = 1; break; case vtkImageMapper.SlicingMode.X: case vtkImageMapper.SlicingMode.Y: case vtkImageMapper.SlicingMode.Z: { axisIndex = 'XYZ'.indexOf(sliceModeLabel); sliceMin = bounds[axisIndex * 2]; sliceMax = bounds[axisIndex * 2 + 1]; const { ijkMode } = model.mapper.getClosestIJKAxis(); stepVal = spacing[ijkMode]; } break; } const propToUpdate = { slice: { domain: { min: sliceMin, max: sliceMax, step: stepVal } }, windowWidth: { domain: { min: 0, max: dataRange[1] - dataRange[0], step: 'any' } }, windowLevel: { domain: { min: dataRange[0], max: dataRange[1], step: 'any' } } }; updateProp('slice', propToUpdate.slice); updateProp('windowWidth', propToUpdate.windowWidth); updateProp('windowLevel', propToUpdate.windowLevel); return { slice: mean(propToUpdate.slice.domain.min, propToUpdate.slice.domain.max), windowWidth: propToUpdate.windowWidth.domain.max, windowLevel: Math.floor(mean(propToUpdate.windowLevel.domain.min, propToUpdate.windowLevel.domain.max)) }; } // ---------------------------------------------------------------------------- // vtkSliceRepresentationProxy methods // ---------------------------------------------------------------------------- function vtkSliceRepresentationProxy(publicAPI, model) { // Set our className model.classHierarchy.push('vtkSliceRepresentationProxy'); model.mapper = vtkImageMapper.newInstance(); model.actor = vtkImageSlice.newInstance(); model.property = model.actor.getProperty(); // connect rendering pipeline model.actor.setMapper(model.mapper); model.actors.push(model.actor); function setInputData(inputDataset) { const state = updateDomains(inputDataset, publicAPI.getDataArray(), model, publicAPI.updateProxyProperty); publicAPI.set(state); // Init slice location const bounds = inputDataset.getBounds(); const extent = inputDataset.getExtent(); switch (model.mapper.getSlicingMode()) { case vtkImageMapper.SlicingMode.I: publicAPI.setSlice(Math.floor(mean(extent[0], extent[1]))); break; case vtkImageMapper.SlicingMode.J: publicAPI.setSlice(Math.floor(mean(extent[2], extent[3]))); break; case vtkImageMapper.SlicingMode.K: publicAPI.setSlice(Math.floor(mean(extent[4], extent[5]))); break; case vtkImageMapper.SlicingMode.X: publicAPI.setSlice(mean(bounds[0], bounds[1])); break; case vtkImageMapper.SlicingMode.Y: publicAPI.setSlice(mean(bounds[2], bounds[3])); break; case vtkImageMapper.SlicingMode.Z: publicAPI.setSlice(mean(bounds[4], bounds[5])); break; } } // Keep things updated model.sourceDependencies.push(model.mapper); model.sourceDependencies.push({ setInputData }); // keeps the slicing mode and domain info updated function updateSlicingMode(mode) { model.mapper.setSlicingMode(vtkImageMapper.SlicingMode[mode]); // Update to previously set position const modelKey = `${mode.toLowerCase()}Slice`; if (modelKey in model && model[modelKey] !== undefined) { model.mapper.setSlice(model[modelKey]); } if (model.input) { // Update domains for UI... const state = updateDomains(publicAPI.getInputDataSet(), publicAPI.getDataArray(), model, publicAPI.updateProxyProperty); publicAPI.set(state); } publicAPI.modified(); } // API ---------------------------------------------------------------------- publicAPI.setSlicingMode = mode => { if (!mode) { return false; } if (model.slicingMode !== mode) { // Update Mode model.slicingMode = mode; updateSlicingMode(mode); return true; } return false; }; publicAPI.getSliceIndex = () => { if ('XYZ'.indexOf(model.slicingMode) !== -1) { return model.mapper.getSliceAtPosition(model.mapper.getSlice()); } return model.mapper.getSlice(); }; publicAPI.getAnnotations = () => { const dynamicAddOn = {}; const sliceIndex = publicAPI.getSliceIndex(); const sliceBounds = model.mapper.getBoundsForSlice(); const sliceNormal = model.mapper.getSlicingModeNormal(); const { ijkMode } = model.mapper.getClosestIJKAxis(); const sliceOrigin = [(sliceBounds[0] + sliceBounds[1]) * 0.5, (sliceBounds[2] + sliceBounds[3]) * 0.5, (sliceBounds[4] + sliceBounds[5]) * 0.5]; let slicePosition = 0; if (sliceBounds[1] - sliceBounds[0] < Number.EPSILON) { slicePosition = sliceBounds[0]; } if (sliceBounds[3] - sliceBounds[2] < Number.EPSILON) { slicePosition = sliceBounds[2]; } if (sliceBounds[5] - sliceBounds[4] < Number.EPSILON) { slicePosition = sliceBounds[4]; } const imageData = model.mapper.getInputData(); if (imageData) { dynamicAddOn.sliceSpacing = imageData.getSpacing()[ijkMode]; dynamicAddOn.dimensions = imageData.getDimensions(); dynamicAddOn.sliceCount = imageData.getDimensions()[ijkMode]; const ijkOrientation = []; for (let i = 0; i < 3; i++) { const extent = [0, 0, 0, 0, 0, 0]; extent[i * 2 + 1] = 1; const tmpBounds = imageData.extentToBounds(extent); if (tmpBounds[1] - tmpBounds[0] > Number.EPSILON) { ijkOrientation[0] = 'IJK'[i]; } if (tmpBounds[3] - tmpBounds[2] > Number.EPSILON) { ijkOrientation[1] = 'IJK'[i]; } if (tmpBounds[5] - tmpBounds[4] > Number.EPSILON) { ijkOrientation[2] = 'IJK'[i]; } } dynamicAddOn.ijkOrientation = ijkOrientation.join(''); } return { ijkMode, sliceBounds, sliceIndex, sliceNormal, sliceOrigin, slicePosition, ...dynamicAddOn }; }; const parentSetColorBy = publicAPI.setColorBy; publicAPI.setColorBy = function (arrayName, arrayLocation) { let componentIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -1; if (arrayName === null) { model.property.setRGBTransferFunction(null); model.property.setPiecewiseFunction(null); } else { parentSetColorBy(arrayName, arrayLocation, componentIndex); const lutProxy = publicAPI.getLookupTableProxy(arrayName); const pwfProxy = publicAPI.getPiecewiseFunctionProxy(arrayName); model.property.setRGBTransferFunction(lutProxy.getLookupTable()); model.property.setPiecewiseFunction(pwfProxy.getPiecewiseFunction()); } }; // Initialize slicing mode updateSlicingMode(model.slicingMode || 'X'); } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = {}; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Object methods vtkAbstractRepresentationProxy.extend(publicAPI, model, initialValues); macro.get(publicAPI, model, ['slicingMode']); // Object specific methods vtkSliceRepresentationProxy(publicAPI, model); // Proxyfy macro.proxyPropertyMapping(publicAPI, model, { visibility: { modelKey: 'actor', property: 'visibility' }, windowWidth: { modelKey: 'property', property: 'colorWindow' }, windowLevel: { modelKey: 'property', property: 'colorLevel' }, interpolationType: { modelKey: 'property', property: 'interpolationType' }, slice: { modelKey: 'mapper', property: 'slice' } }); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkSliceRepresentationProxy'); // ---------------------------------------------------------------------------- var vtkSliceRepresentationProxy$1 = { newInstance, extend }; export { vtkSliceRepresentationProxy$1 as default, extend, newInstance };