Skip to content

Commit

Permalink
fix(scroll): Scrolling failed to find the volume with segmentation (c…
Browse files Browse the repository at this point in the history
…ornerstonejs#470)

* fix: Scrolling failed to find the volume on 2cd segmentation

* fix: Make scrolling work on segmentations that are slightly different
spacing

* Update API

* PR fixes

* Change the name of uid to actorUID to be more specific
  • Loading branch information
wayfarer3130 authored Mar 10, 2023
1 parent 83287d2 commit 79b8c96
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 14 deletions.
1 change: 1 addition & 0 deletions common/reviews/api/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ function getSpacingInNormalDirection(imageVolume: IImageVolume, viewPlaneNormal:
function getTargetVolumeAndSpacingInNormalDir(viewport: IVolumeViewport, camera: ICamera, targetVolumeId?: string): {
imageVolume: IImageVolume;
spacingInNormalDirection: number;
actorUID: string;
};

// @public (undocumented)
Expand Down
1 change: 1 addition & 0 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2943,6 +2943,7 @@ function jumpToSlice(element: HTMLDivElement, options?: JumpToSliceOptions): Pro
type JumpToSliceOptions = {
imageIndex: number;
debounceLoading?: boolean;
volumeId?: string;
};

// @public (undocumented)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import cache from '../cache/cache';
import { EPSILON } from '../constants';
// import type { VolumeViewport } from '../RenderingEngine'
import { ICamera, IImageVolume, IVolumeViewport } from '../types';
import getSpacingInNormalDirection from './getSpacingInNormalDirection';

// One EPSILON part larger multiplier
const EPSILON_PART = 1 + EPSILON;

/**
* Given a volume viewport and camera, find the target volume.
* The imageVolume is retrieved from cache for the specified targetVolumeId or
Expand All @@ -25,45 +29,57 @@ export default function getTargetVolumeAndSpacingInNormalDir(
): {
imageVolume: IImageVolume;
spacingInNormalDirection: number;
actorUID: string;
} {
const { viewPlaneNormal } = camera;
const volumeActors = viewport.getActors();

if (!volumeActors || !volumeActors.length) {
return { spacingInNormalDirection: null, imageVolume: null };
return {
spacingInNormalDirection: null,
imageVolume: null,
actorUID: null,
};
}

const imageVolumes = volumeActors
.map((va) => {
// prefer the referenceUID if it is set, since it can be a derived actor
// and the uid does not necessarily match the volumeId
const uid = va.referenceId ?? va.uid;
return cache.getVolume(uid);
const actorUID = va.referenceId ?? va.uid;
return cache.getVolume(actorUID);
})
.filter((iv) => !!iv);

// If a volumeId is defined, set that volume as the target
if (targetVolumeId) {
const imageVolume = imageVolumes.find(
const imageVolumeIndex = imageVolumes.findIndex(
(iv) => iv.volumeId === targetVolumeId
);

const imageVolume = imageVolumes[imageVolumeIndex];
const { uid: actorUID } = volumeActors[imageVolumeIndex];
const spacingInNormalDirection = getSpacingInNormalDirection(
imageVolume,
viewPlaneNormal
);

return { imageVolume, spacingInNormalDirection };
return { imageVolume, spacingInNormalDirection, actorUID };
}

if (!imageVolumes.length) {
return { spacingInNormalDirection: null, imageVolume: null };
return {
spacingInNormalDirection: null,
imageVolume: null,
actorUID: null,
};
}

// Fetch volume actor with finest resolution in direction of projection.
const smallest = {
spacingInNormalDirection: Infinity,
imageVolume: null,
actorUID: null,
};

for (let i = 0; i < imageVolumes.length; i++) {
Expand All @@ -74,9 +90,16 @@ export default function getTargetVolumeAndSpacingInNormalDir(
viewPlaneNormal
);

if (spacingInNormalDirection < smallest.spacingInNormalDirection) {
// Allow for EPSILON part larger requirement to prefer earlier volumes
// when the spacing is within a factor of EPSILON. Use a factor because
// that deals with very small or very large volumes effectively.
if (
spacingInNormalDirection * EPSILON_PART <
smallest.spacingInNormalDirection
) {
smallest.spacingInNormalDirection = spacingInNormalDirection;
smallest.imageVolume = imageVolume;
smallest.actorUID = volumeActors[i].uid;
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/tools/src/types/JumpToSliceOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
type JumpToSliceOptions = {
imageIndex: number;
debounceLoading?: boolean;
volumeId?: string;
};

export default JumpToSliceOptions;
3 changes: 2 additions & 1 deletion packages/tools/src/utilities/cine/playClip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function playClip(
targetImageIdIndex: viewport.getTargetImageIdIndex(),
imageIds: viewport.getImageIds(),
};

let newImageIdIndex = stackData.targetImageIdIndex;
const imageCount = stackData.imageIds.length;

Expand Down Expand Up @@ -182,6 +182,7 @@ function playClip(
*/
function stopClip(element: HTMLDivElement): void {
const enabledElement = getEnabledElement(element);
if (!enabledElement) return;
const { viewport } = enabledElement;

const cineToolData = getToolState(viewport.element);
Expand Down
9 changes: 5 additions & 4 deletions packages/tools/src/utilities/scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,20 @@ export function scrollVolume(
) {
const camera = viewport.getCamera();
const { focalPoint, viewPlaneNormal, position } = camera;
const { spacingInNormalDirection, imageVolume } =
const { spacingInNormalDirection, actorUID } =
csUtils.getTargetVolumeAndSpacingInNormalDir(viewport, camera, volumeId);

if (!imageVolume) {
if (!actorUID) {
throw new Error(
`Could not find image volume with id ${volumeId} in the viewport`
);
}

const actorEntry = viewport.getActor(imageVolume.volumeId);
const actorEntry = viewport.getActor(actorUID);

if (!actorEntry) {
console.warn('No actor found for with actorUID of', imageVolume.volumeId);
console.warn('No actor found for with actorUID of', actorUID);
return;
}

const volumeActor = actorEntry.actor as Types.VolumeActor;
Expand Down
4 changes: 2 additions & 2 deletions packages/tools/src/utilities/viewport/jumpToSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function jumpToSlice(
element: HTMLDivElement,
options = {} as JumpToSliceOptions
): Promise<void> {
const { imageIndex, debounceLoading } = options;
const { imageIndex, debounceLoading, volumeId } = options;
const enabledElement = getEnabledElement(element);

if (!enabledElement) {
Expand All @@ -40,7 +40,7 @@ async function jumpToSlice(
const imageIndexToJump = _getImageIndexToJump(numberOfSlices, imageIndex);
const delta = imageIndexToJump - currentImageIndex;

scroll(viewport, { delta, debounceLoading });
scroll(viewport, { delta, debounceLoading, volumeId });
}

function _getImageSliceData(
Expand Down

0 comments on commit 79b8c96

Please sign in to comment.