fix: Cornerstone3D 3.0 (#4816)

Co-authored-by: sedghi <ar.sedghi@gmail.com>
This commit is contained in:
Bill Wallaceandsedghi authored and GitHub committed 2025-02-28 14:16:39 -05:00
1 parent 62abb3ac47
commit 24567c4e92
25 files changed
+326 -342

No files matched your search

@@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.19.14",
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/adapters": "^3.0.1",
"@cornerstonejs/core": "^3.0.1",
"@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3"
}
@@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.19.14",
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/adapters": "^3.0.1",
"@cornerstonejs/core": "^3.0.1",
"@kitware/vtk.js": "32.1.1",
"react-color": "^2.19.3"
}
@@ -324,10 +324,8 @@ const commandsModule = ({
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
toolNames?.forEach(toolName => {
toolGroup.setToolConfiguration(toolName, {
strategySpecificConfiguration: {
THRESHOLD: {
threshold: value,
},
threshold: {
range: value,
},
});
});
+3 -3
View File
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.19.14",
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/tools": "^2.19.14",
"@cornerstonejs/adapters": "^3.0.1",
"@cornerstonejs/core": "^3.0.1",
"@cornerstonejs/tools": "^3.0.1",
"classnames": "^2.3.2"
}
}
@@ -391,7 +391,12 @@ function _getStatusComponent({
switch (state) {
case 1:
StatusIcon = () => <Icons.ByName name="status-alert" />;
StatusIcon = () => (
<Icons.ByName
name="status-alert"
className="h-4 w-4"
/>
);
ToolTipMessage = () => (
<div>
@@ -402,7 +407,12 @@ function _getStatusComponent({
);
break;
case 2:
StatusIcon = () => <Icons.ByName name="status-locked" />;
StatusIcon = () => (
<Icons.ByName
name="status-locked"
className="h-4 w-4"
/>
);
ToolTipMessage = () => (
<div>
@@ -417,7 +427,7 @@ function _getStatusComponent({
case 3:
StatusIcon = () => (
<Icons.ByName
className="text-aqua-pale"
className="text-aqua-pale h-4 w-4"
name="status-untracked"
/>
);
@@ -439,7 +449,7 @@ function _getStatusComponent({
return (
<div className="flex h-6 cursor-default text-sm leading-6 text-white">
<div className="bg-customgray-100 flex min-w-[45px] items-center rounded-l-xl rounded-r p-1">
<StatusIcon />
<StatusIcon className="h-4 w-4" />
<span className="ml-1">SR</span>
</div>
{state === 3 && (
@@ -85,7 +85,8 @@ export default function hydrateStructuredReport(
}
});
const datasetToUse = _mapLegacyDataSet(instance);
// Mapping of legacy datasets is now directly handled by adapters module
const datasetToUse = instance;
// Use dcmjs to generate toolState.
let storedMeasurementByAnnotationType = MeasurementReport.generateToolState(
@@ -237,62 +238,3 @@ export default function hydrateStructuredReport(
SeriesInstanceUIDs,
};
}
function _mapLegacyDataSet(dataset) {
const REPORT = 'Imaging Measurements';
const GROUP = 'Measurement Group';
const TRACKING_IDENTIFIER = 'Tracking Identifier';
// Identify the Imaging Measurements
const imagingMeasurementContent = toArray(dataset.ContentSequence).find(
codeMeaningEquals(REPORT)
);
// Retrieve the Measurements themselves
const measurementGroups = toArray(imagingMeasurementContent.ContentSequence).filter(
codeMeaningEquals(GROUP)
);
// For each of the supported measurement types, compute the measurement data
const measurementData = {};
const cornerstoneToolClasses = MeasurementReport.CORNERSTONE_TOOL_CLASSES_BY_UTILITY_TYPE;
const registeredToolClasses = [];
Object.keys(cornerstoneToolClasses).forEach(key => {
registeredToolClasses.push(cornerstoneToolClasses[key]);
measurementData[key] = [];
});
measurementGroups.forEach((measurementGroup, index) => {
const measurementGroupContentSequence = toArray(measurementGroup.ContentSequence);
const TrackingIdentifierGroup = measurementGroupContentSequence.find(
contentItem => contentItem.ConceptNameCodeSequence.CodeMeaning === TRACKING_IDENTIFIER
);
const TrackingIdentifier = TrackingIdentifierGroup.TextValue;
let [cornerstoneTag, toolName] = TrackingIdentifier.split(':');
if (supportedLegacyCornerstoneTags.includes(cornerstoneTag)) {
cornerstoneTag = CORNERSTONE_3D_TAG;
}
const mappedTrackingIdentifier = `${cornerstoneTag}:${toolName}`;
TrackingIdentifierGroup.TextValue = mappedTrackingIdentifier;
});
return dataset;
}
const toArray = function (x) {
return Array.isArray(x) ? x : [x];
};
const codeMeaningEquals = codeMeaningName => {
return contentItem => {
return contentItem.ConceptNameCodeSequence.CodeMeaning === codeMeaningName;
};
};
@@ -1,60 +0,0 @@
import { adaptersSR } from '@cornerstonejs/adapters';
const cornerstoneAdapters =
adaptersSR.Cornerstone3D.MeasurementReport.CORNERSTONE_TOOL_CLASSES_BY_UTILITY_TYPE;
const supportedLegacyCornerstoneTags = ['cornerstoneTools@^4.0.0'];
const CORNERSTONE_3D_TAG = adaptersSR.Cornerstone3D.CORNERSTONE_3D_TAG;
/**
* Checks if the given `displaySet`can be rehydrated into the `measurementService`.
*
* @param {object} displaySet The SR `displaySet` to check.
* @param {object[]} mappings The CornerstoneTools 4 mappings to the `measurementService`.
* @returns {boolean} True if the SR can be rehydrated into the `measurementService`.
*/
export default function isRehydratable(displaySet, mappings) {
if (!mappings || !mappings.length) {
return false;
}
const mappingDefinitions = mappings.map(m => m.annotationType);
const { measurements } = displaySet;
const adapterKeys = Object.keys(cornerstoneAdapters).filter(
adapterKey =>
typeof cornerstoneAdapters[adapterKey].isValidCornerstoneTrackingIdentifier === 'function'
);
const adapters = [];
adapterKeys.forEach(key => {
if (mappingDefinitions.includes(key)) {
// Must have both a dcmjs adapter and a measurementService
// Definition in order to be a candidate for import.
adapters.push(cornerstoneAdapters[key]);
}
});
for (let i = 0; i < measurements.length; i++) {
const { TrackingIdentifier } = measurements[i] || {};
const hydratable = adapters.some(adapter => {
let [cornerstoneTag, toolName] = TrackingIdentifier.split(':');
if (supportedLegacyCornerstoneTags.includes(cornerstoneTag)) {
cornerstoneTag = CORNERSTONE_3D_TAG;
}
const mappedTrackingIdentifier = `${cornerstoneTag}:${toolName}`;
return adapter.isValidCornerstoneTrackingIdentifier(mappedTrackingIdentifier);
});
if (hydratable) {
return true;
}
console.log('Measurement is not rehydratable', TrackingIdentifier, measurements[i]);
}
console.log('No measurements found which were rehydratable');
return false;
}
@@ -0,0 +1,41 @@
import { adaptersSR } from '@cornerstonejs/adapters';
const { MeasurementReport } = adaptersSR.Cornerstone3D;
/**
* Checks if the given `displaySet`can be rehydrated into the `measurementService`.
*
* @param {object} displaySet The SR `displaySet` to check.
* @param {object[]} mappings The CornerstoneTools 4 mappings to the `measurementService`.
* @returns {boolean} True if the SR can be rehydrated into the `measurementService`.
*/
export default function isRehydratable(displaySet, mappings) {
if (!mappings || !mappings.length) {
return false;
}
const mappingDefinitions = new Set<string>();
for (const m of mappings) {
mappingDefinitions.add(m.annotationType);
}
const { measurements } = displaySet;
for (let i = 0; i < measurements.length; i++) {
const { TrackingIdentifier } = measurements[i] || {};
if (!TrackingIdentifier) {
console.warn('No tracking identifier for measurement ', measurements[i]);
continue;
}
const adapter = MeasurementReport.getAdapterForTrackingIdentifier(TrackingIdentifier);
const hydratable = adapter && mappingDefinitions.has(adapter.toolType);
if (hydratable) {
return true;
}
console.log('Measurement is not rehydratable', TrackingIdentifier, measurements[i]);
}
console.log('No measurements found which were rehydratable');
return false;
}
@@ -42,8 +42,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/tools": "^2.19.14",
"@cornerstonejs/core": "^3.0.1",
"@cornerstonejs/tools": "^3.0.1",
"classnames": "^2.3.2"
}
}
+5 -5
View File
@@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.19.14",
"@cornerstonejs/dicom-image-loader": "^3.0.1",
"@ohif/core": "3.10.0-beta.113",
"@ohif/ui": "3.10.0-beta.113",
"dcmjs": "*",
@@ -51,10 +51,10 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.19.14",
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/tools": "^2.19.14",
"@icr/polyseg-wasm": "^0.4.0",
"@cornerstonejs/adapters": "^3.0.1",
"@cornerstonejs/core": "^3.0.1",
"@cornerstonejs/tools": "^3.0.1",
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.1.1",
"html2canvas": "^1.4.1",
@@ -37,6 +37,7 @@ import {
OrientationMarkerTool,
WindowLevelRegionTool,
} from '@cornerstonejs/tools';
import * as polySeg from '@cornerstonejs/polymorphic-segmentation';
import CalibrationLineTool from './tools/CalibrationLineTool';
import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool';
@@ -47,7 +48,11 @@ export default function initCornerstoneTools(configuration = {}) {
AdvancedMagnifyTool.isAnnotation = false;
PlanarFreehandContourSegmentationTool.isAnnotation = false;
init(configuration);
init({
addons: {
polySeg,
},
});
addTool(PanTool);
addTool(WindowLevelTool);
addTool(StackScrollTool);
@@ -2,7 +2,8 @@ import SUPPORTED_TOOLS from './constants/supportedTools';
import { getIsLocked } from './utils/getIsLocked';
import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes';
import { getIsVisible } from './utils/getIsVisible';
const Length = {
const ArrowAnnotate = {
toAnnotation: measurement => {},
/**
@@ -172,4 +173,4 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
values,
};
}
export default Length;
export default ArrowAnnotate;
+2 -2
View File
@@ -32,8 +32,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^2.19.14",
"@cornerstonejs/tools": "^2.19.14",
"@cornerstonejs/core": "^3.0.1",
"@cornerstonejs/tools": "^3.0.1",
"@ohif/core": "3.10.0-beta.113",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
"@ohif/extension-default": "3.10.0-beta.113",
@@ -89,6 +89,15 @@ function TrackedMeasurementsContextProvider(
);
// Jump to the last tracked measurement - most recent
if (!trackedMeasurements?.length) {
console.warn(
"Didn't find any tracked measurements",
measurements,
trackedStudy,
trackedSeries
);
return;
}
const trackedMeasurement = trackedMeasurements[trackedMeasurements.length - 1];
const referencedDisplaySetUID = trackedMeasurement.displaySetInstanceUID;