From 67f614b4272a6a45e42e0b54f16693337148c361 Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 31 May 2024 15:56:55 -0400 Subject: [PATCH] fix(imageIndex vs sliceIndex): imageIndex should be ijk based and slice index view based (#1299) --- common/reviews/api/core.api.md | 10 ++- .../src/RenderingEngine/BaseVolumeViewport.ts | 6 +- .../core/src/RenderingEngine/StackViewport.ts | 8 +++ .../core/src/RenderingEngine/VideoViewport.ts | 6 +- packages/core/src/RenderingEngine/Viewport.ts | 6 +- .../src/RenderingEngine/VolumeViewport.ts | 66 ++++++++++++------- packages/core/src/types/IViewport.ts | 4 +- .../interpolationContourSegmentation/index.ts | 2 +- 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/common/reviews/api/core.api.md b/common/reviews/api/core.api.md index 3c13d85709..f613494da3 100644 --- a/common/reviews/api/core.api.md +++ b/common/reviews/api/core.api.md @@ -2224,6 +2224,8 @@ interface IViewport { // (undocumented) getRotation: () => number; // (undocumented) + getSliceIndex(): number; + // (undocumented) getViewPresentation(viewPresSel?: ViewPresentationSelector): ViewPresentation; // (undocumented) getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference; @@ -3131,6 +3133,8 @@ export class StackViewport extends Viewport implements StackViewport, IImagesLoa // (undocumented) getRotation: () => number; // (undocumented) + getSliceIndex: () => number; + // (undocumented) getTargetImageIdIndex: () => number; // (undocumented) getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference; @@ -3623,6 +3627,8 @@ export class VideoViewport extends Viewport implements IVideoViewport { // (undocumented) protected getScalarData(): CanvasScalarData; // (undocumented) + getSliceIndex(): number; + // (undocumented) protected getTransform(): Transform; // (undocumented) getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference; @@ -3798,6 +3804,8 @@ export class Viewport implements IViewport { // (undocumented) getRotation: () => number; // (undocumented) + getSliceIndex(): number; + // (undocumented) getViewPresentation(viewPresSel?: ViewPresentationSelector): ViewPresentation; // (undocumented) getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference; @@ -4178,7 +4186,7 @@ export class VolumeViewport extends BaseVolumeViewport { // (undocumented) getCurrentImageId: () => string | undefined; // (undocumented) - getCurrentImageIdIndex: (volumeId?: string, useSlabThickness?: boolean) => number; + getCurrentImageIdIndex: (volumeId?: string) => number; // (undocumented) getNumberOfSlices: () => number; // (undocumented) diff --git a/packages/core/src/RenderingEngine/BaseVolumeViewport.ts b/packages/core/src/RenderingEngine/BaseVolumeViewport.ts index 8f5ed129e8..b575f81cf2 100644 --- a/packages/core/src/RenderingEngine/BaseVolumeViewport.ts +++ b/packages/core/src/RenderingEngine/BaseVolumeViewport.ts @@ -614,7 +614,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport { } const { viewPlaneNormal } = target; const delta = - (viewRefSpecifier.sliceIndex as number) - this.getCurrentImageIdIndex(); + (viewRefSpecifier.sliceIndex as number) - this.getSliceIndex(); // Calculate a camera focal point and position const { sliceRangeInfo } = getVolumeViewportScrollInfo( this, @@ -657,7 +657,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport { if (options?.withNavigation) { return true; } - const currentSliceIndex = this.getCurrentImageIdIndex(); + const currentSliceIndex = this.getSliceIndex(); const { sliceIndex } = viewRef; if (Array.isArray(sliceIndex)) { return ( @@ -1757,7 +1757,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport { )?.uid; } - const currentIndex = this.getCurrentImageIdIndex(); + const currentIndex = this.getSliceIndex(); sliceIndex ??= currentIndex; const { viewPlaneNormal, focalPoint } = this.getCamera(); const querySeparator = volumeId.indexOf('?') > -1 ? '&' : '?'; diff --git a/packages/core/src/RenderingEngine/StackViewport.ts b/packages/core/src/RenderingEngine/StackViewport.ts index c1ec2ee87e..74de5c1481 100644 --- a/packages/core/src/RenderingEngine/StackViewport.ts +++ b/packages/core/src/RenderingEngine/StackViewport.ts @@ -2880,6 +2880,14 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader { return this.currentImageIdIndex; }; + /** + * returns the slice index of the view + * @returns slice index + */ + public getSliceIndex = (): number => { + return this.currentImageIdIndex; + }; + /** * Checks to see if this target is or could be shown in this viewport */ diff --git a/packages/core/src/RenderingEngine/VideoViewport.ts b/packages/core/src/RenderingEngine/VideoViewport.ts index cea08d5bc5..83204543fa 100644 --- a/packages/core/src/RenderingEngine/VideoViewport.ts +++ b/packages/core/src/RenderingEngine/VideoViewport.ts @@ -735,7 +735,7 @@ class VideoViewport extends Viewport implements IVideoViewport { if (options.withNavigation) { return true; } - const currentIndex = this.getCurrentImageIdIndex(); + const currentIndex = this.getSliceIndex(); if (Array.isArray(sliceIndex)) { return currentIndex >= sliceIndex[0] && currentIndex <= sliceIndex[1]; } @@ -786,6 +786,10 @@ class VideoViewport extends Viewport implements IVideoViewport { return Math.round(this.videoElement.currentTime * this.fps); } + public getSliceIndex() { + return this.getCurrentImageIdIndex(); + } + public getCamera(): ICamera { const { parallelScale } = this.videoCamera; diff --git a/packages/core/src/RenderingEngine/Viewport.ts b/packages/core/src/RenderingEngine/Viewport.ts index b96b6ba4d7..2a9ee4f8de 100644 --- a/packages/core/src/RenderingEngine/Viewport.ts +++ b/packages/core/src/RenderingEngine/Viewport.ts @@ -1097,6 +1097,10 @@ class Viewport implements IViewport { throw new Error('Not implemented'); } + public getSliceIndex(): number { + throw new Error('Not implemented'); + } + /** * Gets a referenced image url of some sort - could be a real image id, or * could be a URL with parameters. Regardless it refers to the currently displaying @@ -1611,7 +1615,7 @@ class Viewport implements IViewport { cameraFocalPoint, viewPlaneNormal, viewUp, - sliceIndex: viewRefSpecifier.sliceIndex ?? this.getCurrentImageIdIndex(), + sliceIndex: viewRefSpecifier.sliceIndex ?? this.getSliceIndex(), }; return target; } diff --git a/packages/core/src/RenderingEngine/VolumeViewport.ts b/packages/core/src/RenderingEngine/VolumeViewport.ts index f3775a521f..db54882b28 100644 --- a/packages/core/src/RenderingEngine/VolumeViewport.ts +++ b/packages/core/src/RenderingEngine/VolumeViewport.ts @@ -29,7 +29,7 @@ import setDefaultVolumeVOI from './helpers/setDefaultVolumeVOI'; import { setTransferFunctionNodes } from '../utilities/transferFunctionUtils'; import { ImageActor } from '../types/IActor'; import getImageSliceDataForVolumeViewport from '../utilities/getImageSliceDataForVolumeViewport'; -import getVolumeViewportScrollInfo from '../utilities/getVolumeViewportScrollInfo'; +import { vec3 } from 'gl-matrix'; /** * An object representing a VolumeViewport. VolumeViewports are used to render @@ -92,15 +92,6 @@ class VolumeViewport extends BaseVolumeViewport { return numberOfSlices; }; - /** - * Returns the image index associated with the volume viewport. - * @returns The image index. - */ - public getSliceIndex = (): number => { - const { imageIndex } = getImageSliceDataForVolumeViewport(this); - return imageIndex; - }; - /** * Creates and adds volume actors for all volumes defined in the `volumeInputArray`. * For each entry, if a `callback` is supplied, it will be called with the new volume actor as input. @@ -387,23 +378,52 @@ class VolumeViewport extends BaseVolumeViewport { } /** - * Uses the slice range information to compute the current image id index. - * Note that this may be offset from the origin location, or opposite in - * direction to the distance from the origin location, as the index is a - * complete index from minimum to maximum. + * Returns the imageId index of the current slice in the volume viewport. + * Note: this is not guaranteed to be the same as the slice index in the view + * To get the slice index in the view (scroll position), use getSliceIndex() + * + * In future we will even delete this method as it should not be used + * at all. * * @returns The slice index in the direction of the view */ - public getCurrentImageIdIndex = ( - volumeId?: string, - useSlabThickness = true - ): number => { - const { currentStepIndex } = getVolumeViewportScrollInfo( - this, - volumeId || this.getVolumeId(), - useSlabThickness + public getCurrentImageIdIndex = (volumeId?: string): number => { + const { viewPlaneNormal, focalPoint } = this.getCamera(); + + const imageData = this.getImageData(volumeId); + + if (!imageData) { + return; + } + + const { origin, direction, spacing } = imageData; + + const spacingInNormal = getSpacingInNormalDirection( + { direction, spacing }, + viewPlaneNormal ); - return currentStepIndex; + const sub = vec3.create(); + vec3.sub(sub, focalPoint, origin); + const distance = vec3.dot(sub, viewPlaneNormal); + + // divide by the spacing in the normal direction to get the + // number of steps, and subtract 1 to get the index + return Math.round(Math.abs(distance) / spacingInNormal); + }; + + /** + * Returns the image index associated with the volume viewport in the current view, the difference + * between this method and getCurrentImageIdIndex is that this method returns the index of the + * slice in the volume in view direction so at the top (scrollbar top) of the viewport the index + * will be 0 and at the bottom (scrollbar bottom) the index will be the number of slices - 1. + * But the getCurrentImageIdIndex returns the index of current image in the imageIds + * which is not guaranteed to be the same as the slice index in the view. + * + * @returns The image index. + */ + public getSliceIndex = (): number => { + const { imageIndex } = getImageSliceDataForVolumeViewport(this); + return imageIndex; }; /** diff --git a/packages/core/src/types/IViewport.ts b/packages/core/src/types/IViewport.ts index 34b194bc56..893f4fe3a4 100644 --- a/packages/core/src/types/IViewport.ts +++ b/packages/core/src/types/IViewport.ts @@ -333,8 +333,10 @@ interface IViewport { ): boolean; /** Gets the number of slices in the current camera orientation */ getNumberOfSlices(): number; - /** Gets the current slice in the current camera orientation */ + /** Gets the index of the current image, it is not guaranteed to be the slice index in the view, use getSliceIndex for positional information */ getCurrentImageIdIndex(): number; + /** gets the positional slice location in the view, similar to scrollbar, the top image is 0, the bottom is getNumberOfSlices - 1 */ + getSliceIndex(): number; /** * Gets a referenced image url of some sort - could be a real image id, or * could be a URL with parameters. Regardless it refers to the currently displaying diff --git a/packages/tools/examples/interpolationContourSegmentation/index.ts b/packages/tools/examples/interpolationContourSegmentation/index.ts index a694683211..5e0c64e838 100644 --- a/packages/tools/examples/interpolationContourSegmentation/index.ts +++ b/packages/tools/examples/interpolationContourSegmentation/index.ts @@ -201,7 +201,7 @@ function acceptCurrent() { segmentIndex: segmentation.segmentIndex.getActiveSegmentIndex(segmentationId), segmentationId: segmentationIdStack, - sliceIndex: viewport.getCurrentImageIdIndex(), + sliceIndex: viewport.getSliceIndex(), } ); }