Skip to content

Commit

Permalink
feat(referenceLines): showFullDimension option to ReferenceLines tool (
Browse files Browse the repository at this point in the history
…#784)

* showFullDimension option to ReferenceLines tool

* refactor

* update api
  • Loading branch information
m00n620 authored Sep 27, 2023
1 parent a3a4162 commit f9a498a
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 10 deletions.
4 changes: 4 additions & 0 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4440,10 +4440,14 @@ class ReferenceLines extends AnnotationDisplayTool {
// (undocumented)
_init: () => void;
// (undocumented)
intersectInfiniteLines(line1Start: Types_2.Point2, line1End: Types_2.Point2, line2Start: Types_2.Point2, line2End: Types_2.Point2): number[];
// (undocumented)
isDrawing: boolean;
// (undocumented)
isHandleOutsideImage: boolean;
// (undocumented)
isInBound(point: number[], dimensions: Types_2.Point3): boolean;
// (undocumented)
isParallel(vec1: Types_2.Point3, vec2: Types_2.Point3): boolean;
// (undocumented)
isPerpendicular: (vec1: Types_2.Point3, vec2: Types_2.Point3) => boolean;
Expand Down
22 changes: 15 additions & 7 deletions packages/tools/examples/referenceLines/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
createImageIdsAndCacheMetaData,
setTitleAndDescription,
addDropdownToToolbar,
addCheckboxToToolbar,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';

Expand Down Expand Up @@ -138,17 +139,24 @@ addDropdownToToolbar({
const element = elements[index];
element.style.border = '5px solid yellow';

toolGroup.setToolConfiguration(
ReferenceLinesTool.toolName,
{
sourceViewportId: selectedViewportId,
},
true // overwrite
);
toolGroup.setToolConfiguration(ReferenceLinesTool.toolName, {
sourceViewportId: selectedViewportId,
});

toolGroup.setToolEnabled(ReferenceLinesTool.toolName);
},
});

addCheckboxToToolbar({
id: 'show-full-dimension-checkbox',
title: 'Show Full Dimension',
checked: false,
onChange: (showFullDimension) => {
toolGroup.setToolConfiguration(ReferenceLinesTool.toolName, {
showFullDimension,
});
},
});
/**
* Runs the demo
*/
Expand Down
134 changes: 131 additions & 3 deletions packages/tools/src/tools/ReferenceLinesTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { addAnnotation } from '../stateManagement/annotation/annotationState';
import { drawLine as drawLineSvg } from '../drawingSvg';
import { filterViewportsWithToolEnabled } from '../utilities/viewportFilters';
import triggerAnnotationRenderForViewportIds from '../utilities/triggerAnnotationRenderForViewportIds';

import { PublicToolProps, ToolProps, SVGDrawingHelper } from '../types';
import { ReferenceLineAnnotation } from '../types/ToolSpecificAnnotationTypes';
import { StyleSpecifier } from '../types/AnnotationStyle';
Expand Down Expand Up @@ -43,6 +42,7 @@ class ReferenceLines extends AnnotationDisplayTool {
supportedInteractionTypes: ['Mouse', 'Touch'],
configuration: {
sourceViewportId: '',
showFullDimension: false,
},
}
) {
Expand Down Expand Up @@ -177,7 +177,7 @@ class ReferenceLines extends AnnotationDisplayTool {
const bottomLeft = annotation.data.handles.points[2];
const bottomRight = annotation.data.handles.points[3];

const { focalPoint, viewPlaneNormal } = targetViewport.getCamera();
const { focalPoint, viewPlaneNormal, viewUp } = targetViewport.getCamera();
const { viewPlaneNormal: sourceViewPlaneNormal } =
sourceViewport.getCamera();

Expand Down Expand Up @@ -239,10 +239,21 @@ class ReferenceLines extends AnnotationDisplayTool {
const color = this.getStyle('color', styleSpecifier, annotation);
const shadow = this.getStyle('shadow', styleSpecifier, annotation);

const canvasCoordinates = [lineStartWorld, lineEndWorld].map((world) =>
let canvasCoordinates = [lineStartWorld, lineEndWorld].map((world) =>
targetViewport.worldToCanvas(world)
);

if (this.configuration.showFullDimension) {
canvasCoordinates = this.handleFullDimension(
targetViewport,
lineStartWorld,
viewPlaneNormal,
viewUp,
lineEndWorld,
canvasCoordinates
);
}

const dataId = `${annotationUID}-line`;
const lineUID = '1';
drawLineSvg(
Expand Down Expand Up @@ -270,9 +281,126 @@ class ReferenceLines extends AnnotationDisplayTool {
return Math.abs(dot) < EPSILON;
};

private handleFullDimension(
targetViewport: Types.IStackViewport | Types.IVolumeViewport,
lineStartWorld: Types.Point3,
viewPlaneNormal: Types.Point3,
viewUp: Types.Point3,
lineEndWorld: Types.Point3,
canvasCoordinates: Types.Point2[]
) {
const renderingEngine = targetViewport.getRenderingEngine();
const targetId = this.getTargetId(targetViewport);
const targetImage = this.getTargetIdImage(targetId, renderingEngine);

const referencedImageId = this.getReferencedImageId(
targetViewport,
lineStartWorld,
viewPlaneNormal,
viewUp
);

if (referencedImageId && targetImage) {
try {
const { imageData, dimensions } = targetImage;

// Calculate bound image coordinates
const [
topLeftImageCoord,
topRightImageCoord,
bottomRightImageCoord,
bottomLeftImageCoord,
] = [
imageData.indexToWorld([0, 0, 0]) as Types.Point3,
imageData.indexToWorld([dimensions[0] - 1, 0, 0]) as Types.Point3,
imageData.indexToWorld([
dimensions[0] - 1,
dimensions[1] - 1,
0,
]) as Types.Point3,
imageData.indexToWorld([0, dimensions[1] - 1, 0]) as Types.Point3,
].map((world) => csUtils.worldToImageCoords(referencedImageId, world));

// Calculate line start and end image coordinates
const [lineStartImageCoord, lineEndImageCoord] = [
lineStartWorld,
lineEndWorld,
].map((world) => csUtils.worldToImageCoords(referencedImageId, world));

// Calculate intersection points between line and image bounds
canvasCoordinates = [
[topLeftImageCoord, topRightImageCoord],
[topRightImageCoord, bottomRightImageCoord],
[bottomLeftImageCoord, bottomRightImageCoord],
[topLeftImageCoord, bottomLeftImageCoord],
]
.map(([start, end]) =>
this.intersectInfiniteLines(
start,
end,
lineStartImageCoord,
lineEndImageCoord
)
)
.filter((point) => point && this.isInBound(point, dimensions))
.map((point) => {
const world = csUtils.imageToWorldCoords(
referencedImageId,
point as Types.Point2
);
return targetViewport.worldToCanvas(world);
});
} catch (err) {
console.log(err);
}
}
return canvasCoordinates;
}

// get the intersection point between two infinite lines, not line segments
intersectInfiniteLines(
line1Start: Types.Point2,
line1End: Types.Point2,
line2Start: Types.Point2,
line2End: Types.Point2
) {
const [x1, y1] = line1Start;
const [x2, y2] = line1End;
const [x3, y3] = line2Start;
const [x4, y4] = line2End;

// Compute a1, b1, c1, where line joining points 1 and 2 is "a1 x + b1 y + c1 = 0"
const a1 = y2 - y1;
const b1 = x1 - x2;
const c1 = x2 * y1 - x1 * y2;

// Compute a2, b2, c2
const a2 = y4 - y3;
const b2 = x3 - x4;
const c2 = x4 * y3 - x3 * y4;

if (Math.abs(a1 * b2 - a2 * b1) < EPSILON) {
return;
}

const x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
const y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);

return [x, y];
}

isParallel(vec1: Types.Point3, vec2: Types.Point3): boolean {
return Math.abs(vec3.dot(vec1, vec2)) > 1 - EPSILON;
}

isInBound(point: number[], dimensions: Types.Point3): boolean {
return (
point[0] >= 0 &&
point[0] <= dimensions[0] &&
point[1] >= 0 &&
point[1] <= dimensions[1]
);
}
}

ReferenceLines.toolName = 'ReferenceLines';
Expand Down
4 changes: 4 additions & 0 deletions packages/tools/src/tools/base/AnnotationDisplayTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ abstract class AnnotationDisplayTool extends BaseTool {

// for this specific tool
toolSpecificAnnotations.forEach((annotation) => {
if (!annotation.metadata?.referencedImageId) {
return;
}

// if the annotation is drawn on the same imageId
const referencedImageURI = utilities.imageIdToURI(
annotation.metadata.referencedImageId
Expand Down

0 comments on commit f9a498a

Please sign in to comment.