Skip to content

Commit

Permalink
feat(CobbAngle): Add CobbAngle tool (#353)
Browse files Browse the repository at this point in the history
* fix: Fix the build and usage of the adapters

* feat: Add Cobb Angle tool
  • Loading branch information
wayfarer3130 authored Jan 30, 2023
1 parent 378cd7f commit b9bd701
Show file tree
Hide file tree
Showing 11 changed files with 1,195 additions and 219 deletions.
56 changes: 56 additions & 0 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,62 @@ function clip(a: any, b: any, box: any, da?: any, db?: any): 1 | 0;
// @public (undocumented)
function clip_2(val: number, low: number, high: number): number;

// @public (undocumented)
export class CobbAngleTool extends AnnotationTool {
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
// (undocumented)
_activateDraw: (element: HTMLDivElement) => void;
// (undocumented)
_activateModify: (element: HTMLDivElement) => void;
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => AngleAnnotation;
// (undocumented)
angleStartedNotYetCompleted: boolean;
// (undocumented)
_calculateCachedStats(annotation: any, renderingEngine: any, enabledElement: any): any;
// (undocumented)
cancel: (element: HTMLDivElement) => any;
// (undocumented)
_deactivateDraw: (element: HTMLDivElement) => void;
// (undocumented)
_deactivateModify: (element: HTMLDivElement) => void;
// (undocumented)
editData: {
annotation: any;
viewportIdsToRender: string[];
handleIndex?: number;
movingTextBox?: boolean;
newAnnotation?: boolean;
hasMoved?: boolean;
} | null;
// (undocumented)
_getTextLines(data: any, targetId: any): string[];
// (undocumented)
handleSelectedCallback(evt: EventTypes_2.MouseDownEventType, annotation: AngleAnnotation, handle: ToolHandle, interactionType?: string): void;
// (undocumented)
isDrawing: boolean;
// (undocumented)
isHandleOutsideImage: boolean;
// (undocumented)
isPointNearTool: (element: HTMLDivElement, annotation: AngleAnnotation, canvasCoords: Types_2.Point2, proximity: number) => boolean;
// (undocumented)
mouseDragCallback: any;
// (undocumented)
_mouseDragCallback: (evt: EventTypes_2.MouseDragEventType | EventTypes_2.MouseMoveEventType) => void;
// (undocumented)
_mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void;
// (undocumented)
renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
// (undocumented)
_throttledCalculateCachedStats: any;
// (undocumented)
static toolName: any;
// (undocumented)
toolSelectedCallback: (evt: EventTypes_2.MouseDownEventType, annotation: AngleAnnotation, interactionType: InteractionTypes) => void;
// (undocumented)
touchDragCallback: any;
}

// @public (undocumented)
type Color = [number, number, number, number];

Expand Down
27 changes: 20 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@
"@babel/preset-typescript": "^7.16.7",
"@babel/runtime": "^7.16.7",
"@cornerstonejs/calculate-suv": "1.0.2",
"@microsoft/api-extractor": "7.19.5",
"@microsoft/api-extractor": "7.21.3",
"@types/node": "^14.18.9",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"acorn": "^7.1.0",
"acorn-jsx": "^5.2.0",
"autoprefixer": "^10.4.2",
"babel-loader": "8.2.3",
"babel-plugin-istanbul": "^6.1.1",
Expand All @@ -60,18 +62,20 @@
"cross-env": "^7.0.3",
"css-loader": "^5.2.7",
"cssnano": "^4.1.11",
"eslint": "7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint": "^8.17.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "6.x",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-tsdoc": "^0.2.14",
"eslint-webpack-plugin": "^2.6.0",
"file-loader": "^6.2.0",
"follow-redirects": "^1.10.0",
"html-webpack-plugin": "^5.5.0",
"husky": "^4.3.8",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine": "^4.0.2",
"jest": "^27.5.1",
"karma": "^6.3.12",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.1.0",
Expand All @@ -88,9 +92,16 @@
"postcss-import": "^14.0.2",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.4.1",
"prettier": "^2.5.1",
"prettier": "^2.8.3",
"prop-types": "^15.8.1",
"puppeteer": "^13.5.0",
"rollup": "^1.31.1",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.2.4",
"shader-loader": "^1.3.1",
"shelljs": "^0.8.5",
"sinon": "^10.0.0",
Expand All @@ -100,13 +111,15 @@
"ts-loader": "^9.2.6",
"typedoc": "^0.22.13",
"typescript": "4.6.4",
"unzipper": "^0.10.9",
"url-loader": "^4.1.1",
"webpack": "5.67.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^3.11.3",
"webpack-merge": "5.8.0",
"worker-loader": "^3.0.8"
"worker-loader": "^3.0.8",
"xml2js": "^0.4.23"
},
"husky": {
"hooks": {
Expand Down
125 changes: 125 additions & 0 deletions packages/adapters/src/adapters/Cornerstone3D/CobbAngle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { utilities } from "dcmjs";
import CORNERSTONE_3D_TAG from "./cornerstone3DTag";
import MeasurementReport from "./MeasurementReport";

const { CobbAngle: TID300CobbAngle } = utilities.TID300;

const MEASUREMENT_TYPE = "CobbAngle";
const trackingIdentifierTextValue = `${CORNERSTONE_3D_TAG}:${MEASUREMENT_TYPE}`;

class CobbAngle {
// TODO: this function is required for all Cornerstone Tool Adapters, since it is called by MeasurementReport.
static getMeasurementData(
MeasurementGroup,
sopInstanceUIDToImageIdMap,
imageToWorldCoords,
metadata
) {
const { defaultState, NUMGroup, SCOORDGroup, ReferencedFrameNumber } =
MeasurementReport.getSetupMeasurementData(
MeasurementGroup,
sopInstanceUIDToImageIdMap,
metadata,
CobbAngle.toolType
);

const referencedImageId =
defaultState.annotation.metadata.referencedImageId;

const { GraphicData } = SCOORDGroup;
const worldCoords = [];
for (let i = 0; i < GraphicData.length; i += 2) {
const point = imageToWorldCoords(referencedImageId, [
GraphicData[i],
GraphicData[i + 1]
]);
worldCoords.push(point);
}

const state = defaultState;

state.annotation.data = {
handles: {
points: [
worldCoords[0],
worldCoords[1],
worldCoords[2],
worldCoords[3]
],
activeHandleIndex: 0,
textBox: {
hasMoved: false
}
},
cachedStats: {
[`imageId:${referencedImageId}`]: {
angle: NUMGroup
? NUMGroup.MeasuredValueSequence.NumericValue
: null
}
},
frameNumber: ReferencedFrameNumber
};

return state;
}

static getTID300RepresentationArguments(tool, worldToImageCoords) {
const { data, finding, findingSites, metadata } = tool;
const { cachedStats = {}, handles } = data;

const { referencedImageId } = metadata;

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

const start1 = worldToImageCoords(referencedImageId, handles.points[0]);
const end1 = worldToImageCoords(referencedImageId, handles.points[1]);

const start2 = worldToImageCoords(referencedImageId, handles.points[2]);
const end2 = worldToImageCoords(referencedImageId, handles.points[3]);

const point1 = { x: start1[0], y: start1[1] };
const point2 = { x: end1[0], y: end1[1] };
const point3 = { x: start2[0], y: start2[1] };
const point4 = { x: end2[0], y: end2[1] };

const { angle } = cachedStats[`imageId:${referencedImageId}`] || {};

return {
point1,
point2,
point3,
point4,
rAngle: angle,
trackingIdentifierTextValue,
finding,
findingSites: findingSites || []
};
}
}

CobbAngle.toolType = MEASUREMENT_TYPE;
CobbAngle.utilityToolType = MEASUREMENT_TYPE;
console.log("TID300CobbAngle=", TID300CobbAngle);
CobbAngle.TID300Representation = TID300CobbAngle;
CobbAngle.isValidCornerstoneTrackingIdentifier = TrackingIdentifier => {
if (!TrackingIdentifier.includes(":")) {
return false;
}

const [cornerstone3DTag, toolType] = TrackingIdentifier.split(":");

if (cornerstone3DTag !== CORNERSTONE_3D_TAG) {
return false;
}

return toolType === MEASUREMENT_TYPE;
};

MeasurementReport.registerTool(CobbAngle);

export default CobbAngle;
2 changes: 2 additions & 0 deletions packages/adapters/src/adapters/Cornerstone3D/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import CORNERSTONE_3D_TAG from "./cornerstone3DTag";

import ArrowAnnotate from "./ArrowAnnotate";
import Bidirectional from "./Bidirectional";
import CobbAngle from "./CobbAngle";
import EllipticalROI from "./EllipticalROI";
import Length from "./Length";
import PlanarFreehandROI from "./PlanarFreehandROI";
import Probe from "./Probe";

const Cornerstone3D = {
Bidirectional,
CobbAngle,
Length,
EllipticalROI,
ArrowAnnotate,
Expand Down
5 changes: 5 additions & 0 deletions packages/tools/examples/stackAnnotationTools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
EllipticalROITool,
BidirectionalTool,
AngleTool,
CobbAngleTool,
ToolGroupManager,
ArrowAnnotateTool,
Enums: csToolsEnums,
Expand Down Expand Up @@ -60,6 +61,7 @@ const toolsNames = [
EllipticalROITool.toolName,
BidirectionalTool.toolName,
AngleTool.toolName,
CobbAngleTool.toolName,
ArrowAnnotateTool.toolName,
];
let selectedToolName = toolsNames[0];
Expand Down Expand Up @@ -100,6 +102,7 @@ async function run() {
cornerstoneTools.addTool(EllipticalROITool);
cornerstoneTools.addTool(BidirectionalTool);
cornerstoneTools.addTool(AngleTool);
cornerstoneTools.addTool(CobbAngleTool);
cornerstoneTools.addTool(ArrowAnnotateTool);

// Define a tool group, which defines how mouse events map to tool commands for
Expand All @@ -113,6 +116,7 @@ async function run() {
toolGroup.addTool(EllipticalROITool.toolName);
toolGroup.addTool(BidirectionalTool.toolName);
toolGroup.addTool(AngleTool.toolName);
toolGroup.addTool(CobbAngleTool.toolName);
toolGroup.addTool(ArrowAnnotateTool.toolName);

// Set the initial state of the tools, here we set one tool active on left click.
Expand All @@ -131,6 +135,7 @@ async function run() {
toolGroup.setToolPassive(EllipticalROITool.toolName);
toolGroup.setToolPassive(BidirectionalTool.toolName);
toolGroup.setToolPassive(AngleTool.toolName);
toolGroup.setToolPassive(CobbAngleTool.toolName);
toolGroup.setToolPassive(ArrowAnnotateTool.toolName);

// Get Cornerstone imageIds and fetch metadata into RAM
Expand Down
5 changes: 5 additions & 0 deletions packages/tools/examples/stackToVolumeWithAnnotations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const {
EllipticalROITool,
BidirectionalTool,
AngleTool,
CobbAngleTool,
ToolGroupManager,
ArrowAnnotateTool,
StackScrollMouseWheelTool,
Expand Down Expand Up @@ -71,6 +72,7 @@ const toolsNames = [
EllipticalROITool.toolName,
BidirectionalTool.toolName,
AngleTool.toolName,
CobbAngleTool.toolName,
ArrowAnnotateTool.toolName,
];
let selectedToolName = toolsNames[0];
Expand Down Expand Up @@ -139,6 +141,7 @@ async function run() {
cornerstoneTools.addTool(EllipticalROITool);
cornerstoneTools.addTool(BidirectionalTool);
cornerstoneTools.addTool(AngleTool);
cornerstoneTools.addTool(CobbAngleTool);
cornerstoneTools.addTool(ArrowAnnotateTool);
cornerstoneTools.addTool(StackScrollMouseWheelTool);

Expand All @@ -153,6 +156,7 @@ async function run() {
toolGroup.addTool(EllipticalROITool.toolName);
toolGroup.addTool(BidirectionalTool.toolName);
toolGroup.addTool(AngleTool.toolName);
toolGroup.addTool(CobbAngleTool.toolName);
toolGroup.addTool(ArrowAnnotateTool.toolName);
toolGroup.addTool(StackScrollMouseWheelTool.toolName);

Expand All @@ -173,6 +177,7 @@ async function run() {
toolGroup.setToolPassive(EllipticalROITool.toolName);
toolGroup.setToolPassive(BidirectionalTool.toolName);
toolGroup.setToolPassive(AngleTool.toolName);
toolGroup.setToolPassive(CobbAngleTool.toolName);
toolGroup.setToolPassive(ArrowAnnotateTool.toolName);

// Get Cornerstone imageIds and fetch metadata into RAM
Expand Down
2 changes: 2 additions & 0 deletions packages/tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
SegmentationDisplayTool,
BrushTool,
AngleTool,
CobbAngleTool,
MagnifyTool,
ReferenceCursors,
ReferenceLines,
Expand Down Expand Up @@ -88,6 +89,7 @@ export {
PlanarFreehandROITool,
ArrowAnnotateTool,
AngleTool,
CobbAngleTool,
MagnifyTool,
ReferenceCursors,
ReferenceLines,
Expand Down
Loading

0 comments on commit b9bd701

Please sign in to comment.