diff --git a/common/reviews/api/tools.api.md b/common/reviews/api/tools.api.md index 870142c859..e04222237f 100644 --- a/common/reviews/api/tools.api.md +++ b/common/reviews/api/tools.api.md @@ -231,6 +231,10 @@ export class AngleTool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: AngleTool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => AngleAnnotation; // (undocumented) isDrawing: boolean; @@ -645,6 +649,10 @@ export class ArrowAnnotateTool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], text?: string, options?: { annotationUID?: string; + toolInstance?: ArrowAnnotateTool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => ArrowAnnotation; // (undocumented) isDrawing: boolean; @@ -1244,6 +1252,10 @@ export class CircleROITool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: CircleROITool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => CircleROIAnnotation; // (undocumented) isDrawing: boolean; @@ -2231,6 +2243,10 @@ export class EllipticalROITool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: EllipticalROITool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => EllipticalROIAnnotation; // (undocumented) isDrawing: boolean; @@ -3639,6 +3655,10 @@ export class LengthTool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: LengthTool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => LengthAnnotation; // (undocumented) isDrawing: boolean; @@ -4406,6 +4426,10 @@ export class ProbeTool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: ProbeTool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => ProbeAnnotation; // (undocumented) isDrawing: boolean; @@ -4737,6 +4761,10 @@ export class RectangleROITool extends AnnotationTool { // (undocumented) static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; + toolInstance?: RectangleROITool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => RectangleROIAnnotation; // (undocumented) isDrawing: boolean; @@ -5676,6 +5704,10 @@ export class SplineROITool extends ContourSegmentationBaseTool { static hydrate: (viewportId: string, points: Types_2.Point3[], options?: { annotationUID?: string; splineType?: SplineTypesEnum; + toolInstance?: SplineROITool; + referencedImageId?: string; + viewplaneNormal?: Types_2.Point3; + viewUp?: Types_2.Point3; }) => SplineROIAnnotation; // (undocumented) protected isContourSegmentationTool(): boolean; diff --git a/packages/tools/examples/dynamicallyAddAnnotations/angleToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/angleToolUI.ts index b0e762f918..a80d6ff903 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/angleToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/angleToolUI.ts @@ -65,6 +65,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -76,30 +81,41 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const worldPoint1 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point1) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point1 + ) : viewport.canvasToWorld(coords.point1); const worldPoint2 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point2) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point2 + ) : viewport.canvasToWorld(coords.point2); const worldPoint3 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point3) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point3 + ) : viewport.canvasToWorld(coords.point3); AngleTool.hydrate(viewport.id, [worldPoint1, worldPoint2, worldPoint3]); diff --git a/packages/tools/examples/dynamicallyAddAnnotations/arrowAnnotateToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/arrowAnnotateToolUI.ts index 01261ae982..d0578d4ed5 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/arrowAnnotateToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/arrowAnnotateToolUI.ts @@ -53,6 +53,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -64,14 +69,16 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const textInput = form.querySelector(`#${type}-text`) as HTMLInputElement; const text = textInput ? textInput.value : ''; @@ -80,12 +87,18 @@ function addButtonListeners(form: HTMLFormElement): void { const point1 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point1) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point1 + ) : viewport.canvasToWorld(coords.point1); const point2 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point2) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point2 + ) : viewport.canvasToWorld(coords.point2); ArrowAnnotateTool.hydrate(viewport.id, [point1, point2], text); diff --git a/packages/tools/examples/dynamicallyAddAnnotations/circleROIToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/circleROIToolUI.ts index 6085dda1ec..f83446704b 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/circleROIToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/circleROIToolUI.ts @@ -51,6 +51,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -62,28 +67,38 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const worldCenter = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.center) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.center + ) : viewport.canvasToWorld(coords.center); const worldRadiusPoint = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.radiusPoint) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.radiusPoint + ) : viewport.canvasToWorld(coords.radiusPoint); - CircleROITool.hydrate(viewport.id, [worldCenter, worldRadiusPoint]); + CircleROITool.hydrate(viewport.id, [worldCenter, worldRadiusPoint], { + referencedImageId: imageId, + }); }); }); } diff --git a/packages/tools/examples/dynamicallyAddAnnotations/ellipticalROIToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/ellipticalROIToolUI.ts index 6ce414dc45..4f64d6f789 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/ellipticalROIToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/ellipticalROIToolUI.ts @@ -70,6 +70,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -81,20 +86,22 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const convertPoint = (point: Point2): Point3 => type === 'image' - ? (utilities.imageToWorldCoords(currentImageId, point) as Point3) + ? (utilities.imageToWorldCoords(imageId || currentImageId, point) as Point3) : viewport.canvasToWorld(point); const points: Point3[] = [ diff --git a/packages/tools/examples/dynamicallyAddAnnotations/lengthToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/lengthToolUI.ts index d9bf0ec17e..4a065b20ea 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/lengthToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/lengthToolUI.ts @@ -52,6 +52,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -63,25 +68,33 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const worldStart = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.topLeft) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.topLeft + ) : viewport.canvasToWorld(coords.topLeft); const worldEnd = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.topRight) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.topRight + ) : viewport.canvasToWorld(coords.topRight); LengthTool.hydrate(viewport.id, [worldStart, worldEnd]); diff --git a/packages/tools/examples/dynamicallyAddAnnotations/probeToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/probeToolUI.ts index 23d022f8b7..71df27ed8d 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/probeToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/probeToolUI.ts @@ -42,6 +42,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -53,20 +58,25 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const worldStart = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.topLeft) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.topLeft + ) : viewport.canvasToWorld(coords.topLeft); ProbeTool.hydrate(viewport.id, [worldStart]); diff --git a/packages/tools/examples/dynamicallyAddAnnotations/rectangleROIToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/rectangleROIToolUI.ts index 62284e766a..0e5acad432 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/rectangleROIToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/rectangleROIToolUI.ts @@ -71,6 +71,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -82,20 +87,25 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const convertPoint = (point: Point2): Point3 => type === 'image' - ? (utilities.imageToWorldCoords(currentImageId, point) as Point3) + ? (utilities.imageToWorldCoords( + imageId || currentImageId, + point + ) as Point3) : viewport.canvasToWorld(point); const points: Point3[] = [ diff --git a/packages/tools/examples/dynamicallyAddAnnotations/splineROIToolUI.ts b/packages/tools/examples/dynamicallyAddAnnotations/splineROIToolUI.ts index de9b56b0f8..d2dcb39983 100644 --- a/packages/tools/examples/dynamicallyAddAnnotations/splineROIToolUI.ts +++ b/packages/tools/examples/dynamicallyAddAnnotations/splineROIToolUI.ts @@ -65,6 +65,11 @@ function createFormElement(): HTMLFormElement {
+ ${ + coordType === 'image' + ? ` ` + : '' + }

`; }); @@ -76,37 +81,48 @@ function addButtonListeners(form: HTMLFormElement): void { const buttons = form.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', () => { - const [type, viewportType] = button.id.split('-') as [ + const [type, viewportType, useImageId] = button.id.split('-') as [ 'canvas' | 'image', - keyof typeof typeToIdMap + keyof typeof typeToIdMap, + 'imageId'? ]; const enabledElement = getEnabledElementByViewportId( typeToIdMap[viewportType] ); const viewport = enabledElement.viewport; + const imageId = useImageId && viewport.getImageIds()[0]; const coords = getCoordinates(form, type); const currentImageId = viewport.getCurrentImageId() as string; const worldPoint1 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point1) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point1 + ) : viewport.canvasToWorld(coords.point1); const worldPoint2 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point2) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point2 + ) : viewport.canvasToWorld(coords.point2); const worldPoint3 = type === 'image' - ? utilities.imageToWorldCoords(currentImageId, coords.point3) + ? utilities.imageToWorldCoords( + imageId || currentImageId, + coords.point3 + ) : viewport.canvasToWorld(coords.point3); - SplineROITool.hydrate(viewport.id, [ - worldPoint1, - worldPoint2, - worldPoint3, - ]); + SplineROITool.hydrate( + viewport.id, + [worldPoint1, worldPoint2, worldPoint3], + { referencedImageId: imageId } + ); }); }); } diff --git a/packages/tools/src/tools/annotation/AngleTool.ts b/packages/tools/src/tools/annotation/AngleTool.ts index 06b37e5f63..14756d45da 100644 --- a/packages/tools/src/tools/annotation/AngleTool.ts +++ b/packages/tools/src/tools/annotation/AngleTool.ts @@ -88,6 +88,10 @@ class AngleTool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: AngleTool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): AngleAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -97,19 +101,34 @@ class AngleTool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts b/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts index 198f668a63..5917f7b8b2 100644 --- a/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts +++ b/packages/tools/src/tools/annotation/ArrowAnnotateTool.ts @@ -87,6 +87,10 @@ class ArrowAnnotateTool extends AnnotationTool { text?: string, options?: { annotationUID?: string; + toolInstance?: ArrowAnnotateTool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): ArrowAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -96,19 +100,34 @@ class ArrowAnnotateTool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/CircleROITool.ts b/packages/tools/src/tools/annotation/CircleROITool.ts index 8a338784b2..931ab915ca 100644 --- a/packages/tools/src/tools/annotation/CircleROITool.ts +++ b/packages/tools/src/tools/annotation/CircleROITool.ts @@ -1029,6 +1029,10 @@ class CircleROITool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: CircleROITool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): CircleROIAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -1038,19 +1042,34 @@ class CircleROITool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/EllipticalROITool.ts b/packages/tools/src/tools/annotation/EllipticalROITool.ts index 11e4427d00..502c8373da 100644 --- a/packages/tools/src/tools/annotation/EllipticalROITool.ts +++ b/packages/tools/src/tools/annotation/EllipticalROITool.ts @@ -156,6 +156,10 @@ class EllipticalROITool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: EllipticalROITool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): EllipticalROIAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -165,19 +169,34 @@ class EllipticalROITool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/LengthTool.ts b/packages/tools/src/tools/annotation/LengthTool.ts index a2c5ec3223..03827d84ec 100644 --- a/packages/tools/src/tools/annotation/LengthTool.ts +++ b/packages/tools/src/tools/annotation/LengthTool.ts @@ -138,6 +138,10 @@ class LengthTool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: LengthTool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): LengthAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -147,19 +151,34 @@ class LengthTool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || utilities.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/ProbeTool.ts b/packages/tools/src/tools/annotation/ProbeTool.ts index 7327a9e58c..9babf47551 100644 --- a/packages/tools/src/tools/annotation/ProbeTool.ts +++ b/packages/tools/src/tools/annotation/ProbeTool.ts @@ -149,6 +149,10 @@ class ProbeTool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: ProbeTool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): ProbeAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -158,19 +162,34 @@ class ProbeTool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/RectangleROITool.ts b/packages/tools/src/tools/annotation/RectangleROITool.ts index 623c1a194d..693a26e5db 100644 --- a/packages/tools/src/tools/annotation/RectangleROITool.ts +++ b/packages/tools/src/tools/annotation/RectangleROITool.ts @@ -973,6 +973,10 @@ class RectangleROITool extends AnnotationTool { points: Types.Point3[], options?: { annotationUID?: string; + toolInstance?: RectangleROITool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): RectangleROIAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -982,19 +986,34 @@ class RectangleROITool extends AnnotationTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId // we should make those static too - const instance = new this(); + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + const annotation = { annotationUID: options?.annotationUID || csUtils.uuidv4(), data: { diff --git a/packages/tools/src/tools/annotation/SplineROITool.ts b/packages/tools/src/tools/annotation/SplineROITool.ts index 9b13128359..c4608d176c 100644 --- a/packages/tools/src/tools/annotation/SplineROITool.ts +++ b/packages/tools/src/tools/annotation/SplineROITool.ts @@ -1240,6 +1240,10 @@ class SplineROITool extends ContourSegmentationBaseTool { options?: { annotationUID?: string; splineType?: SplineTypesEnum; + toolInstance?: SplineROITool; + referencedImageId?: string; + viewplaneNormal?: Types.Point3; + viewUp?: Types.Point3; } ): SplineROIAnnotation => { const enabledElement = getEnabledElementByViewportId(viewportId); @@ -1254,32 +1258,55 @@ class SplineROITool extends ContourSegmentationBaseTool { const { viewport } = enabledElement; const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); - const { viewPlaneNormal, viewUp } = viewport.getCamera(); + + let { viewPlaneNormal, viewUp } = viewport.getCamera(); + viewPlaneNormal = options?.viewplaneNormal ?? viewPlaneNormal; + viewUp = options?.viewUp ?? viewUp; // This is a workaround to access the protected method getReferencedImageId - // we should make those static too - const instance = new this(); + // we should make those static too Use the provided instance if available so + // that correct configuration is used. + const instance = options?.toolInstance ?? new this(); - const referencedImageId = instance.getReferencedImageId( + let referencedImageId = instance.getReferencedImageId( viewport, points[0], viewPlaneNormal, viewUp ); + if (options?.referencedImageId) { + // If the provided referencedImageId is not the same as the one calculated + // by the camera positions, only set the referencedImageId. The scenario + // here is that only a referencedImageId is given in the options, which + // does not match the current camera position, so the user is wanting to + // apply the annotation to a specific image. + if (referencedImageId !== options.referencedImageId) { + viewPlaneNormal = undefined; + viewUp = undefined; + } + referencedImageId = options.referencedImageId; + } + // Create appropriate spline instance based on type or default const splineType = options?.splineType || SplineTypesEnum.CatmullRom; const splineConfig = instance._getSplineConfig(splineType); const SplineClass = splineConfig.Class; const splineInstance = new SplineClass(); - // Convert world points to canvas for the spline - const canvasPoints = points.map((point) => viewport.worldToCanvas(point)); - splineInstance.setControlPoints(canvasPoints); - const splinePolylineCanvas = splineInstance.getPolylinePoints(); - const splinePolylineWorld = splinePolylineCanvas.map((point) => - viewport.canvasToWorld(point) - ); + /** + * The following appears to be done when rendering the spline, so don't need + * to do it here. This is helpful anyways because if we are adding an + * annotation to an image/plane that is not currently displayed we can't get + * the canvas coordinates for the points. + */ + // Convert world points to canvas for the spline + // const canvasPoints = points.map((point) => viewport.worldToCanvas(point)); + // splineInstance.setControlPoints(canvasPoints); + // const splinePolylineCanvas = splineInstance.getPolylinePoints(); + // const splinePolylineWorld = splinePolylineCanvas.map((point) => + // viewport.canvasToWorld(point) + // ); const annotation = { annotationUID: options?.annotationUID || utilities.uuidv4(), @@ -1295,7 +1322,7 @@ class SplineROITool extends ContourSegmentationBaseTool { }, contour: { closed: true, - polyline: splinePolylineWorld, + // polyline: splinePolylineWorld, }, }, highlighted: false,