Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(SR): SCOORD3D point annotations support for volume and stack viewports #1446

2 changes: 2 additions & 0 deletions common/reviews/api/core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2797,6 +2797,8 @@ type ReferenceCompatibleOptions = {
asVolume?: boolean;
withOrientation?: boolean;
imageURI?: string;
isFiltering?: boolean;
currentImageId?: string;
};

// @public (undocumented)
Expand Down
2 changes: 1 addition & 1 deletion packages/adapters/.babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
}
}]
]
}
}
1 change: 0 additions & 1 deletion packages/core/src/RenderingEngine/BaseVolumeViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import type {
VolumeViewportProperties,
ViewReferenceSpecifier,
ReferenceCompatibleOptions,
ViewPresentation,
ViewReference,
IVolumeViewport,
} from '../types';
Expand Down
53 changes: 49 additions & 4 deletions packages/core/src/RenderingEngine/StackViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import type {
StackViewportProperties,
VOIRange,
ViewReference,
ViewPresentation,
VolumeActor,
} from '../types';
import {
Expand Down Expand Up @@ -98,6 +97,7 @@ import correctShift from './helpers/cpuFallback/rendering/correctShift';
import resetCamera from './helpers/cpuFallback/rendering/resetCamera';
import { Transform } from './helpers/cpuFallback/rendering/transform';
import { findMatchingColormap } from '../utilities/colormap';
import findIndexByFOR from './helpers/findIndexByFOR';

const EPSILON = 1; // Slice Thickness

Expand Down Expand Up @@ -2903,7 +2903,13 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
}

let { imageURI } = options;
const { referencedImageId, sliceIndex } = viewRef;
const { currentImageId, isFiltering = false } = options;
const {
referencedImageId,
sliceIndex,
cameraFocalPoint,
FrameOfReferenceUID,
} = viewRef;

if (viewRef.volumeId && !referencedImageId) {
return options.asVolume === true;
Expand All @@ -2913,16 +2919,38 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
if (options.withNavigation && typeof sliceIndex === 'number') {
testIndex = sliceIndex;
}

const imageId = this.imageIds[testIndex];
if (!imageId) {
return false;
}

if (!imageURI) {
// Remove the dataLoader scheme since that can change
const colonIndex = imageId.indexOf(':');
imageURI = imageId.substring(colonIndex + 1);
}
return referencedImageId?.endsWith(imageURI);

const endsWith = referencedImageId?.endsWith(imageURI);
if (endsWith) {
return endsWith;
}

if (cameraFocalPoint && FrameOfReferenceUID) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no scenario where we don't have cameraFocalPoint

const imageIds =
isFiltering === true
? this.imageIds.filter((imageId) => imageId === currentImageId)
: this.imageIds;

const foundIndex = findIndexByFOR({
FrameOfReferenceUID,
imageIds,
cameraFocalPoint,
});
return foundIndex !== -1;
} else {
return false;
}
}

/**
Expand Down Expand Up @@ -2965,7 +2993,13 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
if (!viewRef) {
return;
}
const { referencedImageId, sliceIndex } = viewRef;
const {
referencedImageId,
sliceIndex,
cameraFocalPoint,
FrameOfReferenceUID,
} = viewRef;

if (
typeof sliceIndex === 'number' &&
referencedImageId &&
Expand All @@ -2976,6 +3010,17 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
const foundIndex = this.imageIds.indexOf(referencedImageId);
if (foundIndex !== -1) {
this.scroll(foundIndex - this.targetImageIdIndex);
} else if (cameraFocalPoint && FrameOfReferenceUID) {
const foundIndex = findIndexByFOR({
FrameOfReferenceUID,
imageIds: this.imageIds,
cameraFocalPoint,
});

if (foundIndex !== -1) {
this.scroll(foundIndex - this.targetImageIdIndex);
return;
}
} else {
throw new Error('Unsupported - referenced image id not found');
}
Expand Down
40 changes: 40 additions & 0 deletions packages/core/src/RenderingEngine/helpers/findIndexByFOR.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as metaData from '../../metaData';

const findIndexByFOR = ({
imageIds,
FrameOfReferenceUID,
cameraFocalPoint,
}) => {
let foundIndex = -1;
for (let i = 0; i < imageIds.length; ++i) {
const imageMetadata = metaData.get('instance', imageIds[i]);
if (imageMetadata.FrameOfReferenceUID !== FrameOfReferenceUID) {
continue;
}

const sliceNormal = [0, 0, 0];
const orientation = imageMetadata.ImageOrientationPatient;
sliceNormal[0] =
orientation[1] * orientation[5] - orientation[2] * orientation[4];
sliceNormal[1] =
orientation[2] * orientation[3] - orientation[0] * orientation[5];
sliceNormal[2] =
orientation[0] * orientation[4] - orientation[1] * orientation[3];

let distanceAlongNormal = 0;
for (let j = 0; j < 3; ++j) {
distanceAlongNormal +=
sliceNormal[j] * imageMetadata.ImagePositionPatient[j];
}

/** Assuming 2 mm tolerance */
if (Math.abs(distanceAlongNormal - cameraFocalPoint[2]) > 2) {
continue;
}
foundIndex = i;
break;
}
return foundIndex;
};

export default findIndexByFOR;
2 changes: 2 additions & 0 deletions packages/core/src/types/IViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export type ReferenceCompatibleOptions = {
* not need to be provided.
*/
imageURI?: string;
isFiltering?: boolean;
currentImageId?: string;
Comment on lines +72 to +73
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these belongs here

};

/**
Expand Down
31 changes: 20 additions & 11 deletions packages/tools/src/tools/annotation/ProbeTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ import {
} from '../../types';
import { ProbeAnnotation } from '../../types/ToolSpecificAnnotationTypes';
import { StyleSpecifier } from '../../types/AnnotationStyle';
import {
ModalityUnitOptions,
getModalityUnit,
} from '../../utilities/getModalityUnit';
import { getModalityUnit } from '../../utilities/getModalityUnit';
import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';

const { transformWorldToIndex } = csUtils;
Expand Down Expand Up @@ -119,6 +116,7 @@ class ProbeTool extends AnnotationTool {
shadow: true,
preventHandleOutsideImage: false,
getTextLines: defaultGetTextLines,
useViewReference: false,
},
}
) {
Expand Down Expand Up @@ -152,31 +150,42 @@ class ProbeTool extends AnnotationTool {
const { viewport, renderingEngine } = enabledElement;

this.isDrawing = true;

const camera = viewport.getCamera();
const { viewPlaneNormal, viewUp } = camera;

const referencedImageId = this.getReferencedImageId(
viewport,
worldPos,
viewPlaneNormal,
viewUp
);

const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
const points = [<Types.Point3>[...worldPos]];

const refImageProps = {
viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
viewUp: <Types.Point3>[...viewUp],
FrameOfReferenceUID,
referencedImageId,
};

const viewRefProps = {
...viewport.getViewReference({ points }),
viewPlaneNormal: undefined,
viewUp: undefined,
cameraFocalPoint: points[0],
};

const annotation = {
invalidated: true,
highlighted: true,
metadata: {
toolName: this.getToolName(),
viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
viewUp: <Types.Point3>[...viewUp],
FrameOfReferenceUID,
referencedImageId,
...(this.configuration.useViewReference ? viewRefProps : refImageProps),
},
data: {
label: '',
handles: { points: [<Types.Point3>[...worldPos]] },
handles: { points },
cachedStats: {},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function filterAnnotationsForDisplay(
spacingInNormalDirection
);
}

if (viewport instanceof StackViewport) {
// 1. Get the currently displayed imageId from the StackViewport
const imageId = viewport.getCurrentImageId();
Expand All @@ -40,9 +41,12 @@ export default function filterAnnotationsForDisplay(
// created on the volumeViewport initially and has the volumeLoader scheme
// but shares the same imageId
const colonIndex = imageId.indexOf(':');

filterOptions.imageURI = imageId.substring(colonIndex + 1);
filterOptions.currentImageId = imageId;
}

filterOptions.isFiltering = true;

return annotations.filter((annotation) => {
if (!annotation.isVisible) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export function filterAnnotationsWithinSamePlane(
(td: Annotation) => {
let annotationViewPlaneNormal = td.metadata.viewPlaneNormal;

// If point graphic type then don't set view plane normal
// @ts-ignore
if (td.metadata.graphicType === 'POINT') {
return true;
}

if (!annotationViewPlaneNormal) {
// This code is run to set the annotation view plane normal
// for historical data which was saved without the normal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export default function filterAnnotationsWithinSlice(
(td: Annotation) => {
let annotationViewPlaneNormal = td.metadata.viewPlaneNormal;

// If point graphic type then don't set view plane normal
// @ts-ignore
if (td.metadata.graphicType === 'POINT') {
return true;
}

if (!annotationViewPlaneNormal) {
// This code is run to set the annotation view plane normal
// for historical data which was saved without the normal.
Expand Down
Loading