Merge pull request #993 from JamesAPetts/vtkViewportSubscriptionManager
feat: 🎸 Synced Window Leveling
This commit is contained in:
commit
7709ebb107
@ -1,16 +1,17 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import { getImageData, loadImageData } from "react-vtkjs-viewport";
|
import { getImageData, loadImageData } from 'react-vtkjs-viewport';
|
||||||
|
|
||||||
import ConnectedVTKViewport from "./ConnectedVTKViewport";
|
import ConnectedVTKViewport from './ConnectedVTKViewport';
|
||||||
import LoadingIndicator from "./LoadingIndicator.js";
|
import LoadingIndicator from './LoadingIndicator.js';
|
||||||
import OHIF from "@ohif/core";
|
import OHIF from '@ohif/core';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cornerstone from "cornerstone-core";
|
import cornerstone from 'cornerstone-core';
|
||||||
import handleSegmentationStorage from "./handleSegmentationStorage.js";
|
import handleSegmentationStorage from './handleSegmentationStorage.js';
|
||||||
import vtkDataArray from "vtk.js/Sources/Common/Core/DataArray";
|
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;
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ cornerstone.metaData.addProvider(
|
|||||||
StackManager.setMetadataProvider(metadataProvider);
|
StackManager.setMetadataProvider(metadataProvider);
|
||||||
|
|
||||||
const SOP_CLASSES = {
|
const SOP_CLASSES = {
|
||||||
SEGMENTATION_STORAGE: "1.2.840.10008.5.1.4.1.1.66.4"
|
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4',
|
||||||
};
|
};
|
||||||
|
|
||||||
const specialCaseHandlers = {};
|
const specialCaseHandlers = {};
|
||||||
@ -42,7 +43,7 @@ const volumeCache = {};
|
|||||||
*/
|
*/
|
||||||
function createLabelMapImageData(backgroundImageData) {
|
function createLabelMapImageData(backgroundImageData) {
|
||||||
const labelMapData = vtkImageData.newInstance(
|
const labelMapData = vtkImageData.newInstance(
|
||||||
backgroundImageData.get("spacing", "origin", "direction")
|
backgroundImageData.get('spacing', 'origin', 'direction')
|
||||||
);
|
);
|
||||||
labelMapData.setDimensions(backgroundImageData.getDimensions());
|
labelMapData.setDimensions(backgroundImageData.getDimensions());
|
||||||
labelMapData.computeTransforms();
|
labelMapData.computeTransforms();
|
||||||
@ -50,7 +51,7 @@ function createLabelMapImageData(backgroundImageData) {
|
|||||||
const values = new Uint8Array(backgroundImageData.getNumberOfPoints());
|
const values = new Uint8Array(backgroundImageData.getNumberOfPoints());
|
||||||
const dataArray = vtkDataArray.newInstance({
|
const dataArray = vtkDataArray.newInstance({
|
||||||
numberOfComponents: 1, // labelmap with single component
|
numberOfComponents: 1, // labelmap with single component
|
||||||
values
|
values,
|
||||||
});
|
});
|
||||||
labelMapData.getPointData().setScalars(dataArray);
|
labelMapData.getPointData().setScalars(dataArray);
|
||||||
|
|
||||||
@ -61,24 +62,24 @@ class OHIFVTKViewport extends Component {
|
|||||||
state = {
|
state = {
|
||||||
volumes: null,
|
volumes: null,
|
||||||
paintFilterLabelMapImageData: null,
|
paintFilterLabelMapImageData: null,
|
||||||
paintFilterBackgroundImageData: null
|
paintFilterBackgroundImageData: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
studies: PropTypes.object,
|
studies: PropTypes.object,
|
||||||
displaySet: PropTypes.object,
|
displaySet: PropTypes.object,
|
||||||
viewportIndex: PropTypes.number,
|
viewportIndex: PropTypes.number,
|
||||||
children: PropTypes.node
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
static id = "OHIFVTKViewport";
|
static id = 'OHIFVTKViewport';
|
||||||
|
|
||||||
static init() {
|
static init() {
|
||||||
console.log("OHIFVTKViewport init()");
|
console.log('OHIFVTKViewport init()');
|
||||||
}
|
}
|
||||||
|
|
||||||
static destroy() {
|
static destroy() {
|
||||||
console.log("OHIFVTKViewport destroy()");
|
console.log('OHIFVTKViewport destroy()');
|
||||||
StackManager.clearStacks();
|
StackManager.clearStacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +110,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
} else if (sopInstanceUid) {
|
} else if (sopInstanceUid) {
|
||||||
const index = stack.imageIds.findIndex(imageId => {
|
const index = stack.imageIds.findIndex(imageId => {
|
||||||
const sopCommonModule = cornerstone.metaData.get(
|
const sopCommonModule = cornerstone.metaData.get(
|
||||||
"sopCommonModule",
|
'sopCommonModule',
|
||||||
imageId
|
imageId
|
||||||
);
|
);
|
||||||
if (!sopCommonModule) {
|
if (!sopCommonModule) {
|
||||||
@ -151,7 +152,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
|
|
||||||
switch (sopClassUid) {
|
switch (sopClassUid) {
|
||||||
case SOP_CLASSES.SEGMENTATION_STORAGE:
|
case SOP_CLASSES.SEGMENTATION_STORAGE:
|
||||||
throw new Error("Not yet implemented");
|
throw new Error('Not yet implemented');
|
||||||
|
|
||||||
const data = handleSegmentationStorage(
|
const data = handleSegmentationStorage(
|
||||||
stack.imageIds,
|
stack.imageIds,
|
||||||
@ -164,7 +165,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
return loadImageData(imageDataObject).then(() => {
|
return loadImageData(imageDataObject).then(() => {
|
||||||
return {
|
return {
|
||||||
data: imageDataObject.vtkImageData,
|
data: imageDataObject.vtkImageData,
|
||||||
labelmap: labelmapDataObject
|
labelmap: labelmapDataObject,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
@ -172,7 +173,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
|
|
||||||
return loadImageData(imageDataObject).then(() => {
|
return loadImageData(imageDataObject).then(() => {
|
||||||
return {
|
return {
|
||||||
data: imageDataObject.vtkImageData
|
data: imageDataObject.vtkImageData,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -189,10 +190,16 @@ class OHIFVTKViewport extends Component {
|
|||||||
volumeActor.setMapper(volumeMapper);
|
volumeActor.setMapper(volumeMapper);
|
||||||
volumeMapper.setInputData(data);
|
volumeMapper.setInputData(data);
|
||||||
|
|
||||||
const range = data.getPointData().getScalars().getRange();
|
const range = data
|
||||||
|
.getPointData()
|
||||||
|
.getScalars()
|
||||||
|
.getRange();
|
||||||
|
|
||||||
// TODO: For PET we might want to just set this to 0-5 SUV
|
// TODO: For PET we might want to just set this to 0-5 SUV
|
||||||
volumeActor.getProperty().getRGBTransferFunction(0).setRange(range[0], range[1]);
|
volumeActor
|
||||||
|
.getProperty()
|
||||||
|
.getRGBTransferFunction(0)
|
||||||
|
.setRange(range[0], range[1]);
|
||||||
|
|
||||||
// TODO: Should look into implementing autoAdjustSampleDistance in vtk
|
// TODO: Should look into implementing autoAdjustSampleDistance in vtk
|
||||||
const sampleDistance =
|
const sampleDistance =
|
||||||
@ -200,7 +207,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
Math.sqrt(
|
Math.sqrt(
|
||||||
data
|
data
|
||||||
.getSpacing()
|
.getSpacing()
|
||||||
.map((v) => v * v)
|
.map(v => v * v)
|
||||||
.reduce((a, b) => a + b, 0)
|
.reduce((a, b) => a + b, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -218,12 +225,12 @@ class OHIFVTKViewport extends Component {
|
|||||||
displaySetInstanceUid,
|
displaySetInstanceUid,
|
||||||
sopClassUids,
|
sopClassUids,
|
||||||
sopInstanceUid,
|
sopInstanceUid,
|
||||||
frameIndex
|
frameIndex,
|
||||||
} = displaySet;
|
} = displaySet;
|
||||||
|
|
||||||
if (sopClassUids.length > 1) {
|
if (sopClassUids.length > 1) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"More than one SOPClassUid in the same series is not yet supported."
|
'More than one SOPClassUid in the same series is not yet supported.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +256,7 @@ class OHIFVTKViewport extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
volumes: [volumeActor],
|
volumes: [volumeActor],
|
||||||
paintFilterBackgroundImageData: data,
|
paintFilterBackgroundImageData: data,
|
||||||
paintFilterLabelMapImageData: labelmap
|
paintFilterLabelMapImageData: labelmap,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +264,11 @@ class OHIFVTKViewport extends Component {
|
|||||||
this.setStateFromProps();
|
this.setStateFromProps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
console.log(this.props.viewportIndex);
|
||||||
|
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;
|
||||||
@ -279,12 +291,12 @@ class OHIFVTKViewport extends Component {
|
|||||||
childrenWithProps = this.props.children.map((child, index) => {
|
childrenWithProps = this.props.children.map((child, index) => {
|
||||||
return React.cloneElement(child, {
|
return React.cloneElement(child, {
|
||||||
viewportIndex: this.props.viewportIndex,
|
viewportIndex: this.props.viewportIndex,
|
||||||
key: index
|
key: index,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = { width: "100%", height: "100%", position: "relative" };
|
const style = { width: '100%', height: '100%', position: 'relative' };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
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 vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
|
||||||
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
|
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
|
||||||
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
|
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
|
||||||
@ -263,16 +264,19 @@ const actions = {
|
|||||||
|
|
||||||
apis = apiByViewport;
|
apis = apiByViewport;
|
||||||
|
|
||||||
/*const rgbTransferFunction = apiByViewport[0].volumes[0]
|
const rgbTransferFunction = apiByViewport[0].volumes[0]
|
||||||
.getProperty()
|
.getProperty()
|
||||||
.getRGBTransferFunction(0);
|
.getRGBTransferFunction(0);
|
||||||
rgbTransferFunction.onModified(() => {
|
|
||||||
|
const onModifiedSubscription = rgbTransferFunction.onModified(() => {
|
||||||
apiByViewport.forEach(a => {
|
apiByViewport.forEach(a => {
|
||||||
const renderWindow = a.genericRenderWindow.getRenderWindow();
|
const renderWindow = a.genericRenderWindow.getRenderWindow();
|
||||||
|
|
||||||
renderWindow.render();
|
renderWindow.render();
|
||||||
});
|
});
|
||||||
});*/
|
});
|
||||||
|
|
||||||
|
vtkViewportSubscriptionManager.pushSubscription(0, onModifiedSubscription);
|
||||||
|
|
||||||
apiByViewport.forEach((api, index) => {
|
apiByViewport.forEach((api, index) => {
|
||||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||||
|
|||||||
28
extensions/vtk/src/utils/vtkViewportSubscriptionManager.js
Normal file
28
extensions/vtk/src/utils/vtkViewportSubscriptionManager.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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;
|
||||||
10
yarn.lock
10
yarn.lock
@ -2272,6 +2272,16 @@
|
|||||||
once "^1.4.0"
|
once "^1.4.0"
|
||||||
universal-user-agent "^4.0.0"
|
universal-user-agent "^4.0.0"
|
||||||
|
|
||||||
|
"@ohif/extension-cornerstone@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ohif/extension-cornerstone/-/extension-cornerstone-2.0.0.tgz#b4ee3b594212502192cdd311a100354857280548"
|
||||||
|
integrity sha512-hvJ3t2GRcu906NiYpUWaJIB9ja/M/MKEYLy19t4XBFpqf4VqoezR2KJpZelmZjQscXGaDQeZgvr3DJO5Nva8Uw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.5.5"
|
||||||
|
classnames "^2.2.6"
|
||||||
|
lodash.throttle "^4.1.1"
|
||||||
|
react-cornerstone-viewport "0.1.30"
|
||||||
|
|
||||||
"@ohif/i18n@^0.2.3":
|
"@ohif/i18n@^0.2.3":
|
||||||
version "0.2.5"
|
version "0.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/@ohif/i18n/-/i18n-0.2.5.tgz#2b92a78109823ce0f50dd590201d980a5fd64974"
|
resolved "https://registry.yarnpkg.com/@ohif/i18n/-/i18n-0.2.5.tgz#2b92a78109823ce0f50dd590201d980a5fd64974"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user