* chore: 🤖 Update react-vtkjs-viewport and refactor vtk extension
* chore: 🤖 Update react-vtkjs-viewport and refactor vtk extension
This commit is contained in:
parent
04ffe3ec76
commit
d5e21bb5bb
@ -48,7 +48,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"react-vtkjs-viewport": "^0.3.0"
|
"react-vtkjs-viewport": "^0.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ohif/core": "^1.4.0",
|
"@ohif/core": "^1.4.0",
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
|
|||||||
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
|
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
|
||||||
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
|
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
|
||||||
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
|
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
|
||||||
import vtkViewportSubscriptionManager from './utils/vtkViewportSubscriptionManager.js';
|
|
||||||
|
|
||||||
const { StackManager } = OHIF.utils;
|
const { StackManager } = OHIF.utils;
|
||||||
|
|
||||||
@ -182,7 +181,6 @@ class OHIFVTKViewport extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { vtkImageData, imageMetaData0 } = imageDataObject;
|
const { vtkImageData, imageMetaData0 } = imageDataObject;
|
||||||
|
|
||||||
const { windowWidth, windowCenter, modality } = imageMetaData0;
|
const { windowWidth, windowCenter, modality } = imageMetaData0;
|
||||||
|
|
||||||
let lower;
|
let lower;
|
||||||
@ -208,15 +206,10 @@ class OHIFVTKViewport extends Component {
|
|||||||
.getRGBTransferFunction(0)
|
.getRGBTransferFunction(0)
|
||||||
.setRange(lower, upper);
|
.setRange(lower, upper);
|
||||||
|
|
||||||
// TODO: Should look into implementing autoAdjustSampleDistance in vtk
|
|
||||||
// Manually changing the sample distance here by a couple orders of
|
|
||||||
// Magnitude in either direction makes no difference.
|
|
||||||
// Also setting volumeMapper.setMaximumSamplesPerRay(10000)
|
|
||||||
// Prevents the warning of too many samples, but the resolution isn't improved.
|
|
||||||
|
|
||||||
const spacing = vtkImageData.getSpacing();
|
const spacing = vtkImageData.getSpacing();
|
||||||
|
// Set the sample distance to half the mean length of one side. This is where the divide by 6 comes from.
|
||||||
// https://github.com/Kitware/VTK/blob/6b559c65bb90614fb02eb6d1b9e3f0fca3fe4b0b/Rendering/VolumeOpenGL2/vtkSmartVolumeMapper.cxx#L344
|
// https://github.com/Kitware/VTK/blob/6b559c65bb90614fb02eb6d1b9e3f0fca3fe4b0b/Rendering/VolumeOpenGL2/vtkSmartVolumeMapper.cxx#L344
|
||||||
const sampleDistance = (spacing[0] + spacing[1] + spacing[2]) / 6.0;
|
const sampleDistance = (spacing[0] + spacing[1] + spacing[2]) / 6;
|
||||||
|
|
||||||
volumeMapper.setSampleDistance(sampleDistance);
|
volumeMapper.setSampleDistance(sampleDistance);
|
||||||
|
|
||||||
@ -251,6 +244,8 @@ class OHIFVTKViewport extends Component {
|
|||||||
frameIndex
|
frameIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.imageDataObject = imageDataObject;
|
||||||
|
|
||||||
// TODO: Temporarily disabling this since it is not yet
|
// TODO: Temporarily disabling this since it is not yet
|
||||||
// being used and hurts performance significantly.
|
// being used and hurts performance significantly.
|
||||||
/*if (!labelmap) {
|
/*if (!labelmap) {
|
||||||
@ -294,10 +289,6 @@ class OHIFVTKViewport extends Component {
|
|||||||
this.setStateFromProps();
|
this.setStateFromProps();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
vtkViewportSubscriptionManager.unsubscribe(this.props.viewportIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { studies, displaySet } = this.props.viewportData;
|
const { studies, displaySet } = this.props.viewportData;
|
||||||
const prevDisplaySet = prevProps.viewportData.displaySet;
|
const prevDisplaySet = prevProps.viewportData.displaySet;
|
||||||
|
|||||||
@ -4,66 +4,16 @@ import {
|
|||||||
vtkInteractorStyleMPRSlice,
|
vtkInteractorStyleMPRSlice,
|
||||||
vtkInteractorStyleMPRRotate,
|
vtkInteractorStyleMPRRotate,
|
||||||
vtkSVGCrosshairsWidget,
|
vtkSVGCrosshairsWidget,
|
||||||
vtkSVGWidgetManager,
|
|
||||||
} from 'react-vtkjs-viewport';
|
} from 'react-vtkjs-viewport';
|
||||||
|
|
||||||
import setMPRLayout from './utils/setMPRLayout.js';
|
import setMPRLayout from './utils/setMPRLayout.js';
|
||||||
import setViewportToVTK from './utils/setViewportToVTK.js';
|
import setViewportToVTK from './utils/setViewportToVTK.js';
|
||||||
import vtkViewportSubscriptionManager from './utils/vtkViewportSubscriptionManager.js';
|
|
||||||
import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
|
|
||||||
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
|
|
||||||
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
|
|
||||||
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants.js';
|
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants.js';
|
||||||
|
|
||||||
const { BlendMode } = Constants;
|
const { BlendMode } = Constants;
|
||||||
|
|
||||||
// TODO: Put this somewhere else
|
// TODO: Put this somewhere else
|
||||||
let apis = {};
|
let apis = {};
|
||||||
let currentSlabThickness = 0.1;
|
|
||||||
let defaultSlabThickness = 0.1;
|
|
||||||
|
|
||||||
function getCrosshairCallbackForIndex(index) {
|
|
||||||
return ({ worldPos }) => {
|
|
||||||
// Set camera focal point to world coordinate for linked views
|
|
||||||
apis.forEach((api, viewportIndex) => {
|
|
||||||
if (viewportIndex !== index) {
|
|
||||||
// We are basically doing the same as getSlice but with the world coordinate
|
|
||||||
// that we want to jump to instead of the camera focal point.
|
|
||||||
// I would rather do the camera adjustment directly but I keep
|
|
||||||
// doing it wrong and so this is good enough for now.
|
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
|
||||||
|
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
|
||||||
const sliceNormal = istyle.getSliceNormal();
|
|
||||||
const transform = vtkMatrixBuilder
|
|
||||||
.buildFromDegree()
|
|
||||||
.identity()
|
|
||||||
.rotateFromDirections(sliceNormal, [1, 0, 0]);
|
|
||||||
|
|
||||||
const mutatedWorldPos = worldPos.slice();
|
|
||||||
transform.apply(mutatedWorldPos);
|
|
||||||
const slice = mutatedWorldPos[0];
|
|
||||||
|
|
||||||
istyle.setSlice(slice);
|
|
||||||
|
|
||||||
renderWindow.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderer = api.genericRenderWindow.getRenderer();
|
|
||||||
const wPos = vtkCoordinate.newInstance();
|
|
||||||
wPos.setCoordinateSystemToWorld();
|
|
||||||
wPos.setValue(worldPos);
|
|
||||||
|
|
||||||
const displayPosition = wPos.getComputedDisplayValue(renderer);
|
|
||||||
const { svgWidgetManager } = api;
|
|
||||||
api.svgWidgets.crosshairsWidget.setPoint(
|
|
||||||
displayPosition[0],
|
|
||||||
displayPosition[1]
|
|
||||||
);
|
|
||||||
svgWidgetManager.render();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function _getActiveViewportVTKApi(viewports) {
|
async function _getActiveViewportVTKApi(viewports) {
|
||||||
const {
|
const {
|
||||||
@ -105,8 +55,6 @@ async function _getActiveViewportVTKApi(viewports) {
|
|||||||
|
|
||||||
function _setView(api, sliceNormal, viewUp) {
|
function _setView(api, sliceNormal, viewUp) {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
const renderer = api.genericRenderWindow.getRenderer();
|
|
||||||
const camera = renderer.getActiveCamera();
|
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||||
istyle.setSliceNormal(...sliceNormal);
|
istyle.setSliceNormal(...sliceNormal);
|
||||||
istyle.setViewUp(...viewUp);
|
istyle.setViewUp(...viewUp);
|
||||||
@ -114,41 +62,6 @@ function _setView(api, sliceNormal, viewUp) {
|
|||||||
renderWindow.render();
|
renderWindow.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchMPRInteractors(api, istyle) {
|
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
|
||||||
const currentIStyle = renderWindow.getInteractor().getInteractorStyle();
|
|
||||||
|
|
||||||
let currentViewport;
|
|
||||||
if (currentIStyle.getViewport && istyle.getViewport) {
|
|
||||||
currentViewport = currentIStyle.getViewport();
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentSlabThickness;
|
|
||||||
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
|
||||||
currentSlabThickness = currentIStyle.getSlabThickness();
|
|
||||||
defaultSlabThickness = currentSlabThickness;
|
|
||||||
}
|
|
||||||
|
|
||||||
const interactor = renderWindow.getInteractor();
|
|
||||||
|
|
||||||
interactor.setInteractorStyle(istyle);
|
|
||||||
|
|
||||||
// TODO: Not sure why this is required the second time this function is called
|
|
||||||
istyle.setInteractor(interactor);
|
|
||||||
|
|
||||||
if (currentViewport) {
|
|
||||||
istyle.setViewport(currentViewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (istyle.getVolumeMapper() !== api.volumes[0]) {
|
|
||||||
if (currentSlabThickness) {
|
|
||||||
istyle.setSlabThickness(currentSlabThickness);
|
|
||||||
}
|
|
||||||
|
|
||||||
istyle.setVolumeMapper(api.volumes[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
axial: async ({ viewports }) => {
|
axial: async ({ viewports }) => {
|
||||||
const api = await _getActiveViewportVTKApi(viewports);
|
const api = await _getActiveViewportVTKApi(viewports);
|
||||||
@ -175,52 +88,48 @@ const actions = {
|
|||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const istyle = vtkInteractorStyleMPRRotate.newInstance();
|
const istyle = vtkInteractorStyleMPRRotate.newInstance();
|
||||||
|
|
||||||
switchMPRInteractors(api, istyle);
|
api.setInteractorStyle({ istyle });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
enableCrosshairsTool: () => {
|
enableCrosshairsTool: () => {
|
||||||
apis.forEach((api, index) => {
|
apis.forEach((api, apiIndex) => {
|
||||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||||
|
|
||||||
switchMPRInteractors(api, istyle);
|
api.setInteractorStyle({
|
||||||
|
istyle,
|
||||||
istyle.setCallback(getCrosshairCallbackForIndex(index));
|
configuration: { apis, apiIndex },
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
enableLevelTool: () => {
|
enableLevelTool: () => {
|
||||||
|
const callbacks = {
|
||||||
|
setOnLevelsChanged: ({ windowCenter, windowWidth }) => {
|
||||||
|
apis.forEach(api => {
|
||||||
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
|
|
||||||
|
renderWindow.render();
|
||||||
|
|
||||||
|
api.updateVOI(windowWidth, windowCenter);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const istyle = vtkInteractorStyleMPRWindowLevel.newInstance();
|
const istyle = vtkInteractorStyleMPRWindowLevel.newInstance();
|
||||||
|
|
||||||
switchMPRInteractors(api, istyle);
|
api.setInteractorStyle({ istyle, callbacks });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setSlabThickness: ({ slabThickness }) => {
|
setSlabThickness: ({ slabThickness }) => {
|
||||||
currentSlabThickness = slabThickness;
|
|
||||||
|
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
api.setSlabThickness(slabThickness);
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
|
||||||
|
|
||||||
if (istyle.setSlabThickness) {
|
|
||||||
istyle.setSlabThickness(currentSlabThickness);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderWindow.render();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
changeSlabThickness: ({ change }) => {
|
changeSlabThickness: ({ change }) => {
|
||||||
currentSlabThickness += change;
|
|
||||||
currentSlabThickness = Math.max(currentSlabThickness, 0.1);
|
|
||||||
|
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const slabThickness = Math.max(api.getSlabThickness() + change, 0.1);
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
|
||||||
|
|
||||||
if (istyle.setSlabThickness) {
|
api.setSlabThickness(slabThickness);
|
||||||
istyle.setSlabThickness(currentSlabThickness);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderWindow.render();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setBlendModeToComposite: () => {
|
setBlendModeToComposite: () => {
|
||||||
@ -228,13 +137,15 @@ const actions = {
|
|||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||||
|
|
||||||
|
const slabThickness = api.getSlabThickness();
|
||||||
|
|
||||||
const mapper = api.volumes[0].getMapper();
|
const mapper = api.volumes[0].getMapper();
|
||||||
if (mapper.setBlendModeToComposite) {
|
if (mapper.setBlendModeToComposite) {
|
||||||
mapper.setBlendModeToComposite();
|
mapper.setBlendModeToComposite();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (istyle.setSlabThickness) {
|
if (istyle.setSlabThickness) {
|
||||||
istyle.setSlabThickness(defaultSlabThickness);
|
istyle.setSlabThickness(slabThickness);
|
||||||
}
|
}
|
||||||
renderWindow.render();
|
renderWindow.render();
|
||||||
});
|
});
|
||||||
@ -252,7 +163,6 @@ const actions = {
|
|||||||
setBlendMode: ({ blendMode }) => {
|
setBlendMode: ({ blendMode }) => {
|
||||||
apis.forEach(api => {
|
apis.forEach(api => {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
|
||||||
|
|
||||||
api.volumes[0].getMapper().setBlendMode(blendMode);
|
api.volumes[0].getMapper().setBlendMode(blendMode);
|
||||||
|
|
||||||
@ -264,28 +174,8 @@ const actions = {
|
|||||||
const displaySet =
|
const displaySet =
|
||||||
viewports.viewportSpecificData[viewports.activeViewportIndex];
|
viewports.viewportSpecificData[viewports.activeViewportIndex];
|
||||||
|
|
||||||
// TODO -> Clean this logic up a bit.
|
// Get current VOI if cornerstone viewport.
|
||||||
const cornerstoneElement = cornerstone.getEnabledElement(displaySet.dom);
|
const cornerstoneVOI = getVOIFromCornerstoneViewport(displaySet);
|
||||||
|
|
||||||
let cornerstoneVOI;
|
|
||||||
|
|
||||||
if (cornerstoneElement) {
|
|
||||||
const imageId = cornerstoneElement.image.imageId;
|
|
||||||
|
|
||||||
const { modality } = cornerstone.metaData.get(
|
|
||||||
'generalSeriesModule',
|
|
||||||
imageId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (modality !== 'PT') {
|
|
||||||
const { windowWidth, windowCenter } = cornerstoneElement.viewport.voi;
|
|
||||||
|
|
||||||
cornerstoneVOI = {
|
|
||||||
windowWidth,
|
|
||||||
windowCenter,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewportProps = [
|
const viewportProps = [
|
||||||
{
|
{
|
||||||
@ -295,7 +185,6 @@ const actions = {
|
|||||||
viewUp: [0, -1, 0],
|
viewUp: [0, -1, 0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// Sagital
|
// Sagital
|
||||||
orientation: {
|
orientation: {
|
||||||
@ -312,77 +201,29 @@ const actions = {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let apiByViewport;
|
|
||||||
try {
|
try {
|
||||||
apiByViewport = await setMPRLayout(displaySet, viewportProps);
|
apis = await setMPRLayout(displaySet, viewportProps, 1, 3);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
apis = apiByViewport;
|
|
||||||
|
|
||||||
const rgbTransferFunction = apiByViewport[0].volumes[0]
|
|
||||||
.getProperty()
|
|
||||||
.getRGBTransferFunction(0);
|
|
||||||
|
|
||||||
if (cornerstoneVOI) {
|
if (cornerstoneVOI) {
|
||||||
const { windowWidth, windowCenter } = cornerstoneVOI;
|
setVOI(cornerstoneVOI);
|
||||||
const lower = windowCenter - windowWidth / 2.0;
|
|
||||||
const upper = windowCenter + windowWidth / 2.0;
|
|
||||||
|
|
||||||
rgbTransferFunction.setRange(lower, upper);
|
|
||||||
|
|
||||||
apiByViewport.forEach(api => {
|
|
||||||
api.updateVOI(windowWidth, windowCenter);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onModifiedSubscription = rgbTransferFunction.onModified(() => {
|
// Add widgets and set default interactorStyle of each viewport.
|
||||||
const range = rgbTransferFunction.getMappingRange();
|
apis.forEach((api, apiIndex) => {
|
||||||
const windowWidth = Math.abs(range[1] - range[0]);
|
api.addSVGWidget(
|
||||||
const windowCenter = range[0] + windowWidth / 2;
|
vtkSVGCrosshairsWidget.newInstance(),
|
||||||
|
'crosshairsWidget'
|
||||||
apiByViewport.forEach(api => {
|
);
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
|
||||||
|
|
||||||
renderWindow.render();
|
|
||||||
|
|
||||||
api.updateVOI(windowWidth, windowCenter);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
vtkViewportSubscriptionManager.pushSubscription(0, onModifiedSubscription);
|
|
||||||
|
|
||||||
apiByViewport.forEach((api, index) => {
|
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
|
||||||
const renderer = api.genericRenderWindow.getRenderer();
|
|
||||||
|
|
||||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
|
||||||
|
|
||||||
istyle.setVolumeMapper(api.volumes[0]);
|
api.setInteractorStyle({
|
||||||
istyle.setCallback(getCrosshairCallbackForIndex(index));
|
istyle,
|
||||||
|
configuration: { apis, apiIndex },
|
||||||
const svgWidgetManager = vtkSVGWidgetManager.newInstance();
|
});
|
||||||
svgWidgetManager.setRenderer(renderer);
|
|
||||||
svgWidgetManager.setScale(1);
|
|
||||||
|
|
||||||
const crosshairsWidget = vtkSVGCrosshairsWidget.newInstance();
|
|
||||||
|
|
||||||
svgWidgetManager.addWidget(crosshairsWidget);
|
|
||||||
svgWidgetManager.render();
|
|
||||||
|
|
||||||
api.svgWidgetManager = svgWidgetManager;
|
|
||||||
api.svgWidgets = {
|
|
||||||
crosshairsWidget,
|
|
||||||
};
|
|
||||||
|
|
||||||
const orientation = api.getOrientation();
|
|
||||||
|
|
||||||
istyle.setViewUp(...orientation.viewUp);
|
|
||||||
istyle.setSliceNormal(...orientation.sliceNormal);
|
|
||||||
|
|
||||||
renderWindow.render();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -472,3 +313,41 @@ export default {
|
|||||||
definitions,
|
definitions,
|
||||||
defaultContext: 'ACTIVE_VIEWPORT::VTK',
|
defaultContext: 'ACTIVE_VIEWPORT::VTK',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getVOIFromCornerstoneViewport(displaySet) {
|
||||||
|
const cornerstoneElement = cornerstone.getEnabledElement(displaySet.dom);
|
||||||
|
|
||||||
|
if (cornerstoneElement) {
|
||||||
|
const imageId = cornerstoneElement.image.imageId;
|
||||||
|
|
||||||
|
const { modality } = cornerstone.metaData.get(
|
||||||
|
'generalSeriesModule',
|
||||||
|
imageId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (modality !== 'PT') {
|
||||||
|
const { windowWidth, windowCenter } = cornerstoneElement.viewport.voi;
|
||||||
|
|
||||||
|
return {
|
||||||
|
windowWidth,
|
||||||
|
windowCenter,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setVOI(voi) {
|
||||||
|
const { windowWidth, windowCenter } = voi;
|
||||||
|
const lower = windowCenter - windowWidth / 2.0;
|
||||||
|
const upper = windowCenter + windowWidth / 2.0;
|
||||||
|
|
||||||
|
const rgbTransferFunction = apis[0].volumes[0]
|
||||||
|
.getProperty()
|
||||||
|
.getRGBTransferFunction(0);
|
||||||
|
|
||||||
|
rgbTransferFunction.setRange(lower, upper);
|
||||||
|
|
||||||
|
apis.forEach(api => {
|
||||||
|
api.updateVOI(windowWidth, windowCenter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export default function setMPRLayout(
|
|||||||
displaySet,
|
displaySet,
|
||||||
viewportPropsArray,
|
viewportPropsArray,
|
||||||
numRows = 1,
|
numRows = 1,
|
||||||
numColumns = 3
|
numColumns = 1
|
||||||
) {
|
) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const viewports = [];
|
const viewports = [];
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
const subscriptions = [];
|
|
||||||
|
|
||||||
// This is pretty hacky right now, but it makes sure we don't keep adding subscriptions.
|
|
||||||
// TODO -> Nuke this and move it up a layer once we have more vigorous layout support.
|
|
||||||
|
|
||||||
const vtkViewportSubscriptionManager = {
|
|
||||||
subscriptions,
|
|
||||||
pushSubscription(viewportIndex, subscription) {
|
|
||||||
if (!Array.isArray(subscriptions[viewportIndex])) {
|
|
||||||
subscriptions[viewportIndex] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions[viewportIndex].push(subscription);
|
|
||||||
},
|
|
||||||
unsubscribe(viewportIndex) {
|
|
||||||
if (!subscriptions[viewportIndex]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (subscriptions[viewportIndex].length) {
|
|
||||||
subscriptions[viewportIndex].pop().unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions[viewportIndex] = null;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default vtkViewportSubscriptionManager;
|
|
||||||
Loading…
Reference in New Issue
Block a user