Skip to content

Commit

Permalink
feat: Add new 3D volume viewport (#281)
Browse files Browse the repository at this point in the history
* Extract common volume viewport functionality to base class

* Add viewport presets

* Add utility function for applying preset to volume actor

* Add new 3D volume viewport

* Add example for VolumeViewport3D

* feat: add presets dropdown to demo

* update example info json

Co-authored-by: Luccas Correa <luccascorrea@estudio89.com.br>
Co-authored-by: Alireza <ar.sedghi@gmail.com>
  • Loading branch information
3 people committed Dec 9, 2022
1 parent 4186c94 commit 57cf7ac
Show file tree
Hide file tree
Showing 24 changed files with 3,882 additions and 2,891 deletions.
4,658 changes: 2,359 additions & 2,299 deletions common/reviews/api/core.api.md

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions common/reviews/api/streaming-image-volume-loader.api.md
Expand Up @@ -1250,11 +1250,37 @@ type ViewportInputOptions = {
suppressEvents?: boolean;
};

// @public (undocumented)
interface ViewportPreset {
// (undocumented)
ambient: string;
// (undocumented)
colorTransfer: string;
// (undocumented)
diffuse: string;
// (undocumented)
gradientOpacity: string;
// (undocumented)
interpolation: string;
// (undocumented)
name: string;
// (undocumented)
scalarOpacity: string;
// (undocumented)
shade: string;
// (undocumented)
specular: string;
// (undocumented)
specularPower: string;
}

// @public
enum ViewportType {
ORTHOGRAPHIC = 'orthographic',
PERSPECTIVE = 'perspective',
STACK = 'stack',
// (undocumented)
VOLUME_3D = 'volume3d',
}

// @public (undocumented)
Expand Down
24 changes: 24 additions & 0 deletions common/reviews/api/tools.api.md
Expand Up @@ -4671,6 +4671,30 @@ type ViewportInputOptions = {
suppressEvents?: boolean;
};

// @public (undocumented)
interface ViewportPreset {
// (undocumented)
ambient: string;
// (undocumented)
colorTransfer: string;
// (undocumented)
diffuse: string;
// (undocumented)
gradientOpacity: string;
// (undocumented)
interpolation: string;
// (undocumented)
name: string;
// (undocumented)
scalarOpacity: string;
// (undocumented)
shade: string;
// (undocumented)
specular: string;
// (undocumented)
specularPower: string;
}

declare namespace visibility {
export {
setAnnotationVisibility,
Expand Down
185 changes: 185 additions & 0 deletions packages/core/examples/volumeViewport3D/index.ts
@@ -0,0 +1,185 @@
import {
RenderingEngine,
Types,
Enums,
setVolumesForViewports,
volumeLoader,
utilities,
CONSTANTS,
} from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setTitleAndDescription,
addDropdownToToolbar,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';
import { VolumeActor } from 'core/src/types';

// This is for debugging purposes
console.warn(
'Click on index.ts to open source code for this example --------->'
);

const {
ToolGroupManager,
TrackballRotateTool,
Enums: csToolsEnums,
} = cornerstoneTools;

const { ViewportType } = Enums;
const { MouseBindings } = csToolsEnums;

// Define a unique id for the volume
let renderingEngine;
const volumeName = 'CT_VOLUME_ID'; // Id of the volume less loader prefix
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
const volumeId = `${volumeLoaderScheme}:${volumeName}`; // VolumeId with loader id + volume id
const renderingEngineId = 'myRenderingEngine';
const viewportId = '3D_VIEWPORT';

// ======== Set up page ======== //
setTitleAndDescription(
'3D Volume Rendering',
'Here we demonstrate how to 3D render a volume.'
);

const size = '500px';
const content = document.getElementById('content');
const viewportGrid = document.createElement('div');

viewportGrid.style.display = 'flex';
viewportGrid.style.display = 'flex';
viewportGrid.style.flexDirection = 'row';

const element1 = document.createElement('div');
element1.oncontextmenu = () => false;

element1.style.width = size;
element1.style.height = size;

viewportGrid.appendChild(element1);

content.appendChild(viewportGrid);

const instructions = document.createElement('p');
instructions.innerText = 'Click the image to rotate it.';

content.append(instructions);

addDropdownToToolbar({
options: {
values: CONSTANTS.VIEWPORT_PRESETS.map((preset) => preset.name),
defaultValue: 'CT-Bone',
},
onSelectedValueChange: (presetName) => {
const volumeActor = renderingEngine
.getViewport(viewportId)
.getDefaultActor().actor as VolumeActor;

utilities.applyPreset(
volumeActor,
CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === presetName)
);

renderingEngine.render();
},
});

// ============================= //

/**
* Runs the demo
*/
async function run() {
// Init Cornerstone and related libraries
await initDemo();

const toolGroupId = 'TOOL_GROUP_ID';

// Add tools to Cornerstone3D
cornerstoneTools.addTool(TrackballRotateTool);

// Define a tool group, which defines how mouse events map to tool commands for
// Any viewport using the group
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);

// Add the tools to the tool group and specify which volume they are pointing at
toolGroup.addTool(TrackballRotateTool.toolName, {
configuration: { volumeId },
});

// Set the initial state of the tools, here we set one tool active on left click.
// This means left click will draw that tool.
toolGroup.setToolActive(TrackballRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});

// Get Cornerstone imageIds and fetch metadata into RAM
const imageIds = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.367700692008930469189923116409',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
type: 'VOLUME',
});

// Instantiate a rendering engine
renderingEngine = new RenderingEngine(renderingEngineId);

// Create the viewports

const viewportInputArray = [
{
viewportId: viewportId,
type: ViewportType.VOLUME_3D,
element: element1,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
background: <Types.Point3>[0.2, 0, 0.2],
},
},
];

renderingEngine.setViewports(viewportInputArray);

// Set the tool group on the viewports
toolGroup.addViewport(viewportId, renderingEngineId);

// Define a volume in memory
const volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds,
});

// Set the volume to load
volume.load();

setVolumesForViewports(renderingEngine, [{ volumeId }], [viewportId]).then(
() => {
const volumeActor = renderingEngine
.getViewport(viewportId)
.getDefaultActor().actor as VolumeActor;

utilities.applyPreset(
volumeActor,
CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === 'CT-Bone')
);

const renderer = viewport.getRenderer();
renderer.getActiveCamera().elevation(-70);
viewport.setCamera({ parallelScale: 600 });

viewport.render();
}
);

const viewport = renderingEngine.getViewport(viewportId);
renderingEngine.render();
}

run();

0 comments on commit 57cf7ac

Please sign in to comment.