diff --git a/common/reviews/api/core.api.md b/common/reviews/api/core.api.md index 9eab43f35..6cb87b3aa 100644 --- a/common/reviews/api/core.api.md +++ b/common/reviews/api/core.api.md @@ -54,6 +54,8 @@ export abstract class BaseVolumeViewport extends Viewport implements IVolumeView // (undocumented) addVolumes(volumeInputArray: Array, immediate?: boolean, suppressEvents?: boolean): Promise; // (undocumented) + protected applyViewOrientation(orientation: OrientationAxis | OrientationVectors): void; + // (undocumented) canvasToWorld: (canvasPos: Point2) => Point3; // (undocumented) flip(flipDirection: FlipDirection): void; @@ -70,6 +72,8 @@ export abstract class BaseVolumeViewport extends Viewport implements IVolumeView // (undocumented) getIntensityFromWorld(point: Point3): number; // (undocumented) + protected _getOrientationVectors(orientation: OrientationAxis | OrientationVectors): OrientationVectors; + // (undocumented) getProperties: () => VolumeViewportProperties; // (undocumented) getSlabThickness(): number; diff --git a/packages/core/examples/volumeViewport3D/index.ts b/packages/core/examples/volumeViewport3D/index.ts index a1e3b2b79..ccafad13f 100644 --- a/packages/core/examples/volumeViewport3D/index.ts +++ b/packages/core/examples/volumeViewport3D/index.ts @@ -1,19 +1,19 @@ import { - RenderingEngine, - Types, + CONSTANTS, Enums, + RenderingEngine, setVolumesForViewports, - volumeLoader, + Types, utilities, - CONSTANTS, + volumeLoader, } from '@cornerstonejs/core'; +import * as cornerstoneTools from '@cornerstonejs/tools'; import { - initDemo, + addDropdownToToolbar, createImageIdsAndCacheMetaData, + initDemo, setTitleAndDescription, - addDropdownToToolbar, } from '../../../../utils/demo/helpers'; -import * as cornerstoneTools from '@cornerstonejs/tools'; // This is for debugging purposes console.warn( @@ -138,7 +138,7 @@ async function run() { type: ViewportType.VOLUME_3D, element: element1, defaultOptions: { - orientation: Enums.OrientationAxis.SAGITTAL, + orientation: Enums.OrientationAxis.CORONAL, background: [0.2, 0, 0.2], }, }, @@ -168,10 +168,6 @@ async function run() { CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === 'CT-Bone') ); - const renderer = viewport.getRenderer(); - renderer.getActiveCamera().elevation(-70); - viewport.setCamera({ parallelScale: 600 }); - viewport.render(); } ); diff --git a/packages/core/src/RenderingEngine/BaseVolumeViewport.ts b/packages/core/src/RenderingEngine/BaseVolumeViewport.ts index 3582d35bb..e51d0e5ed 100644 --- a/packages/core/src/RenderingEngine/BaseVolumeViewport.ts +++ b/packages/core/src/RenderingEngine/BaseVolumeViewport.ts @@ -1,44 +1,45 @@ import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume'; import cache from '../cache'; +import { MPR_CAMERA_VALUES, RENDERING_DEFAULTS } from '../constants'; +import { + BlendModes, + Events, + OrientationAxis, + VOILUTFunctionType, +} from '../enums'; import ViewportType from '../enums/ViewportType'; -import Viewport from './Viewport'; -import { createVolumeActor } from './helpers'; -import volumeNewImageEventDispatcher, { - resetVolumeNewImageState, -} from './helpers/volumeNewImageEventDispatcher'; -import { loadVolume } from '../loaders/volumeLoader'; -import vtkSlabCamera from './vtkClasses/vtkSlabCamera'; +import eventTarget from '../eventTarget'; import { getShouldUseCPURendering } from '../init'; +import { loadVolume } from '../loaders/volumeLoader'; import type { - Point2, - Point3, - IImageData, - IVolumeInput, ActorEntry, FlipDirection, - VolumeViewportProperties, + IImageData, + IVolumeInput, + OrientationVectors, + Point2, + Point3, VOIRange, + VolumeViewportProperties, } from '../types'; +import { VoiModifiedEventDetail } from '../types/EventTypes'; import type { ViewportInput } from '../types/IViewport'; import type IVolumeViewport from '../types/IVolumeViewport'; -import { - Events, - BlendModes, - OrientationAxis, - VOILUTFunctionType, -} from '../enums'; -import eventTarget from '../eventTarget'; import { actorIsA, - imageIdToURI, - triggerEvent, createSigmoidRGBTransferFunction, getVoiFromSigmoidRGBTransferFunction, + imageIdToURI, + triggerEvent, } from '../utilities'; +import { createVolumeActor } from './helpers'; +import volumeNewImageEventDispatcher, { + resetVolumeNewImageState, +} from './helpers/volumeNewImageEventDispatcher'; +import Viewport from './Viewport'; import type { vtkSlabCamera as vtkSlabCameraType } from './vtkClasses/vtkSlabCamera'; -import { VoiModifiedEventDetail } from '../types/EventTypes'; -import { RENDERING_DEFAULTS } from '../constants'; +import vtkSlabCamera from './vtkClasses/vtkSlabCamera'; /** * Abstract base class for volume viewports. VolumeViewports are used to render @@ -94,6 +95,22 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport { return false; } + protected applyViewOrientation( + orientation: OrientationAxis | OrientationVectors + ) { + const { viewPlaneNormal, viewUp } = + this._getOrientationVectors(orientation); + const camera = this.getVtkActiveCamera(); + camera.setDirectionOfProjection( + -viewPlaneNormal[0], + -viewPlaneNormal[1], + -viewPlaneNormal[2] + ); + camera.setViewUpFrom(viewUp); + + this.resetCamera(); + } + private initializeVolumeNewImageEventDispatcher(): void { const volumeNewImageHandlerBound = volumeNewImageHandler.bind(this); const volumeNewImageCleanUpBound = volumeNewImageCleanUp.bind(this); @@ -758,6 +775,31 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport { }); }; + protected _getOrientationVectors( + orientation: OrientationAxis | OrientationVectors + ): OrientationVectors { + if (typeof orientation === 'object') { + if (orientation.viewPlaneNormal && orientation.viewUp) { + return orientation; + } else { + throw new Error( + 'Invalid orientation object. It must contain viewPlaneNormal and viewUp' + ); + } + } else if ( + typeof orientation === 'string' && + MPR_CAMERA_VALUES[orientation] + ) { + return MPR_CAMERA_VALUES[orientation]; + } else { + throw new Error( + `Invalid orientation: ${orientation}. Valid orientations are: ${Object.keys( + MPR_CAMERA_VALUES + ).join(', ')}` + ); + } + } + /** * Reset the camera for the volume viewport */ diff --git a/packages/core/src/RenderingEngine/VolumeViewport.ts b/packages/core/src/RenderingEngine/VolumeViewport.ts index 601fd49fc..8b24561b4 100644 --- a/packages/core/src/RenderingEngine/VolumeViewport.ts +++ b/packages/core/src/RenderingEngine/VolumeViewport.ts @@ -1,20 +1,20 @@ -import { vec3 } from 'gl-matrix'; import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane'; +import { vec3 } from 'gl-matrix'; import cache from '../cache'; -import transformWorldToIndex from '../utilities/transformWorldToIndex'; +import { EPSILON, MPR_CAMERA_VALUES, RENDERING_DEFAULTS } from '../constants'; +import { BlendModes, OrientationAxis } from '../enums'; import type { - Point3, - IVolumeInput, ActorEntry, IImageVolume, + IVolumeInput, OrientationVectors, + Point3, } from '../types'; import type { ViewportInput } from '../types/IViewport'; -import { RENDERING_DEFAULTS, MPR_CAMERA_VALUES, EPSILON } from '../constants'; -import { BlendModes, OrientationAxis } from '../enums'; -import BaseVolumeViewport from './BaseVolumeViewport'; import { actorIsA } from '../utilities'; +import transformWorldToIndex from '../utilities/transformWorldToIndex'; +import BaseVolumeViewport from './BaseVolumeViewport'; /** * An object representing a VolumeViewport. VolumeViewports are used to render @@ -35,17 +35,7 @@ class VolumeViewport extends BaseVolumeViewport { // if the camera is set to be acquisition axis then we need to skip // it for now until the volume is set if (orientation && orientation !== OrientationAxis.ACQUISITION) { - const { viewPlaneNormal, viewUp } = - this._getOrientationVectors(orientation); - const camera = this.getVtkActiveCamera(); - camera.setDirectionOfProjection( - -viewPlaneNormal[0], - -viewPlaneNormal[1], - -viewPlaneNormal[2] - ); - camera.setViewUpFrom(viewUp); - - this.resetCamera(); + this.applyViewOrientation(orientation); return; } @@ -144,31 +134,6 @@ class VolumeViewport extends BaseVolumeViewport { } } - private _getOrientationVectors( - orientation: OrientationAxis | OrientationVectors - ): OrientationVectors { - if (typeof orientation === 'object') { - if (orientation.viewPlaneNormal && orientation.viewUp) { - return orientation; - } else { - throw new Error( - 'Invalid orientation object. It must contain viewPlaneNormal and viewUp' - ); - } - } else if ( - typeof orientation === 'string' && - MPR_CAMERA_VALUES[orientation] - ) { - return MPR_CAMERA_VALUES[orientation]; - } else { - throw new Error( - `Invalid orientation: ${orientation}. Valid orientations are: ${Object.keys( - MPR_CAMERA_VALUES - ).join(', ')}` - ); - } - } - private _getAcquisitionPlaneOrientation(): OrientationVectors { const actorEntry = this.getDefaultActor(); diff --git a/packages/core/src/RenderingEngine/VolumeViewport3D.ts b/packages/core/src/RenderingEngine/VolumeViewport3D.ts index e3ef3b4bc..98a970151 100644 --- a/packages/core/src/RenderingEngine/VolumeViewport3D.ts +++ b/packages/core/src/RenderingEngine/VolumeViewport3D.ts @@ -1,6 +1,6 @@ +import { OrientationAxis } from '../enums'; import type { ViewportInput } from '../types/IViewport'; import BaseVolumeViewport from './BaseVolumeViewport'; -import { RENDERING_DEFAULTS } from '../constants'; /** * An object representing a 3-dimensional volume viewport. VolumeViewport3Ds are used to render @@ -13,13 +13,17 @@ class VolumeViewport3D extends BaseVolumeViewport { constructor(props: ViewportInput) { super(props); - const { parallelProjection } = this.options; + const { parallelProjection, orientation } = this.options; const activeCamera = this.getVtkActiveCamera(); if (parallelProjection != null) { activeCamera.setParallelProjection(parallelProjection); } + + if (orientation && orientation !== OrientationAxis.ACQUISITION) { + this.applyViewOrientation(orientation); + } } public resetCamera( diff --git a/packages/core/test/groundTruth/sphere_default_sagittal.png b/packages/core/test/groundTruth/sphere_default_sagittal.png index dfe72115d..912099c9a 100644 Binary files a/packages/core/test/groundTruth/sphere_default_sagittal.png and b/packages/core/test/groundTruth/sphere_default_sagittal.png differ diff --git a/packages/core/test/volumeViewport_gpu_render_test.js b/packages/core/test/volumeViewport_gpu_render_test.js index 72fc4bde6..232fdbebc 100644 --- a/packages/core/test/volumeViewport_gpu_render_test.js +++ b/packages/core/test/volumeViewport_gpu_render_test.js @@ -92,8 +92,8 @@ describe('Volume Viewport GPU -- ', () => { const element = createViewport( this.renderingEngine, Enums.OrientationAxis.SAGITTAL, - 1000, - 1000, + 300, + 300, ViewportType.VOLUME_3D ); this.DOMElements.push(element);