irc_web/.svn/pristine/83/83b0f5045e0a14c75fe8ceff74d...

851 lines
26 KiB
Plaintext

import {
RenderingEngine,
Types,
Enums,
setVolumesForViewports,
volumeLoader,
getRenderingEngine,
} from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setTitleAndDescription,
setPetColorMapTransferFunctionForVolumeActor,
setPetTransferFunctionForVolumeActor,
setCtTransferFunctionForVolumeActor,
addDropdownToToolbar,
addButtonToToolbar,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';
const {
ToolGroupManager,
Enums: csToolsEnums,
WindowLevelTool,
PanTool,
ZoomTool,
StackScrollMouseWheelTool,
synchronizers,
MIPJumpToClickTool,
VolumeRotateMouseWheelTool,
CrosshairsTool,
TrackballRotateTool,
} = cornerstoneTools;
const { MouseBindings } = csToolsEnums;
const { ViewportType, BlendModes } = Enums;
const { createCameraPositionSynchronizer, createVOISynchronizer } =
synchronizers;
let renderingEngine;
const wadoRsRoot = 'https://d3t6nz73ql33tx.cloudfront.net/dicomweb';
const StudyInstanceUID =
'1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463';
const renderingEngineId = 'myRenderingEngine';
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
const ctVolumeName = 'CT_VOLUME_ID'; // Id of the volume less loader prefix
const ctVolumeId = `${volumeLoaderScheme}:${ctVolumeName}`; // VolumeId with loader id + volume id
const ptVolumeName = 'PT_VOLUME_ID';
const ptVolumeId = `${volumeLoaderScheme}:${ptVolumeName}`;
const ctToolGroupId = 'CT_TOOLGROUP_ID';
const ptToolGroupId = 'PT_TOOLGROUP_ID';
const fusionToolGroupId = 'FUSION_TOOLGROUP_ID';
const mipToolGroupUID = 'MIP_TOOLGROUP_ID';
let ctImageIds;
let ptImageIds;
let ctVolume;
let ptVolume;
const axialCameraSynchronizerId = 'AXIAL_CAMERA_SYNCHRONIZER_ID';
const sagittalCameraSynchronizerId = 'SAGITTAL_CAMERA_SYNCHRONIZER_ID';
const coronalCameraSynchronizerId = 'CORONAL_CAMERA_SYNCHRONIZER_ID';
const ctVoiSynchronizerId = 'CT_VOI_SYNCHRONIZER_ID';
const ptVoiSynchronizerId = 'PT_VOI_SYNCHRONIZER_ID';
let axialCameraPositionSynchronizer;
let sagittalCameraPositionSynchronizer;
let coronalCameraPositionSynchronizer;
let ctVoiSynchronizer;
let ptVoiSynchronizer;
let mipToolGroup;
const viewportIds = {
CT: { AXIAL: 'CT_AXIAL', SAGITTAL: 'CT_SAGITTAL', CORONAL: 'CT_CORONAL' },
PT: { AXIAL: 'PT_AXIAL', SAGITTAL: 'PT_SAGITTAL', CORONAL: 'PT_CORONAL' },
FUSION: {
AXIAL: 'FUSION_AXIAL',
SAGITTAL: 'FUSION_SAGITTAL',
CORONAL: 'FUSION_CORONAL',
},
PETMIP: {
CORONAL: 'PET_MIP_CORONAL',
},
};
// ======== Set up page ======== //
setTitleAndDescription(
'PET-CT',
'PT-CT fusion layout with Crosshairs, and synchronized cameras, CT W/L and PET threshold'
);
const optionsValues = [WindowLevelTool.toolName, CrosshairsTool.toolName];
// ============================= //
addDropdownToToolbar({
options: { values: optionsValues, defaultValue: WindowLevelTool.toolName },
onSelectedValueChange: (toolNameAsStringOrNumber) => {
const toolName = String(toolNameAsStringOrNumber);
[ctToolGroupId, ptToolGroupId, fusionToolGroupId].forEach((toolGroupId) => {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
// Set the other tools disabled so we don't get conflicts.
// Note we only strictly need to change the one which is currently active.
if (toolName === WindowLevelTool.toolName) {
// Set crosshairs passive so they are still interactable
toolGroup.setToolPassive(CrosshairsTool.toolName);
toolGroup.setToolActive(WindowLevelTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }],
});
} else {
toolGroup.setToolDisabled(WindowLevelTool.toolName);
toolGroup.setToolActive(CrosshairsTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }],
});
}
});
},
});
const resizeObserver = new ResizeObserver(() => {
console.log('Size changed');
renderingEngine = getRenderingEngine(renderingEngineId);
if (renderingEngine) {
renderingEngine.resize(true, false);
}
});
const viewportGrid = document.createElement('div');
viewportGrid.style.display = 'grid';
viewportGrid.style.gridTemplateRows = `[row1-start] 33% [row2-start] 33% [row3-start] 33% [end]`;
viewportGrid.style.gridTemplateColumns = `[col1-start] 20% [col2-start] 20% [col3-start] 20% [col4-start] 20% [col5-start] 20%[end]`;
viewportGrid.style.width = '95vw';
viewportGrid.style.height = '80vh';
const content = document.getElementById('content');
content.appendChild(viewportGrid);
const element1_1 = document.createElement('div');
const element1_2 = document.createElement('div');
const element1_3 = document.createElement('div');
const element2_1 = document.createElement('div');
const element2_2 = document.createElement('div');
const element2_3 = document.createElement('div');
const element3_1 = document.createElement('div');
const element3_2 = document.createElement('div');
const element3_3 = document.createElement('div');
const element_mip = document.createElement('div');
// Place main 3x3 viewports
element1_1.style.gridColumnStart = '1';
element1_1.style.gridRowStart = '1';
element1_2.style.gridColumnStart = '2';
element1_2.style.gridRowStart = '1';
element1_3.style.gridColumnStart = '3';
element1_3.style.gridRowStart = '1';
element2_1.style.gridColumnStart = '1';
element2_1.style.gridRowStart = '2';
element2_2.style.gridColumnStart = '2';
element2_2.style.gridRowStart = '2';
element2_3.style.gridColumnStart = '3';
element2_3.style.gridRowStart = '2';
element3_1.style.gridColumnStart = '1';
element3_1.style.gridRowStart = '3';
element3_2.style.gridColumnStart = '2';
element3_2.style.gridRowStart = '3';
element3_3.style.gridColumnStart = '3';
element3_3.style.gridRowStart = '3';
// Place MIP viewport
element_mip.style.gridColumnStart = '4';
element_mip.style.gridRowStart = '1';
element_mip.style.gridRowEnd = 'span 3';
viewportGrid.appendChild(element1_1);
viewportGrid.appendChild(element1_2);
viewportGrid.appendChild(element1_3);
viewportGrid.appendChild(element2_1);
viewportGrid.appendChild(element2_2);
viewportGrid.appendChild(element2_3);
viewportGrid.appendChild(element3_1);
viewportGrid.appendChild(element3_2);
viewportGrid.appendChild(element3_3);
viewportGrid.appendChild(element_mip);
const elements = [
element1_1,
element1_2,
element1_3,
element2_1,
element2_2,
element2_3,
element3_1,
element3_2,
element3_3,
];
elements.forEach((element) => {
element.style.width = '100%';
element.style.height = '100%';
// Disable right click context menu so we can have right click tools
element.oncontextmenu = (e) => e.preventDefault();
resizeObserver.observe(element);
});
element_mip.style.width = '100%';
element_mip.style.height = '100%';
element_mip.oncontextmenu = (e) => e.preventDefault();
resizeObserver.observe(element_mip);
const instructions = document.createElement('p');
instructions.innerText = `
Basic Controls:
- Left click: Use selected tool
- Middle click: Pan
- Right click: Zoom
- Mouse Wheel: Stack Scroll
Window Level Tool:
- Drag to set the window level for the CT and threshold for the PET.
Crosshairs:
- When the tool is active: Click/Drag anywhere in the viewport to move the center of the crosshairs.
- Drag a reference line to move it, scrolling the other views.
- Square (closest to center): Drag these to change the thickness of the MIP slab in that plane.
- Circle (further from center): Drag these to rotate the axes.
PET MIP:
- Mouse Wheel: Rotate PET
- Left click: Jump all views to the point of highest SUV in the region clicked.
Volume_3D Controls:
- Middle click : Rotate the image
- Mouse Wheel: Rotate PET
- Right click : Pan
- Left click: Jump all views to the point of highest SUV in the region clicked.
`;
instructions.style.gridColumnStart = '5';
instructions.style.gridRowStart = '1';
instructions.style.gridRowEnd = 'span 3';
viewportGrid.append(instructions);
// ============================= //
const viewportColors = {
[viewportIds.CT.AXIAL]: 'rgb(200, 0, 0)',
[viewportIds.CT.SAGITTAL]: 'rgb(200, 200, 0)',
[viewportIds.CT.CORONAL]: 'rgb(0, 200, 0)',
[viewportIds.PT.AXIAL]: 'rgb(200, 0, 0)',
[viewportIds.PT.SAGITTAL]: 'rgb(200, 200, 0)',
[viewportIds.PT.CORONAL]: 'rgb(0, 200, 0)',
[viewportIds.FUSION.AXIAL]: 'rgb(200, 0, 0)',
[viewportIds.FUSION.SAGITTAL]: 'rgb(200, 200, 0)',
[viewportIds.FUSION.CORONAL]: 'rgb(0, 200, 0)',
};
const viewportReferenceLineControllable = [
viewportIds.CT.AXIAL,
viewportIds.CT.SAGITTAL,
viewportIds.CT.CORONAL,
viewportIds.PT.AXIAL,
viewportIds.PT.SAGITTAL,
viewportIds.PT.CORONAL,
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
];
const viewportReferenceLineDraggableRotatable = [
viewportIds.CT.AXIAL,
viewportIds.CT.SAGITTAL,
viewportIds.CT.CORONAL,
viewportIds.PT.AXIAL,
viewportIds.PT.SAGITTAL,
viewportIds.PT.CORONAL,
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
];
const viewportReferenceLineSlabThicknessControlsOn = [
viewportIds.CT.AXIAL,
viewportIds.CT.SAGITTAL,
viewportIds.CT.CORONAL,
viewportIds.PT.AXIAL,
viewportIds.PT.SAGITTAL,
viewportIds.PT.CORONAL,
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
];
function getReferenceLineColor(viewportId) {
return viewportColors[viewportId];
}
function getReferenceLineControllable(viewportId) {
const index = viewportReferenceLineControllable.indexOf(viewportId);
return index !== -1;
}
function getReferenceLineDraggableRotatable(viewportId) {
const index = viewportReferenceLineDraggableRotatable.indexOf(viewportId);
return index !== -1;
}
function getReferenceLineSlabThicknessControlsOn(viewportId) {
const index =
viewportReferenceLineSlabThicknessControlsOn.indexOf(viewportId);
return index !== -1;
}
function setUpToolGroups() {
// Add tools to Cornerstone3D
cornerstoneTools.addTool(WindowLevelTool);
cornerstoneTools.addTool(PanTool);
cornerstoneTools.addTool(ZoomTool);
cornerstoneTools.addTool(StackScrollMouseWheelTool);
cornerstoneTools.addTool(MIPJumpToClickTool);
cornerstoneTools.addTool(VolumeRotateMouseWheelTool);
cornerstoneTools.addTool(CrosshairsTool);
cornerstoneTools.addTool(TrackballRotateTool);
// Define tool groups for the main 9 viewports.
// Crosshairs currently only supports 3 viewports for a toolgroup due to the
// way it is constructed, but its configuration input allows us to synchronize
// multiple sets of 3 viewports.
const ctToolGroup = ToolGroupManager.createToolGroup(ctToolGroupId);
const ptToolGroup = ToolGroupManager.createToolGroup(ptToolGroupId);
const fusionToolGroup = ToolGroupManager.createToolGroup(fusionToolGroupId);
ctToolGroup.addViewport(viewportIds.CT.AXIAL, renderingEngineId);
ctToolGroup.addViewport(viewportIds.CT.SAGITTAL, renderingEngineId);
ctToolGroup.addViewport(viewportIds.CT.CORONAL, renderingEngineId);
ptToolGroup.addViewport(viewportIds.PT.AXIAL, renderingEngineId);
ptToolGroup.addViewport(viewportIds.PT.SAGITTAL, renderingEngineId);
ptToolGroup.addViewport(viewportIds.PT.CORONAL, renderingEngineId);
fusionToolGroup.addViewport(viewportIds.FUSION.AXIAL, renderingEngineId);
fusionToolGroup.addViewport(viewportIds.FUSION.SAGITTAL, renderingEngineId);
fusionToolGroup.addViewport(viewportIds.FUSION.CORONAL, renderingEngineId);
// Manipulation Tools
[ctToolGroup, ptToolGroup].forEach((toolGroup) => {
toolGroup.addTool(PanTool.toolName);
toolGroup.addTool(ZoomTool.toolName);
toolGroup.addTool(StackScrollMouseWheelTool.toolName);
toolGroup.addTool(CrosshairsTool.toolName, {
getReferenceLineColor,
getReferenceLineControllable,
getReferenceLineDraggableRotatable,
getReferenceLineSlabThicknessControlsOn,
});
});
fusionToolGroup.addTool(PanTool.toolName);
fusionToolGroup.addTool(ZoomTool.toolName);
fusionToolGroup.addTool(StackScrollMouseWheelTool.toolName);
fusionToolGroup.addTool(CrosshairsTool.toolName, {
getReferenceLineColor,
getReferenceLineControllable,
getReferenceLineDraggableRotatable,
getReferenceLineSlabThicknessControlsOn,
// Only set CT volume to MIP in the fusion viewport
filterActorUIDsToSetSlabThickness: [ctVolumeId],
});
// Here is the difference in the toolGroups used, that we need to specify the
// volume to use for the WindowLevelTool for the fusion viewports
ctToolGroup.addTool(WindowLevelTool.toolName);
ptToolGroup.addTool(WindowLevelTool.toolName);
fusionToolGroup.addTool(WindowLevelTool.toolName, {
volumeId: ptVolumeId,
});
[ctToolGroup, ptToolGroup, fusionToolGroup].forEach((toolGroup) => {
toolGroup.setToolActive(WindowLevelTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});
toolGroup.setToolActive(PanTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Auxiliary, // Middle Click
},
],
});
toolGroup.setToolActive(ZoomTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Secondary, // Right Click
},
],
});
toolGroup.setToolActive(StackScrollMouseWheelTool.toolName);
toolGroup.setToolPassive(CrosshairsTool.toolName);
});
// MIP Tool Groups
mipToolGroup = ToolGroupManager.createToolGroup(mipToolGroupUID);
mipToolGroup.addTool('VolumeRotateMouseWheel');
mipToolGroup.addTool('MIPJumpToClickTool', {
toolGroupId: ptToolGroupId,
});
// Set the initial state of the tools, here we set one tool active on left click.
// This means left click will draw that tool.
mipToolGroup.setToolActive('MIPJumpToClickTool', {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});
// As the Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
// hook instead of mouse buttons, it does not need to assign any mouse button.
mipToolGroup.setToolActive('VolumeRotateMouseWheel');
mipToolGroup.addViewport(viewportIds.PETMIP.CORONAL, renderingEngineId);
console.debug(mipToolGroup);
}
function setUpSynchronizers() {
axialCameraPositionSynchronizer = createCameraPositionSynchronizer(
axialCameraSynchronizerId
);
sagittalCameraPositionSynchronizer = createCameraPositionSynchronizer(
sagittalCameraSynchronizerId
);
coronalCameraPositionSynchronizer = createCameraPositionSynchronizer(
coronalCameraSynchronizerId
);
ctVoiSynchronizer = createVOISynchronizer(ctVoiSynchronizerId);
ptVoiSynchronizer = createVOISynchronizer(ptVoiSynchronizerId);
// Add viewports to camera synchronizers
[
viewportIds.CT.AXIAL,
viewportIds.PT.AXIAL,
viewportIds.FUSION.AXIAL,
].forEach((viewportId) => {
axialCameraPositionSynchronizer.add({
renderingEngineId,
viewportId,
});
});
[
viewportIds.CT.SAGITTAL,
viewportIds.PT.SAGITTAL,
viewportIds.FUSION.SAGITTAL,
].forEach((viewportId) => {
sagittalCameraPositionSynchronizer.add({
renderingEngineId,
viewportId,
});
});
[
viewportIds.CT.CORONAL,
viewportIds.PT.CORONAL,
viewportIds.FUSION.CORONAL,
].forEach((viewportId) => {
coronalCameraPositionSynchronizer.add({
renderingEngineId,
viewportId,
});
});
// Add viewports to VOI synchronizers
[
viewportIds.CT.AXIAL,
viewportIds.CT.SAGITTAL,
viewportIds.CT.CORONAL,
].forEach((viewportId) => {
ctVoiSynchronizer.add({
renderingEngineId,
viewportId,
});
});
[
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
].forEach((viewportId) => {
// In this example, the fusion viewports are only targets for CT VOI
// synchronization, not sources
ctVoiSynchronizer.addTarget({
renderingEngineId,
viewportId,
});
});
[
viewportIds.PT.AXIAL,
viewportIds.PT.SAGITTAL,
viewportIds.PT.CORONAL,
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
viewportIds.PETMIP.CORONAL,
].forEach((viewportId) => {
ptVoiSynchronizer.add({
renderingEngineId,
viewportId,
});
});
}
async function getPtImageIds() {
return await createImageIdsAndCacheMetaData({
StudyInstanceUID,
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.879445243400782656317561081015',
wadoRsRoot,
});
}
async function getCtImageIds() {
return await createImageIdsAndCacheMetaData({
StudyInstanceUID,
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561',
wadoRsRoot,
});
}
async function setUpDisplay() {
// Create the viewports
const viewportInputArray = [
{
viewportId: viewportIds.CT.AXIAL,
type: ViewportType.ORTHOGRAPHIC,
element: element1_1,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
},
},
{
viewportId: viewportIds.CT.SAGITTAL,
type: ViewportType.ORTHOGRAPHIC,
element: element1_2,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
},
},
{
viewportId: viewportIds.CT.CORONAL,
type: ViewportType.ORTHOGRAPHIC,
element: element1_3,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
},
},
{
viewportId: viewportIds.PT.AXIAL,
type: ViewportType.ORTHOGRAPHIC,
element: element2_1,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
background: <Types.Point3>[1, 1, 1],
},
},
{
viewportId: viewportIds.PT.SAGITTAL,
type: ViewportType.ORTHOGRAPHIC,
element: element2_2,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
background: <Types.Point3>[1, 1, 1],
},
},
{
viewportId: viewportIds.PT.CORONAL,
type: ViewportType.ORTHOGRAPHIC,
element: element2_3,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
background: <Types.Point3>[1, 1, 1],
},
},
{
viewportId: viewportIds.FUSION.AXIAL,
type: ViewportType.ORTHOGRAPHIC,
element: element3_1,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
},
},
{
viewportId: viewportIds.FUSION.SAGITTAL,
type: ViewportType.ORTHOGRAPHIC,
element: element3_2,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
},
},
{
viewportId: viewportIds.FUSION.CORONAL,
type: ViewportType.ORTHOGRAPHIC,
element: element3_3,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
},
},
{
viewportId: viewportIds.PETMIP.CORONAL,
type: ViewportType.ORTHOGRAPHIC,
element: element_mip,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
background: <Types.Point3>[1, 1, 1],
},
},
];
renderingEngine.setViewports(viewportInputArray);
// Set the volumes to load
ptVolume.load();
ctVolume.load();
// Set volumes on the viewports
await setVolumesForViewports(
renderingEngine,
[
{
volumeId: ctVolumeId,
callback: setCtTransferFunctionForVolumeActor,
},
],
[viewportIds.CT.AXIAL, viewportIds.CT.SAGITTAL, viewportIds.CT.CORONAL]
);
await setVolumesForViewports(
renderingEngine,
[
{
volumeId: ptVolumeId,
callback: setPetTransferFunctionForVolumeActor,
},
],
[viewportIds.PT.AXIAL, viewportIds.PT.SAGITTAL, viewportIds.PT.CORONAL]
);
await setVolumesForViewports(
renderingEngine,
[
{
volumeId: ctVolumeId,
callback: setCtTransferFunctionForVolumeActor,
},
{
volumeId: ptVolumeId,
callback: setPetColorMapTransferFunctionForVolumeActor,
},
],
[
viewportIds.FUSION.AXIAL,
viewportIds.FUSION.SAGITTAL,
viewportIds.FUSION.CORONAL,
]
);
// Calculate size of fullBody pet mip
const ptVolumeDimensions = ptVolume.dimensions;
// Only make the MIP as large as it needs to be.
const slabThickness = Math.sqrt(
ptVolumeDimensions[0] * ptVolumeDimensions[0] +
ptVolumeDimensions[1] * ptVolumeDimensions[1] +
ptVolumeDimensions[2] * ptVolumeDimensions[2]
);
setVolumesForViewports(
renderingEngine,
[
{
volumeId: ptVolumeId,
callback: setPetTransferFunctionForVolumeActor,
blendMode: BlendModes.MAXIMUM_INTENSITY_BLEND,
slabThickness,
},
],
[viewportIds.PETMIP.CORONAL]
);
initializeCameraSync(renderingEngine);
// Render the viewports
renderingEngine.render();
}
addButtonToToolbar({
title: 'toggle volume3d',
onClick: async () => {
const viewportInput = {
viewportId: viewportIds.PETMIP.CORONAL,
type: ViewportType.VOLUME_3D,
element: element_mip,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
background: <Types.Point3>[1, 1, 1],
},
};
const volume3dToolGroup = mipToolGroup;
toggleVolume(viewportInput);
setupVolume3dSynchronizer(viewportInput);
setUpVolume3dToolGroup(volume3dToolGroup);
renderingEngine.render();
},
});
function toggleVolume(viewportInput) {
renderingEngine.enableElement(viewportInput);
const viewport = <Types.IVolumeViewport>(
renderingEngine.getViewport(viewportIds.PETMIP.CORONAL)
);
const ptVolumeDimensions = ptVolume.dimensions;
// Only make the MIP as large as it needs to be.
const slabThickness = Math.sqrt(
ptVolumeDimensions[0] * ptVolumeDimensions[0] +
ptVolumeDimensions[1] * ptVolumeDimensions[1] +
ptVolumeDimensions[2] * ptVolumeDimensions[2]
);
viewport.setVolumes([
{
volumeId: ptVolumeId,
callback: setPetTransferFunctionForVolumeActor,
slabThickness: slabThickness,
blendMode: BlendModes.MAXIMUM_INTENSITY_BLEND,
},
]);
}
function setupVolume3dSynchronizer(viewportInput) {
ptVoiSynchronizer.addTarget({
renderingEngineId,
viewportId: viewportInput.viewportId,
});
}
function setUpVolume3dToolGroup(toolGroup) {
toolGroup.addTool(PanTool.toolName);
toolGroup.addTool(TrackballRotateTool.toolName);
toolGroup.setToolActive(PanTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Secondary,
},
],
});
toolGroup.setToolActive(TrackballRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Auxiliary,
},
],
});
toolGroup.addViewport(viewportIds.PETMIP.CORONAL, renderingEngineId);
}
function initializeCameraSync(renderingEngine) {
// The fusion scene is the target as it is scaled to both volumes.
// TODO -> We should have a more generic way to do this,
// So that when all data is added we can synchronize zoom/position before interaction.
const axialCtViewport = renderingEngine.getViewport(viewportIds.CT.AXIAL);
const sagittalCtViewport = renderingEngine.getViewport(
viewportIds.CT.SAGITTAL
);
const coronalCtViewport = renderingEngine.getViewport(viewportIds.CT.CORONAL);
const axialPtViewport = renderingEngine.getViewport(viewportIds.PT.AXIAL);
const sagittalPtViewport = renderingEngine.getViewport(
viewportIds.PT.SAGITTAL
);
const coronalPtViewport = renderingEngine.getViewport(viewportIds.PT.CORONAL);
const axialFusionViewport = renderingEngine.getViewport(
viewportIds.FUSION.AXIAL
);
const sagittalFusionViewport = renderingEngine.getViewport(
viewportIds.FUSION.SAGITTAL
);
const coronalFusionViewport = renderingEngine.getViewport(
viewportIds.FUSION.CORONAL
);
initCameraSynchronization(axialFusionViewport, axialCtViewport);
initCameraSynchronization(axialFusionViewport, axialPtViewport);
initCameraSynchronization(sagittalFusionViewport, sagittalCtViewport);
initCameraSynchronization(sagittalFusionViewport, sagittalPtViewport);
initCameraSynchronization(coronalFusionViewport, coronalCtViewport);
initCameraSynchronization(coronalFusionViewport, coronalPtViewport);
renderingEngine.render();
}
function initCameraSynchronization(sViewport, tViewport) {
// Initialise the sync as they viewports will have
// Different initial zoom levels for viewports of different sizes.
const camera = sViewport.getCamera();
tViewport.setCamera(camera);
}
/**
* Runs the demo
*/
async function run() {
// Init Cornerstone and related libraries
await initDemo();
// Instantiate a rendering engine
renderingEngine = new RenderingEngine(renderingEngineId);
// Get Cornerstone imageIds and fetch metadata into RAM
ctImageIds = await getCtImageIds();
ptImageIds = await getPtImageIds();
// Define a volume in memory
ctVolume = await volumeLoader.createAndCacheVolume(ctVolumeId, {
imageIds: ctImageIds,
});
// Define a volume in memory
ptVolume = await volumeLoader.createAndCacheVolume(ptVolumeId, {
imageIds: ptImageIds,
});
// Display needs to be set up first so that we have viewport to reference for tools and synchronizers.
await setUpDisplay();
// Tools and synchronizers can be set up in any order.
setUpToolGroups();
setUpSynchronizers();
}
run();