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

fix for elliptical roi #479

Merged
merged 4 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1527,6 +1527,7 @@ interface EllipticalROIAnnotation extends Annotation {
};
label: string;
cachedStats?: ROICachedStats;
initialRotation: number;
};
}

Expand Down
20 changes: 14 additions & 6 deletions packages/adapters/src/adapters/Cornerstone3D/EllipticalROI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,27 @@ class EllipticalROI {
static getTID300RepresentationArguments(tool, worldToImageCoords) {
const { data, finding, findingSites, metadata } = tool;
const { cachedStats = {}, handles } = data;

const rotation = data.initialRotation || 0;
const { referencedImageId } = metadata;

if (!referencedImageId) {
throw new Error(
"EllipticalROI.getTID300RepresentationArguments: referencedImageId is not defined"
);
}

const top = worldToImageCoords(referencedImageId, handles.points[0]);
const bottom = worldToImageCoords(referencedImageId, handles.points[1]);
const left = worldToImageCoords(referencedImageId, handles.points[2]);
const right = worldToImageCoords(referencedImageId, handles.points[3]);
let top, bottom, left, right;
// this way when it's restored we can assume the initial rotation is 0.
if (rotation == 90 || rotation == 270) {
bottom = worldToImageCoords(referencedImageId, handles.points[2]);
top = worldToImageCoords(referencedImageId, handles.points[3]);
left = worldToImageCoords(referencedImageId, handles.points[0]);
right = worldToImageCoords(referencedImageId, handles.points[1]);
} else {
top = worldToImageCoords(referencedImageId, handles.points[0]);
bottom = worldToImageCoords(referencedImageId, handles.points[1]);
left = worldToImageCoords(referencedImageId, handles.points[2]);
right = worldToImageCoords(referencedImageId, handles.points[3]);
}

// find the major axis and minor axis
const topBottomLength = Math.abs(top[1] - bottom[1]);
Expand Down
103 changes: 98 additions & 5 deletions packages/tools/examples/stackAnnotationTools/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { RenderingEngine, Types, Enums } from '@cornerstonejs/core';
import {
RenderingEngine,
Types,
Enums,
getRenderingEngine,
} from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setTitleAndDescription,
addDropdownToToolbar,
addButtonToToolbar,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';

Expand All @@ -25,8 +31,10 @@ const {
Enums: csToolsEnums,
} = cornerstoneTools;

const { ViewportType } = Enums;
const { ViewportType, Events } = Enums;
const { MouseBindings } = csToolsEnums;
const renderingEngineId = 'myRenderingEngine';
const viewportId = 'CT_STACK';

// ======== Set up page ======== //
setTitleAndDescription(
Expand All @@ -46,10 +54,42 @@ element.style.height = '500px';

content.appendChild(element);

const info = document.createElement('div');
content.appendChild(info);

const instructions = document.createElement('p');
instructions.innerText = 'Left Click to use selected tool';
info.appendChild(instructions);

const rotationInfo = document.createElement('div');
info.appendChild(rotationInfo);

const flipHorizontalInfo = document.createElement('div');
info.appendChild(flipHorizontalInfo);

const flipVerticalInfo = document.createElement('div');
info.appendChild(flipVerticalInfo);

element.addEventListener(Events.CAMERA_MODIFIED, (_) => {
// Get the rendering engine
const renderingEngine = getRenderingEngine(renderingEngineId);

// Get the stack viewport
const viewport = <Types.IStackViewport>(
renderingEngine.getViewport(viewportId)
);

if (!viewport) {
return;
}

const { flipHorizontal, flipVertical } = viewport.getCamera();
const { rotation } = viewport.getProperties();

content.append(instructions);
rotationInfo.innerText = `Rotation: ${Math.round(rotation)}`;
flipHorizontalInfo.innerText = `Flip horizontal: ${flipHorizontal}`;
flipVerticalInfo.innerText = `Flip vertical: ${flipVertical}`;
});
// ============================= //

const toolGroupId = 'STACK_TOOL_GROUP_ID';
Expand Down Expand Up @@ -88,6 +128,61 @@ addDropdownToToolbar({
},
});

addButtonToToolbar({
title: 'Flip H',
onClick: () => {
// Get the rendering engine
const renderingEngine = getRenderingEngine(renderingEngineId);

// Get the stack viewport
const viewport = <Types.IStackViewport>(
renderingEngine.getViewport(viewportId)
);

const { flipHorizontal } = viewport.getCamera();
viewport.setCamera({ flipHorizontal: !flipHorizontal });

viewport.render();
},
});

addButtonToToolbar({
title: 'Flip V',
onClick: () => {
// Get the rendering engine
const renderingEngine = getRenderingEngine(renderingEngineId);

// Get the stack viewport
const viewport = <Types.IStackViewport>(
renderingEngine.getViewport(viewportId)
);

const { flipVertical } = viewport.getCamera();

viewport.setCamera({ flipVertical: !flipVertical });

viewport.render();
},
});

addButtonToToolbar({
title: 'Rotate Delta 90',
onClick: () => {
// Get the rendering engine
const renderingEngine = getRenderingEngine(renderingEngineId);

// Get the stack viewport
const viewport = <Types.IStackViewport>(
renderingEngine.getViewport(viewportId)
);

const { rotation } = viewport.getProperties();
viewport.setProperties({ rotation: rotation + 90 });

viewport.render();
},
});

/**
* Runs the demo
*/
Expand Down Expand Up @@ -148,11 +243,9 @@ async function run() {
});

// Instantiate a rendering engine
const renderingEngineId = 'myRenderingEngine';
const renderingEngine = new RenderingEngine(renderingEngineId);

// Create a stack viewport
const viewportId = 'CT_STACK';
const viewportInput = {
viewportId,
type: ViewportType.STACK,
Expand Down
20 changes: 18 additions & 2 deletions packages/tools/src/tools/annotation/EllipticalROITool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class EllipticalROITool extends AnnotationTool {
activeHandleIndex: null,
},
cachedStats: {},
initialRotation: viewport.getRotation(),
},
};

Expand Down Expand Up @@ -765,9 +766,24 @@ class EllipticalROITool extends AnnotationTool {
const canvasCoordinates = points.map((p) =>
viewport.worldToCanvas(p)
) as [Types.Point2, Types.Point2, Types.Point2, Types.Point2];
const canvasCorners = <Array<Types.Point2>>(
getCanvasEllipseCorners(canvasCoordinates)

const rotation = Math.abs(
viewport.getRotation() - (data.initialRotation || 0)
);
let canvasCorners;

if (rotation == 90 || rotation == 270) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you check the save/restore in the adapters please?

Copy link
Collaborator Author

@IbrahimCSAE IbrahimCSAE Mar 16, 2023

Choose a reason for hiding this comment

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

Is this what you are referring to?

https://github.com/cornerstonejs/cornerstone3D-beta/blob/b989d505098a2d1dcdcb23c9af7ace719f07dcbd/packages/adapters/src/adapters/Cornerstone3D/EllipticalROI.ts#L96

would you like me to follow this approach here too?

I'm not sure what you mean by save/restore

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, I want you to run OHIF, create some markup with different initial rotations, then save it, and see if it still displays the same object after it loads back in. You may need to do something special in the adapter to make sure it gets saved/restored correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah it doesn’t save correctly, I’ll work on this and update you.

Copy link
Collaborator Author

@IbrahimCSAE IbrahimCSAE Mar 17, 2023

Choose a reason for hiding this comment

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

It works as expected now, before saving, If its already rotated, I convert so the rotation is 0, so when its restored we won't need the rotation value since it will always be 0.

FYI the DICOMSRDisplayTool in OHIF needs to change so it renders properly, only the cornerstone native tool renders properly now.

It renders fine in my GIF because I modified the DICOMSRDisplayTool locally to account for the rotation the same way I did it for the native cornerstone tool. so this below has to be added to the DICOMSRDisplayTool

https://github.com/OHIF/Viewers/blob/544bf55a4fb33400a25929c34ced0d1b95b2e125/extensions/cornerstone-dicom-sr/src/tools/DICOMSRDisplayTool.ts#L292

    const rotation = viewport.getRotation();

      canvasCoordinates = ellipsePointsWorld.map(p =>
        viewport.worldToCanvas(p)
      );
      let canvasCorners;
      if (rotation == 90 || rotation == 270) {
        canvasCorners = <Array<Types.Point2>>(
          utilities.math.ellipse.getCanvasEllipseCorners([
            canvasCoordinates[2],
            canvasCoordinates[3],
            canvasCoordinates[0],
            canvasCoordinates[1],
          ])
        );
      } else {
        canvasCorners = <Array<Types.Point2>>(
          utilities.math.ellipse.getCanvasEllipseCorners(canvasCoordinates)
        );
      }

GIF 6

Thank u

canvasCorners = <Array<Types.Point2>>getCanvasEllipseCorners([
canvasCoordinates[2], // bottom
canvasCoordinates[3], // top
canvasCoordinates[0], // left
canvasCoordinates[1], // right
]);
} else {
canvasCorners = <Array<Types.Point2>>(
getCanvasEllipseCorners(canvasCoordinates) // bottom, top, left, right, keep as is
);
}

const { centerPointRadius } = this.configuration;

Expand Down
1 change: 1 addition & 0 deletions packages/tools/src/types/ToolSpecificAnnotationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface EllipticalROIAnnotation extends Annotation {
};
label: string;
cachedStats?: ROICachedStats;
initialRotation: number;
};
}

Expand Down