Skip to content

Commit

Permalink
feat(shades): add light shades to volume rendering (#1068)
Browse files Browse the repository at this point in the history
* Refactor volumeViewport3D example and BaseVolumeViewport***

***Add preset modification event***

***Update applyPreset utility function

* api
  • Loading branch information
sedghi authored Feb 9, 2024
1 parent f0e0232 commit 65c6bd9
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 61 deletions.
2 changes: 2 additions & 0 deletions common/reviews/api/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,8 @@ export enum EVENTS {
// (undocumented)
PRE_STACK_NEW_IMAGE = "CORNERSTONE_PRE_STACK_NEW_IMAGE",
// (undocumented)
PRESET_MODIFIED = "CORNERSTONE_VIEWPORT_RENDERING_PRESET_MODIFIED",
// (undocumented)
STACK_NEW_IMAGE = "CORNERSTONE_STACK_NEW_IMAGE",
// (undocumented)
STACK_VIEWPORT_NEW_STACK = "CORNERSTONE_STACK_VIEWPORT_NEW_STACK",
Expand Down
57 changes: 13 additions & 44 deletions packages/core/examples/volumeViewport3D/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
RenderingEngine,
setVolumesForViewports,
Types,
utilities,
volumeLoader,
} from '@cornerstonejs/core';
import * as cornerstoneTools from '@cornerstonejs/tools';
import {
addButtonToToolbar,
addDropdownToToolbar,
addManipulationBindings,
createImageIdsAndCacheMetaData,
initDemo,
setTitleAndDescription,
Expand All @@ -22,11 +22,7 @@ console.warn(
'Click on index.ts to open source code for this example --------->'
);

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

const { ViewportType } = Enums;
const { MouseBindings } = csToolsEnums;
Expand Down Expand Up @@ -91,21 +87,15 @@ addDropdownToToolbar({
defaultValue: 'CT-Bone',
},
onSelectedValueChange: (presetName) => {
const volumeActor = renderingEngine
.getViewport(viewportId)
.getDefaultActor().actor as Types.VolumeActor;

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

renderingEngine.render();
viewport.setProperties({ preset: presetName });
viewport.render();
},
});

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

let viewport;

/**
* Runs the demo
*/
Expand All @@ -115,26 +105,13 @@ async function run() {

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
},
],
addManipulationBindings(toolGroup, {
is3DViewport: true,
});

// Get Cornerstone imageIds and fetch metadata into RAM
Expand All @@ -158,7 +135,7 @@ async function run() {
element: element1,
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
background: <Types.Point3>[0.2, 0, 0.2],
background: CONSTANTS.BACKGROUND_COLORS.slicer3D,
},
},
];
Expand All @@ -175,24 +152,16 @@ async function run() {

// Set the volume to load
volume.load();
viewport = renderingEngine.getViewport(viewportId);

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

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

viewport.setProperties({
preset: 'CT-Bone',
});
viewport.render();
}
);

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

run();
21 changes: 16 additions & 5 deletions packages/core/src/RenderingEngine/BaseVolumeViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
*
* @returns void
*/
private setPreset(presetName, volumeId, suppressEvents) {
private setPreset(presetNameOrObj, volumeId, suppressEvents) {
const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);

if (!applicableVolumeActorInfo) {
Expand All @@ -672,17 +672,28 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {

const { volumeActor } = applicableVolumeActorInfo;

const preset = VIEWPORT_PRESETS.find((preset) => {
return preset.name === presetName;
});
let preset = presetNameOrObj;

if (typeof preset === 'string') {
preset = VIEWPORT_PRESETS.find((preset) => {
return preset.name === presetNameOrObj;
});
}

if (!preset) {
return;
}

applyPreset(volumeActor, preset);

this.viewportProperties.preset = presetName;
if (!suppressEvents) {
triggerEvent(this.element, Events.PRESET_MODIFIED, {
viewportId: this.id,
volumeId: applicableVolumeActorInfo.volumeId,
actor: volumeActor,
presetName: preset.name,
});
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/enums/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ enum Events {
* and see what event detail is included in {@link EventTypes.VoiModifiedEventDetail | VoiModified Event Detail }
*/
VOI_MODIFIED = 'CORNERSTONE_VOI_MODIFIED',
/**
* Triggers on the HTML element when viewport modifies its preset (used in volume viewport 3D)
*
* Make use of {@link EventTypes.PresetModifiedEvent | PresetModified Event Type } for typing your event listeners for PRESET_MODIFIED event,
*/
PRESET_MODIFIED = 'CORNERSTONE_VIEWPORT_RENDERING_PRESET_MODIFIED',
/**
* Triggers on the HTML element when viewport modifies its display area
*
Expand Down
27 changes: 15 additions & 12 deletions packages/core/src/utilities/applyPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,35 +57,38 @@ export default function applyPreset(

applyPointsToPiecewiseFunction(normPoints, shiftRange, ofun);

actor.getProperty().setScalarOpacity(0, ofun);
const property = actor.getProperty();

property.setScalarOpacity(0, ofun);
const [
gradientMinValue,
gradientMinOpacity,
gradientMaxValue,
gradientMaxOpacity,
] = preset.gradientOpacity.split(' ').splice(1).map(parseFloat);

actor.getProperty().setUseGradientOpacity(0, true);
actor.getProperty().setGradientOpacityMinimumValue(0, gradientMinValue);
actor.getProperty().setGradientOpacityMinimumOpacity(0, gradientMinOpacity);
actor.getProperty().setGradientOpacityMaximumValue(0, gradientMaxValue);
actor.getProperty().setGradientOpacityMaximumOpacity(0, gradientMaxOpacity);
property.setUseGradientOpacity(0, true);
property.setGradientOpacityMinimumValue(0, gradientMinValue);
property.setGradientOpacityMinimumOpacity(0, gradientMinOpacity);
property.setGradientOpacityMaximumValue(0, gradientMaxValue);
property.setGradientOpacityMaximumOpacity(0, gradientMaxOpacity);

if (preset.interpolation === '1') {
actor.getProperty().setInterpolationTypeToFastLinear();
//actor.getProperty().setInterpolationTypeToLinear()
property.setInterpolationTypeToFastLinear();
//property.setInterpolationTypeToLinear()
}

property.setShade(preset.shade === '1');

const ambient = parseFloat(preset.ambient);
const diffuse = parseFloat(preset.diffuse);
const specular = parseFloat(preset.specular);
const specularPower = parseFloat(preset.specularPower);

actor.getProperty().setAmbient(ambient);
actor.getProperty().setDiffuse(diffuse);
actor.getProperty().setSpecular(specular);
actor.getProperty().setSpecularPower(specularPower);
property.setAmbient(ambient);
property.setDiffuse(diffuse);
property.setSpecular(specular);
property.setSpecularPower(specularPower);
}

function getShiftRange(colorTransferArray) {
Expand Down

0 comments on commit 65c6bd9

Please sign in to comment.