diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json
index 923385eda..76e8fe82b 100644
--- a/extensions/cornerstone-dicom-sr/package.json
+++ b/extensions/cornerstone-dicom-sr/package.json
@@ -36,7 +36,7 @@
"@ohif/extension-cornerstone": "^3.0.0",
"@ohif/extension-measurement-tracking": "^3.0.0",
"@ohif/ui": "^2.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/extensions/cornerstone-dicom-sr/src/init.ts b/extensions/cornerstone-dicom-sr/src/init.ts
index ec24b5c48..84cbcaf37 100644
--- a/extensions/cornerstone-dicom-sr/src/init.ts
+++ b/extensions/cornerstone-dicom-sr/src/init.ts
@@ -6,6 +6,7 @@ import {
BidirectionalTool,
CobbAngleTool,
EllipticalROITool,
+ CircleROITool,
LengthTool,
PlanarFreehandROITool,
} from '@cornerstonejs/tools';
@@ -24,6 +25,7 @@ export default function init({
addToolInstance(toolNames.SRLength, LengthTool, {});
addToolInstance(toolNames.SRBidirectional, BidirectionalTool);
addToolInstance(toolNames.SREllipticalROI, EllipticalROITool);
+ addToolInstance(toolNames.SRCircleROI, CircleROITool);
addToolInstance(toolNames.SRArrowAnnotate, ArrowAnnotateTool);
addToolInstance(toolNames.SRAngle, AngleTool);
// TODO - fix the SR display of Cobb Angle, as it joins the two lines
@@ -40,6 +42,7 @@ export default function init({
SRLength: dashedLine,
SRBidirectional: dashedLine,
SREllipticalROI: dashedLine,
+ SRCircleROI: dashedLine,
SRArrowAnnotate: dashedLine,
SRCobbAngle: dashedLine,
SRAngle: dashedLine,
diff --git a/extensions/cornerstone-dicom-sr/src/tools/toolNames.ts b/extensions/cornerstone-dicom-sr/src/tools/toolNames.ts
index 48375f4cb..2e52ec111 100644
--- a/extensions/cornerstone-dicom-sr/src/tools/toolNames.ts
+++ b/extensions/cornerstone-dicom-sr/src/tools/toolNames.ts
@@ -5,6 +5,7 @@ const toolNames = {
SRLength: 'SRLength',
SRBidirectional: 'SRBidirectional',
SREllipticalROI: 'SREllipticalROI',
+ SRCircleROI: 'SRCircleROI',
SRArrowAnnotate: 'SRArrowAnnotate',
SRAngle: 'SRAngle',
SRCobbAngle: 'SRCobbAngle',
diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json
index 2eab62700..cae1befd0 100644
--- a/extensions/cornerstone/package.json
+++ b/extensions/cornerstone/package.json
@@ -30,7 +30,7 @@
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
"cornerstone-wado-image-loader": "^4.13.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/extensions/cornerstone/src/initCornerstoneTools.js b/extensions/cornerstone/src/initCornerstoneTools.js
index 2d305af8a..5df8f8983 100644
--- a/extensions/cornerstone/src/initCornerstoneTools.js
+++ b/extensions/cornerstone/src/initCornerstoneTools.js
@@ -9,6 +9,7 @@ import {
LengthTool,
RectangleROITool,
EllipticalROITool,
+ CircleROITool,
BidirectionalTool,
ArrowAnnotateTool,
DragProbeTool,
@@ -41,6 +42,7 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(LengthTool);
addTool(RectangleROITool);
addTool(EllipticalROITool);
+ addTool(CircleROITool);
addTool(BidirectionalTool);
addTool(ArrowAnnotateTool);
addTool(DragProbeTool);
@@ -83,6 +85,7 @@ const toolNames = {
Probe: ProbeTool.toolName,
RectangleROI: RectangleROITool.toolName,
EllipticalROI: EllipticalROITool.toolName,
+ CircleROI: CircleROITool.toolName,
Bidirectional: BidirectionalTool.toolName,
Angle: AngleTool.toolName,
CobbAngle: CobbAngleTool.toolName,
diff --git a/extensions/cornerstone/src/initMeasurementService.js b/extensions/cornerstone/src/initMeasurementService.js
index 36b7229d2..c11a53111 100644
--- a/extensions/cornerstone/src/initMeasurementService.js
+++ b/extensions/cornerstone/src/initMeasurementService.js
@@ -24,6 +24,7 @@ const initMeasurementService = (
Length,
Bidirectional,
EllipticalROI,
+ CircleROI,
ArrowAnnotate,
Angle,
CobbAngle,
@@ -78,6 +79,14 @@ const initMeasurementService = (
EllipticalROI.toMeasurement
);
+ measurementService.addMapping(
+ csTools3DVer1MeasurementSource,
+ 'CircleROI',
+ CircleROI.matchingCriteria,
+ CircleROI.toAnnotation,
+ CircleROI.toMeasurement
+ );
+
measurementService.addMapping(
csTools3DVer1MeasurementSource,
'ArrowAnnotate',
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/ArrowAnnotate.js b/extensions/cornerstone/src/utils/measurementServiceMappings/ArrowAnnotate.ts
similarity index 100%
rename from extensions/cornerstone/src/utils/measurementServiceMappings/ArrowAnnotate.js
rename to extensions/cornerstone/src/utils/measurementServiceMappings/ArrowAnnotate.ts
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/Bidirectional.js b/extensions/cornerstone/src/utils/measurementServiceMappings/Bidirectional.ts
similarity index 100%
rename from extensions/cornerstone/src/utils/measurementServiceMappings/Bidirectional.js
rename to extensions/cornerstone/src/utils/measurementServiceMappings/Bidirectional.ts
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts
new file mode 100644
index 000000000..c55d7da4b
--- /dev/null
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/CircleROI.ts
@@ -0,0 +1,228 @@
+import SUPPORTED_TOOLS from './constants/supportedTools';
+import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
+import getModalityUnit from './utils/getModalityUnit';
+import { utils } from '@ohif/core';
+
+const CircleROI = {
+ toAnnotation: measurement => {},
+ toMeasurement: (
+ csToolsEventDetail,
+ DisplaySetService,
+ CornerstoneViewportService,
+ getValueTypeFromToolType
+ ) => {
+ const { annotation, viewportId } = csToolsEventDetail;
+ const { metadata, data, annotationUID } = annotation;
+
+ if (!metadata || !data) {
+ console.warn('Length tool: Missing metadata or data');
+ return null;
+ }
+
+ const { toolName, referencedImageId, FrameOfReferenceUID } = metadata;
+ const validToolType = SUPPORTED_TOOLS.includes(toolName);
+
+ if (!validToolType) {
+ throw new Error('Tool not supported');
+ }
+
+ const {
+ SOPInstanceUID,
+ SeriesInstanceUID,
+ StudyInstanceUID,
+ } = getSOPInstanceAttributes(
+ referencedImageId,
+ CornerstoneViewportService,
+ viewportId
+ );
+
+ let displaySet;
+
+ if (SOPInstanceUID) {
+ displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
+ SOPInstanceUID,
+ SeriesInstanceUID
+ );
+ } else {
+ displaySet = DisplaySetService.getDisplaySetsForSeries(SeriesInstanceUID);
+ }
+
+ const { points } = data.handles;
+
+ const mappedAnnotations = getMappedAnnotations(
+ annotation,
+ DisplaySetService
+ );
+
+ const displayText = getDisplayText(mappedAnnotations, displaySet);
+ const getReport = () =>
+ _getReport(mappedAnnotations, points, FrameOfReferenceUID);
+
+ return {
+ uid: annotationUID,
+ SOPInstanceUID,
+ FrameOfReferenceUID,
+ points,
+ metadata,
+ referenceSeriesUID: SeriesInstanceUID,
+ referenceStudyUID: StudyInstanceUID,
+ frameNumber: mappedAnnotations[0]?.frameNumber || 1,
+ toolName: metadata.toolName,
+ displaySetInstanceUID: displaySet.displaySetInstanceUID,
+ label: data.label,
+ displayText: displayText,
+ data: data.cachedStats,
+ type: getValueTypeFromToolType(toolName),
+ getReport,
+ };
+ },
+};
+
+function getMappedAnnotations(annotation, DisplaySetService) {
+ const { metadata, data } = annotation;
+ const { cachedStats } = data;
+ const { referencedImageId } = metadata;
+ const targets = Object.keys(cachedStats);
+
+ if (!targets.length) {
+ return [];
+ }
+
+ const annotations = [];
+ Object.keys(cachedStats).forEach(targetId => {
+ const targetStats = cachedStats[targetId];
+
+ if (!referencedImageId) {
+ // Todo: Non-acquisition plane measurement mapping not supported yet
+ throw new Error(
+ 'Non-acquisition plane measurement mapping not supported'
+ );
+ }
+
+ const {
+ SOPInstanceUID,
+ SeriesInstanceUID,
+ frameNumber,
+ } = getSOPInstanceAttributes(referencedImageId);
+
+ const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
+ SOPInstanceUID,
+ SeriesInstanceUID,
+ frameNumber
+ );
+
+ const { SeriesNumber } = displaySet;
+ const { mean, stdDev, max, area, Modality } = targetStats;
+ const unit = getModalityUnit(Modality);
+
+ annotations.push({
+ SeriesInstanceUID,
+ SOPInstanceUID,
+ SeriesNumber,
+ frameNumber,
+ Modality,
+ unit,
+ mean,
+ stdDev,
+ max,
+ area,
+ });
+ });
+
+ return annotations;
+}
+
+/*
+This function is used to convert the measurement data to a format that is
+suitable for the report generation (e.g. for the csv report). The report
+returns a list of columns and corresponding values.
+*/
+function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
+ const columns = [];
+ const values = [];
+
+ // Add Type
+ columns.push('AnnotationType');
+ values.push('Cornerstone:CircleROI');
+
+ mappedAnnotations.forEach(annotation => {
+ const { mean, stdDev, max, area, unit } = annotation;
+
+ if (!mean || !unit || !max || !area) {
+ return;
+ }
+
+ columns.push(
+ `max (${unit})`,
+ `mean (${unit})`,
+ `std (${unit})`,
+ `area (mm2)`
+ );
+ values.push(max, mean, stdDev, area);
+ });
+
+ if (FrameOfReferenceUID) {
+ columns.push('FrameOfReferenceUID');
+ values.push(FrameOfReferenceUID);
+ }
+
+ if (points) {
+ columns.push('points');
+ // points has the form of [[x1, y1, z1], [x2, y2, z2], ...]
+ // convert it to string of [[x1 y1 z1];[x2 y2 z2];...]
+ // so that it can be used in the csv report
+ values.push(points.map(p => p.join(' ')).join(';'));
+ }
+
+ return {
+ columns,
+ values,
+ };
+}
+
+function getDisplayText(mappedAnnotations, displaySet) {
+ if (!mappedAnnotations || !mappedAnnotations.length) {
+ return '';
+ }
+
+ const displayText = [];
+
+ // Area is the same for all series
+ const { area, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
+
+ const instance = displaySet.images.find(
+ image => image.SOPInstanceUID === SOPInstanceUID
+ );
+
+ let InstanceNumber;
+ if (instance) {
+ InstanceNumber = instance.InstanceNumber;
+ }
+
+ const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : '';
+ const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : '';
+
+ // Area sometimes becomes undefined if `preventHandleOutsideImage` is off.
+ const roundedArea = utils.roundNumber(area || 0, 2);
+ displayText.push(`${roundedArea} mm2`);
+
+ // Todo: we need a better UI for displaying all these information
+ mappedAnnotations.forEach(mappedAnnotation => {
+ const { unit, max, SeriesNumber } = mappedAnnotation;
+
+ let maxStr = '';
+ if (max) {
+ const roundedMax = utils.roundNumber(max, 2);
+ maxStr = `Max: ${roundedMax} ${unit} `;
+ }
+
+ const str = `${maxStr}(S:${SeriesNumber}${instanceText}${frameText})`;
+ if (!displayText.includes(str)) {
+ displayText.push(str);
+ }
+ });
+
+ return displayText;
+}
+
+export default CircleROI;
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.js b/extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts
similarity index 100%
rename from extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.js
rename to extensions/cornerstone/src/utils/measurementServiceMappings/EllipticalROI.ts
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/Length.js b/extensions/cornerstone/src/utils/measurementServiceMappings/Length.ts
similarity index 90%
rename from extensions/cornerstone/src/utils/measurementServiceMappings/Length.js
rename to extensions/cornerstone/src/utils/measurementServiceMappings/Length.ts
index 206208257..8dad5a1c1 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/Length.js
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/Length.ts
@@ -1,6 +1,6 @@
import SUPPORTED_TOOLS from './constants/supportedTools';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
-import { displaySetService, utils } from '@ohif/core';
+import { utils } from '@ohif/core';
const Length = {
toAnnotation: measurement => {},
@@ -32,15 +32,12 @@ const Length = {
throw new Error('Tool not supported');
}
- const {
- SOPInstanceUID,
- SeriesInstanceUID,
- StudyInstanceUID,
- } = getSOPInstanceAttributes(
- referencedImageId,
- cornerstoneViewportService,
- viewportId
- );
+ const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } =
+ getSOPInstanceAttributes(
+ referencedImageId,
+ cornerstoneViewportService,
+ viewportId
+ );
let displaySet;
@@ -104,11 +101,8 @@ function getMappedAnnotations(annotation, displaySetService) {
);
}
- const {
- SOPInstanceUID,
- SeriesInstanceUID,
- frameNumber,
- } = getSOPInstanceAttributes(referencedImageId);
+ const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
+ getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -179,12 +173,8 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
- const {
- length,
- SeriesNumber,
- SOPInstanceUID,
- frameNumber,
- } = mappedAnnotations[0];
+ const { length, SeriesNumber, SOPInstanceUID, frameNumber } =
+ mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
index 7560dc137..01f1178b9 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/RectangleROI.ts
@@ -4,7 +4,7 @@ import getModalityUnit from './utils/getModalityUnit';
import { utils } from '@ohif/core';
const RectangleROI = {
- toAnnotation: measurement => { },
+ toAnnotation: measurement => {},
toMeasurement: (
csToolsEventDetail,
DisplaySetService,
@@ -26,15 +26,12 @@ const RectangleROI = {
throw new Error('Tool not supported');
}
- const {
- SOPInstanceUID,
- SeriesInstanceUID,
- StudyInstanceUID,
- } = getSOPInstanceAttributes(
- referencedImageId,
- CornerstoneViewportService,
- viewportId
- );
+ const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } =
+ getSOPInstanceAttributes(
+ referencedImageId,
+ CornerstoneViewportService,
+ viewportId
+ );
let displaySet;
@@ -99,11 +96,8 @@ function getMappedAnnotations(annotation, DisplaySetService) {
);
}
- const {
- SOPInstanceUID,
- SeriesInstanceUID,
- frameNumber,
- } = getSOPInstanceAttributes(referencedImageId);
+ const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
+ getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -143,7 +137,7 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
// Add Type
columns.push('AnnotationType');
- values.push('Cornerstone:EllipticalROI');
+ values.push('Cornerstone:RectangleROI');
mappedAnnotations.forEach(annotation => {
const { mean, stdDev, max, area, unit } = annotation;
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js b/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js
index 00be9ae14..e1e8a1755 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js
@@ -1,6 +1,7 @@
export default [
'Length',
'EllipticalROI',
+ 'CircleROI',
'Bidirectional',
'ArrowAnnotate',
'Angle',
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts
index 4d5c77f17..2a4562e7d 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts
@@ -2,6 +2,7 @@ import { MeasurementService } from '@ohif/core';
import Length from './Length';
import Bidirectional from './Bidirectional';
import EllipticalROI from './EllipticalROI';
+import CircleROI from './CircleROI';
import ArrowAnnotate from './ArrowAnnotate';
import CobbAngle from './CobbAngle';
import Angle from './Angle';
@@ -25,6 +26,7 @@ const measurementServiceMappingsFactory = (
const {
POLYLINE,
ELLIPSE,
+ CIRCLE,
RECTANGLE,
BIDIRECTIONAL,
POINT,
@@ -37,6 +39,7 @@ const measurementServiceMappingsFactory = (
const TOOL_TYPE_TO_VALUE_TYPE = {
Length: POLYLINE,
EllipticalROI: ELLIPSE,
+ CircleROI: CIRCLE,
RectangleROI: RECTANGLE,
PlanarFreehandROI: POLYLINE,
Bidirectional: BIDIRECTIONAL,
@@ -104,6 +107,22 @@ const measurementServiceMappingsFactory = (
],
},
+ CircleROI: {
+ toAnnotation: CircleROI.toAnnotation,
+ toMeasurement: csToolsAnnotation =>
+ CircleROI.toMeasurement(
+ csToolsAnnotation,
+ displaySetService,
+ cornerstoneViewportService,
+ _getValueTypeFromToolType
+ ),
+ matchingCriteria: [
+ {
+ valueType: MeasurementService.VALUE_TYPES.CIRCLE,
+ },
+ ],
+ },
+
RectangleROI: {
toAnnotation: RectangleROI.toAnnotation,
toMeasurement: csToolsAnnotation =>
diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
index b93226bb1..c0707dd4f 100644
--- a/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
+++ b/extensions/cornerstone/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
@@ -13,8 +13,8 @@ import * as cornerstone from '@cornerstonejs/core';
*/
export default function getSOPInstanceAttributes(
imageId,
- cornerstoneViewportService,
- viewportId
+ cornerstoneViewportService = undefined,
+ viewportId = undefined
) {
if (imageId) {
return _getUIDFromImageID(imageId);
diff --git a/extensions/default/package.json b/extensions/default/package.json
index 0ca309f62..81ca66393 100644
--- a/extensions/default/package.json
+++ b/extensions/default/package.json
@@ -32,7 +32,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/i18n": "^1.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicomweb-client": "^0.8.4",
"prop-types": "^15.6.2",
"react": "^17.0.2",
diff --git a/extensions/dicom-pdf/package.json b/extensions/dicom-pdf/package.json
index 85684879c..1de3bce06 100644
--- a/extensions/dicom-pdf/package.json
+++ b/extensions/dicom-pdf/package.json
@@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/extensions/dicom-video/package.json b/extensions/dicom-video/package.json
index 83f4e060b..6447fa568 100644
--- a/extensions/dicom-video/package.json
+++ b/extensions/dicom-video/package.json
@@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json
index 332d84253..59ab9e3b9 100644
--- a/extensions/measurement-tracking/package.json
+++ b/extensions/measurement-tracking/package.json
@@ -35,7 +35,7 @@
"@cornerstonejs/core": "^0.40.0",
"@cornerstonejs/tools": "^0.60.1",
"@ohif/extension-cornerstone-dicom-sr": "^3.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"lodash.debounce": "^4.17.21",
"prop-types": "^15.6.2",
"react": "^17.0.2",
diff --git a/extensions/tmtv/package.json b/extensions/tmtv/package.json
index 9210d7cfa..89d25ba3b 100644
--- a/extensions/tmtv/package.json
+++ b/extensions/tmtv/package.json
@@ -30,7 +30,7 @@
"peerDependencies": {
"@ohif/core": "^3.0.0",
"@ohif/ui": "^2.0.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
diff --git a/modes/basic-dev-mode/src/index.js b/modes/basic-dev-mode/src/index.js
index d74ee60a4..229feb643 100644
--- a/modes/basic-dev-mode/src/index.js
+++ b/modes/basic-dev-mode/src/index.js
@@ -81,6 +81,7 @@ function modeFactory({ modeConfiguration }) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.Probe },
{ toolName: toolNames.EllipticalROI },
+ { toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.CalibrationLine },
@@ -134,11 +135,8 @@ function modeFactory({ modeConfiguration }) {
]);
},
onModeExit: ({ servicesManager }) => {
- const {
- toolGroupService,
- measurementService,
- toolbarService,
- } = servicesManager.services;
+ const { toolGroupService, measurementService, toolbarService } =
+ servicesManager.services;
toolGroupService.destroy();
},
diff --git a/modes/basic-dev-mode/src/toolbarButtons.js b/modes/basic-dev-mode/src/toolbarButtons.js
index 4a08edbf0..995e4dea6 100644
--- a/modes/basic-dev-mode/src/toolbarButtons.js
+++ b/modes/basic-dev-mode/src/toolbarButtons.js
@@ -130,6 +130,21 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
+ _createToolButton(
+ 'CircleROI',
+ 'tool-circle',
+ 'Circle',
+ [
+ {
+ commandName: 'setToolActive',
+ commandOptions: {
+ toolName: 'CircleROI',
+ },
+ context: 'CORNERSTONE',
+ },
+ ],
+ 'Circle Tool'
+ ),
],
},
},
diff --git a/modes/basic-test-mode/src/initToolGroups.js b/modes/basic-test-mode/src/initToolGroups.js
index 105b1a2f8..ccc5c1a6d 100644
--- a/modes/basic-test-mode/src/initToolGroups.js
+++ b/modes/basic-test-mode/src/initToolGroups.js
@@ -32,6 +32,7 @@ function initDefaultToolGroup(
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
+ { toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
@@ -110,6 +111,7 @@ function initSRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: SRToolNames.SRArrowAnnotate },
{ toolName: SRToolNames.SRBidirectional },
{ toolName: SRToolNames.SREllipticalROI },
+ { toolName: SRToolNames.SRCircleROI },
],
enabled: [
{
@@ -170,6 +172,7 @@ function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
+ { toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
diff --git a/modes/basic-test-mode/src/toolbarButtons.js b/modes/basic-test-mode/src/toolbarButtons.js
index 9a04581c5..2d0492f6d 100644
--- a/modes/basic-test-mode/src/toolbarButtons.js
+++ b/modes/basic-test-mode/src/toolbarButtons.js
@@ -200,6 +200,29 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
+ _createToolButton(
+ 'CircleROI',
+ 'tool-circle',
+ 'Circle',
+ [
+ {
+ commandName: 'setToolActive',
+ commandOptions: {
+ toolName: 'CircleROI',
+ },
+ context: 'CORNERSTONE',
+ },
+ {
+ commandName: 'setToolActive',
+ commandOptions: {
+ toolName: 'SRCircleROI',
+ toolGroupId: 'SRToolGroup',
+ },
+ context: 'CORNERSTONE',
+ },
+ ],
+ 'Circle Tool'
+ ),
],
},
},
diff --git a/modes/longitudinal/src/initToolGroups.js b/modes/longitudinal/src/initToolGroups.js
index 6bbe668d2..b8e88db90 100644
--- a/modes/longitudinal/src/initToolGroups.js
+++ b/modes/longitudinal/src/initToolGroups.js
@@ -32,6 +32,7 @@ function initDefaultToolGroup(
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
+ { toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
@@ -113,6 +114,7 @@ function initSRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: SRToolNames.SRArrowAnnotate },
{ toolName: SRToolNames.SRBidirectional },
{ toolName: SRToolNames.SREllipticalROI },
+ { toolName: SRToolNames.SRCircleROI },
],
enabled: [
{
@@ -173,6 +175,7 @@ function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) {
{ toolName: toolNames.Bidirectional },
{ toolName: toolNames.DragProbe },
{ toolName: toolNames.EllipticalROI },
+ { toolName: toolNames.CircleROI },
{ toolName: toolNames.RectangleROI },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Angle },
diff --git a/modes/longitudinal/src/toolbarButtons.js b/modes/longitudinal/src/toolbarButtons.js
index a2b72cbf1..92de37e89 100644
--- a/modes/longitudinal/src/toolbarButtons.js
+++ b/modes/longitudinal/src/toolbarButtons.js
@@ -208,6 +208,29 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
+ _createToolButton(
+ 'CircleROI',
+ 'tool-circle',
+ 'Circle',
+ [
+ {
+ commandName: 'setToolActive',
+ commandOptions: {
+ toolName: 'CircleROI',
+ },
+ context: 'CORNERSTONE',
+ },
+ {
+ commandName: 'setToolActive',
+ commandOptions: {
+ toolName: 'SRCircleROI',
+ toolGroupId: 'SRToolGroup',
+ },
+ context: 'CORNERSTONE',
+ },
+ ],
+ 'Circle Tool'
+ ),
],
},
},
diff --git a/modes/tmtv/src/toolbarButtons.js b/modes/tmtv/src/toolbarButtons.js
index 8fd347737..f6f707221 100644
--- a/modes/tmtv/src/toolbarButtons.js
+++ b/modes/tmtv/src/toolbarButtons.js
@@ -173,6 +173,20 @@ const toolbarButtons = [
],
'Ellipse Tool'
),
+ _createToolButton(
+ 'CircleROI',
+ 'tool-circle',
+ 'Circle',
+ [
+ ..._createCommands('setToolActive', 'CircleROI', [
+ toolGroupIds.CT,
+ toolGroupIds.PT,
+ toolGroupIds.Fusion,
+ // toolGroupIds.MPR,
+ ]),
+ ],
+ 'Circle Tool'
+ ),
],
},
},
@@ -299,8 +313,7 @@ const toolbarButtons = [
commandName: 'displayNotification',
commandOptions: {
title: 'RectangleROI Threshold Tip',
- text:
- 'RectangleROI Threshold tool should be used on PT Axial Viewport',
+ text: 'RectangleROI Threshold tool should be used on PT Axial Viewport',
type: 'info',
},
},
diff --git a/platform/core/package.json b/platform/core/package.json
index 42c973065..cb97a9eab 100644
--- a/platform/core/package.json
+++ b/platform/core/package.json
@@ -37,7 +37,7 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"dicomweb-client": "^0.8.4",
"isomorphic-base64": "^1.0.2",
"lodash.merge": "^4.6.1",
diff --git a/platform/core/src/utils/roundNumber.js b/platform/core/src/utils/roundNumber.js
index b62e5df42..a441225da 100644
--- a/platform/core/src/utils/roundNumber.js
+++ b/platform/core/src/utils/roundNumber.js
@@ -1,5 +1,9 @@
+/**
+ * @param {string | number} value
+ * @param {number} decimals
+ */
function _round(value, decimals) {
- return Number(value.toFixed(decimals));
+ return Number(value).toFixed(decimals);
}
export default _round;
diff --git a/platform/docs/versioned_docs/version-3.0/platform/extensions/modules/toolbar.md b/platform/docs/versioned_docs/version-3.0/platform/extensions/modules/toolbar.md
index f340e0c4e..98e0d91a7 100644
--- a/platform/docs/versioned_docs/version-3.0/platform/extensions/modules/toolbar.md
+++ b/platform/docs/versioned_docs/version-3.0/platform/extensions/modules/toolbar.md
@@ -184,6 +184,16 @@ to create `MeasurementTools` nested button
toolName: 'EllipticalRoi',
}
},
+ // Circle tool
+ {
+ id: 'CircleROI',
+ icon: 'tool-circle',
+ label: 'Circle',
+ type: 'tool',
+ commandOptions: {
+ toolName: 'CircleROI',
+ }
+ },
],
},
}
diff --git a/platform/docs/versioned_docs/version-3.0/platform/services/data/ToolbarService.md b/platform/docs/versioned_docs/version-3.0/platform/services/data/ToolbarService.md
index b080c6ef4..92ab50048 100644
--- a/platform/docs/versioned_docs/version-3.0/platform/services/data/ToolbarService.md
+++ b/platform/docs/versioned_docs/version-3.0/platform/services/data/ToolbarService.md
@@ -210,6 +210,16 @@ to create `MeasurementTools` nested button
toolName: 'EllipticalRoi',
}
},
+ // Circle tool
+ {
+ id: 'CircleROI',
+ icon: 'tool-circle',
+ label: 'Circle',
+ type: 'tool',
+ commandOptions: {
+ toolName: 'CircleROI',
+ }
+ },
],
},
}
diff --git a/platform/ui/src/assets/icons/tool-circle.svg b/platform/ui/src/assets/icons/tool-circle.svg
new file mode 100644
index 000000000..e94375564
--- /dev/null
+++ b/platform/ui/src/assets/icons/tool-circle.svg
@@ -0,0 +1,3 @@
+
diff --git a/platform/ui/src/components/Icon/getIcon.js b/platform/ui/src/components/Icon/getIcon.js
index e6c3b986a..b8df5463d 100644
--- a/platform/ui/src/components/Icon/getIcon.js
+++ b/platform/ui/src/components/Icon/getIcon.js
@@ -81,6 +81,7 @@ import toolWindow from './../../assets/icons/tool-window-level.svg';
import toolAnnotate from './../../assets/icons/tool-annotate.svg';
import toolBidirectional from './../../assets/icons/tool-bidirectional.svg';
import toolElipse from './../../assets/icons/tool-elipse.svg';
+import toolCircle from './../../assets/icons/tool-circle.svg';
import toolLength from './../../assets/icons/tool-length.svg';
import toolStackScroll from './../../assets/icons/tool-stack-scroll.svg';
import toolMagnify from './../../assets/icons/tool-magnify.svg';
@@ -199,6 +200,7 @@ const ICONS = {
'tool-annotate': toolAnnotate,
'tool-bidirectional': toolBidirectional,
'tool-elipse': toolElipse,
+ 'tool-circle': toolCircle,
'tool-length': toolLength,
'tool-stack-scroll': toolStackScroll,
'tool-magnify': toolMagnify,
diff --git a/platform/viewer/package.json b/platform/viewer/package.json
index 60bbf2f42..2c1c7325b 100644
--- a/platform/viewer/package.json
+++ b/platform/viewer/package.json
@@ -66,7 +66,7 @@
"core-js": "^3.16.1",
"cornerstone-math": "^0.1.9",
"cornerstone-wado-image-loader": "^4.13.0",
- "dcmjs": "^0.29.4",
+ "dcmjs": "^0.29.5",
"detect-gpu": "^4.0.16",
"dicom-parser": "^1.8.9",
"dotenv-webpack": "^1.7.0",
diff --git a/yarn.lock b/yarn.lock
index e5d1f8dde..5611ea7a2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9247,21 +9247,9 @@ dayjs@^1.10.4:
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
-dcmjs@^0.29.4:
- version "0.29.4"
- resolved "https://registry.npmjs.org/dcmjs/-/dcmjs-0.29.4.tgz#3fb13945611979f756bc91b3f199fd87b4eabdb4"
- integrity sha512-PzD6C4oB7v/AVTIPbkS6D6hjgVcSW7+T+DsxFpkD1xcEgU4qjGM16WGEHH3ZAPDBF0Xgm2d9FXUu/lXZIyfmow==
- dependencies:
- "@babel/runtime-corejs2" "^7.17.8"
- gl-matrix "^3.1.0"
- lodash.clonedeep "^4.5.0"
- loglevelnext "^3.0.1"
- ndarray "^1.0.19"
- pako "^2.0.4"
-
dcmjs@^0.29.5:
version "0.29.5"
- resolved "https://registry.npmjs.org/dcmjs/-/dcmjs-0.29.5.tgz#3e2311fc47aafc70f21e236ad89e2ff9ba6589fd"
+ resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.29.5.tgz#3e2311fc47aafc70f21e236ad89e2ff9ba6589fd"
integrity sha512-CcLo3pwitf9JhhvW3/icCraxUhaIKJRyOys9XJlBBDn5TQskyJzxgveLKejcryHn4DooqlJPeMuM4ixdPFEERQ==
dependencies:
"@babel/runtime-corejs2" "^7.17.8"