@ohif/extension-vtk: Add basic MIP and Slab Thickness controls. UI to be updated later (#685)
This commit is contained in:
parent
2fd60f3109
commit
d8b4a4d4c0
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-vtk",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@ -39,7 +39,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"react-vtkjs-viewport": "0.0.10",
|
||||
"react-vtkjs-viewport": "0.0.11",
|
||||
"vtk.js": "^8.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
vtkInteractorStyleMPRCrosshairs,
|
||||
vtkInteractorStyleMPRSlice,
|
||||
vtkInteractorStyleMPRWindowLevel,
|
||||
vtkInteractorStyleMPRSlice,
|
||||
vtkSVGCrosshairsWidget,
|
||||
vtkSVGWidgetManager,
|
||||
} from 'react-vtkjs-viewport';
|
||||
@ -11,9 +11,13 @@ import setViewportToVTK from './utils/setViewportToVTK.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';
|
||||
|
||||
const { BlendMode } = Constants;
|
||||
|
||||
// TODO: Put this somewhere else
|
||||
let apis = {};
|
||||
let currentSlabThickness = 0.1;
|
||||
|
||||
function getCrosshairCallbackForIndex(index) {
|
||||
return ({ worldPos }) => {
|
||||
@ -96,26 +100,24 @@ function _setView(api, sliceNormal, viewUp) {
|
||||
istyle.setSliceNormal(...sliceNormal);
|
||||
camera.setViewUp(...viewUp);
|
||||
|
||||
api.volumes[0].getMapper().setSampleDistance(5.0);
|
||||
api.volumes[0].getMapper().setMaximumSamplesPerRay(2000);
|
||||
|
||||
renderWindow.render();
|
||||
}
|
||||
|
||||
function switchMPRInteractors(api, istyle) {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
const currentIStyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
let currentNormal;
|
||||
if (istyle.getSliceNormal) {
|
||||
currentNormal = istyle.getSliceNormal();
|
||||
if (currentIStyle.getSliceNormal && istyle.getSliceNormal) {
|
||||
currentNormal = currentIStyle.getSliceNormal();
|
||||
}
|
||||
|
||||
// TODO: This is a hacky workaround because disabling the vtkInteractorStyleMPRSlice is currently
|
||||
// broken. The camera.onModified is never removed. (https://github.com/Kitware/vtk-js/issues/1110)
|
||||
renderWindow
|
||||
.getInteractor()
|
||||
.getInteractorStyle()
|
||||
.setInteractor(null);
|
||||
let currentSlabThickness;
|
||||
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
||||
currentSlabThickness = currentIStyle.getSlabThickness();
|
||||
}
|
||||
|
||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||
|
||||
@ -126,6 +128,11 @@ function switchMPRInteractors(api, istyle) {
|
||||
if (currentNormal) {
|
||||
istyle.setSliceNormal(currentNormal);
|
||||
}
|
||||
|
||||
if (currentSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
}
|
||||
|
||||
istyle.setVolumeMapper(api.volumes[0]);
|
||||
}
|
||||
}
|
||||
@ -152,14 +159,14 @@ const actions = {
|
||||
|
||||
_setView(api, [0, 1, 0], [0, 0, 1]);
|
||||
},
|
||||
enableRotateTool: async ({ viewports }) => {
|
||||
enableRotateTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRSlice.newInstance();
|
||||
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
},
|
||||
enableCrosshairsTool: async ({ viewports }) => {
|
||||
enableCrosshairsTool: () => {
|
||||
apis.forEach((api, index) => {
|
||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||
|
||||
@ -168,13 +175,61 @@ const actions = {
|
||||
istyle.setCallback(getCrosshairCallbackForIndex(index));
|
||||
});
|
||||
},
|
||||
enableLevelTool: async ({ viewports }) => {
|
||||
enableLevelTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRWindowLevel.newInstance();
|
||||
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
},
|
||||
setSlabThickness: slabThickness => {
|
||||
currentSlabThickness = slabThickness;
|
||||
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
|
||||
// TODO: Do this inside the interactors in a setSlabThickness function instead
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
const dist = camera.getDistance();
|
||||
const near = dist - currentSlabThickness / 2;
|
||||
const far = dist + currentSlabThickness / 2;
|
||||
|
||||
camera.setClippingRange(near, far);
|
||||
}
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
changeSlabThickness: ({ change }) => {
|
||||
currentSlabThickness += change;
|
||||
currentSlabThickness = Math.max(currentSlabThickness, 0.1);
|
||||
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
}
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
setBlendMode: ({ blendMode }) => {
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
api.volumes[0].getMapper().setBlendMode(blendMode);
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
mpr2d: async ({ viewports }) => {
|
||||
const displaySet =
|
||||
viewports.viewportSpecificData[viewports.activeViewportIndex];
|
||||
@ -199,20 +254,11 @@ const actions = {
|
||||
});
|
||||
});*/
|
||||
|
||||
apis[0].volumes[0].getMapper().setSampleDistance(1.5);
|
||||
|
||||
apiByViewport.forEach((api, index) => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
|
||||
// TODO: This is a hacky workaround because disabling the vtkInteractorStyleMPRSlice is currently
|
||||
// broken. The camera.onModified is never removed. (https://github.com/Kitware/vtk-js/issues/1110)
|
||||
renderWindow
|
||||
.getInteractor()
|
||||
.getInteractorStyle()
|
||||
.setInteractor(null);
|
||||
|
||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||
|
||||
@ -258,6 +304,8 @@ const actions = {
|
||||
},
|
||||
};
|
||||
|
||||
window.vtkActions = actions;
|
||||
|
||||
const definitions = {
|
||||
axial: {
|
||||
commandFn: actions.axial,
|
||||
@ -276,19 +324,59 @@ const definitions = {
|
||||
},
|
||||
enableRotateTool: {
|
||||
commandFn: actions.enableRotateTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
enableCrosshairsTool: {
|
||||
commandFn: actions.enableCrosshairsTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
enableLevelTool: {
|
||||
commandFn: actions.enableLevelTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
setBlendModeToComposite: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.COMPOSITE_BLEND },
|
||||
},
|
||||
setBlendModeToMaximumIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
|
||||
},
|
||||
setBlendModeToMinimumIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.MINIMUM_INTENSITY_BLEND },
|
||||
},
|
||||
setBlendModeToAverageIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.AVERAGE_INTENSITY_BLEND },
|
||||
},
|
||||
setSlabThickness: {
|
||||
// TODO: How do we pass in a function argument?
|
||||
commandFn: actions.setSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
increaseSlabThickness: {
|
||||
commandFn: actions.changeSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {
|
||||
change: 3,
|
||||
},
|
||||
},
|
||||
decreaseSlabThickness: {
|
||||
commandFn: actions.changeSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {
|
||||
change: -3,
|
||||
},
|
||||
},
|
||||
mpr2d: {
|
||||
commandFn: actions.mpr2d,
|
||||
storeContexts: ['viewports'],
|
||||
|
||||
@ -31,6 +31,43 @@ const definitions = [
|
||||
commandName: 'enableRotateTool',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToComposite',
|
||||
label: 'Disable MIP',
|
||||
icon: 'times',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'setBlendModeToComposite',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToMaximumIntensity',
|
||||
label: 'Enable MIP',
|
||||
icon: 'soft-tissue',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'setBlendModeToMaximumIntensity',
|
||||
commandOptions: {},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'increaseSlabThickness',
|
||||
label: 'Increase Slab Thickness',
|
||||
icon: 'caret-up',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'increaseSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'decreaseSlabThickness',
|
||||
label: 'Decrease Slab Thickness',
|
||||
icon: 'caret-down',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'decreaseSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
|
||||
@ -5519,10 +5519,10 @@ react-viewerbase@^0.15.1:
|
||||
react-i18next "^10.11.0"
|
||||
react-with-direction "1.3.0"
|
||||
|
||||
react-vtkjs-viewport@0.0.9:
|
||||
version "0.0.9"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.0.9.tgz#da79aa66f52dcd731bcc5abd2587cbb120a25331"
|
||||
integrity sha512-VwRCY2DPxWMhix4v3PAtdENp3U1p+Z9nKf1Ch5+KWRKF6fWeA+B2glYKMYNpPnP4bULzVz9iwV+Zeojt3gEibA==
|
||||
react-vtkjs-viewport@0.0.11:
|
||||
version "0.0.11"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.0.11.tgz#cedd993ca226502bf0417a3748a5b2f806522519"
|
||||
integrity sha512-ttWw7bU/lL/nJuaaKdtAc8448vMJmlRQzpkpuP/J+3lTzIQbQPCPU40LqgONjr7LvL5++61N2GJ8m+PRgHyfxQ==
|
||||
dependencies:
|
||||
moment "^2.24.0"
|
||||
|
||||
@ -6974,10 +6974,10 @@ void-elements@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
|
||||
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
|
||||
|
||||
vtk.js@^8.11.0:
|
||||
version "8.11.1"
|
||||
resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.11.1.tgz#cdf69705a72a2a3ce76d7442d1b3903e3de770d4"
|
||||
integrity sha512-Y5ZCFtoMOuuJt44fyj91Gqeg9ZeCQovyoJlEHG1oUHLPehQTvq0oW09WqBcxVSdiv92x3aXYWtgZjm/s4EWw7Q==
|
||||
vtk.js@^8.13.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.13.0.tgz#d22bbe3403d86f979703506f9be83ab8e5099248"
|
||||
integrity sha512-uoq2U0Yu2XjuKeeduuGRXlphHR6cdIvtZ5useNMJ8FobK9dpeFTT4ncoyPXx77KvwOMSueT8W+ngm/e9+FGZtA==
|
||||
dependencies:
|
||||
base64-js "1.2.1"
|
||||
blueimp-md5 "2.10.0"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user