fix(cornerstone-dicom-rt): adding caching usage to cornerstone-dicom-rt SOP Class Handler (#5387)

This commit is contained in:
Vinícius Alves de Faria Resende 2025-09-05 09:35:16 -03:00 committed by GitHub
parent 7de1c78fc4
commit d6ea179ac4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 54 deletions

View File

@ -4,7 +4,11 @@ import i18n from '@ohif/i18n';
import { SOPClassHandlerId } from './id';
import loadRTStruct from './loadRTStruct';
const sopClassUids = ['1.2.840.10008.5.1.4.1.1.481.3'];
const { sopClassDictionary } = utils;
const sopClassUids = [sopClassDictionary.RTStructureSetStorage];
const cachedRTStructsSEG = new Set<string>();
const loadPromises = {};
@ -113,39 +117,45 @@ function _load(
) {
const { SOPInstanceUID } = rtDisplaySet;
const { segmentationService } = servicesManager.services;
if (
(rtDisplaySet.loading || rtDisplaySet.isLoaded) &&
loadPromises[SOPInstanceUID] &&
_segmentationExistsInCache(rtDisplaySet, segmentationService)
cachedRTStructsSEG.has(rtDisplaySet.displaySetInstanceUID)
) {
return loadPromises[SOPInstanceUID];
}
rtDisplaySet.loading = true;
const { unsubscribe } = segmentationService.subscribe(
segmentationService.EVENTS.SEGMENTATION_LOADING_COMPLETE,
(evt: { rtDisplaySet: { displaySetInstanceUID: string } }) => {
if (evt.rtDisplaySet?.displaySetInstanceUID === rtDisplaySet.displaySetInstanceUID) {
cachedRTStructsSEG.add(rtDisplaySet.displaySetInstanceUID);
unsubscribe();
}
}
);
// We don't want to fire multiple loads, so we'll wait for the first to finish
// and also return the same promise to any other callers.
loadPromises[SOPInstanceUID] = new Promise(async (resolve, reject) => {
if (!rtDisplaySet.structureSet) {
const structureSet = await loadRTStruct(extensionManager, rtDisplaySet, headers);
loadPromises[SOPInstanceUID] = new Promise<void>(async (resolve, reject) => {
try {
if (!rtDisplaySet.structureSet) {
const structureSet = await loadRTStruct(extensionManager, rtDisplaySet, headers);
rtDisplaySet.structureSet = structureSet;
}
rtDisplaySet.structureSet = structureSet;
}
if (createSegmentation) {
await segmentationService.createSegmentationForRTDisplaySet(rtDisplaySet);
}
if (createSegmentation) {
segmentationService
.createSegmentationForRTDisplaySet(rtDisplaySet)
.then(() => {
rtDisplaySet.loading = false;
resolve();
})
.catch(error => {
rtDisplaySet.loading = false;
reject(error);
});
} else {
rtDisplaySet.loading = false;
resolve();
} catch (error) {
reject(error);
} finally {
rtDisplaySet.loading = false;
}
});
@ -187,11 +197,6 @@ function _deriveReferencedSeriesSequenceFromFrameOfReferenceSequence(
return ReferencedSeriesSequence;
}
function _segmentationExistsInCache() {
// Todo: fix this
return false;
}
function getSopClassHandlerModule(params: OhifTypes.Extensions.ExtensionParams) {
const { servicesManager, extensionManager } = params;

View File

@ -137,16 +137,12 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,
continue;
}
const isSupported = false;
const ContourSequenceArray = _toArray(ContourSequence);
const contourPoints = [];
for (let c = 0; c < ContourSequenceArray.length; c++) {
for (const ContourSequenceItem of ContourSequenceArray) {
const { ContourData, NumberOfContourPoints, ContourGeometricType, ContourImageSequence } =
ContourSequenceArray[c];
let isSupported = false;
ContourSequenceItem;
const points = [];
for (let p = 0; p < NumberOfContourPoints * 3; p += 3) {
@ -157,22 +153,18 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,
});
}
switch (ContourGeometricType) {
case 'CLOSED_PLANAR':
case 'OPEN_PLANAR':
case 'POINT':
isSupported = true;
break;
default:
continue;
}
const supportedContourTypesMap = new Map([
['CLOSED_PLANAR', false],
['OPEN_NONPLANAR', false],
['OPEN_PLANAR', false],
['POINT', true],
]);
contourPoints.push({
numberOfPoints: NumberOfContourPoints,
points,
type: ContourGeometricType,
isSupported,
isSupported: supportedContourTypesMap.get(ContourGeometricType) ?? false,
});
if (ContourImageSequence?.ReferencedSOPInstanceUID) {
@ -187,8 +179,7 @@ export default async function loadRTStruct(extensionManager, rtStructDisplaySet,
StructureSetROISequence,
RTROIObservationsSequence,
ROIContour,
contourPoints,
isSupported
contourPoints
);
}
return structureSet;
@ -199,8 +190,7 @@ function _setROIContourMetadata(
StructureSetROISequence,
RTROIObservationsSequence,
ROIContour,
contourPoints,
isSupported
contourPoints
) {
const StructureSetROI = StructureSetROISequence.find(
structureSetROI => structureSetROI.ROINumber === ROIContour.ReferencedROINumber
@ -211,9 +201,9 @@ function _setROIContourMetadata(
ROIName: StructureSetROI.ROIName,
ROIGenerationAlgorithm: StructureSetROI.ROIGenerationAlgorithm,
ROIDescription: StructureSetROI.ROIDescription,
isSupported,
contourPoints,
visible: true,
colorArray: [],
};
_setROIContourDataColor(ROIContour, ROIContourData);

View File

@ -574,10 +574,19 @@ class SegmentationService extends PubSubService {
// find the first image id that contains a referenced SOP instance UID
const firstSegmentedSliceImageId =
referencedImageIds?.find(imageId =>
referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId))
referencedImageIdsWithGeometry.some(referencedId =>
imageId.includes(referencedId as string)
)
) || null;
rtDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
if (!structureSet.ROIContours?.length) {
throw new Error(
'The structureSet does not contain any ROIContours. Please ensure the structureSet is loaded first.'
);
}
// Map ROI contours to RT Struct Data
const allRTStructData = mapROIContoursToRTStructData(structureSet, rtDisplaySetUID);
@ -600,12 +609,6 @@ class SegmentationService extends PubSubService {
},
};
if (!structureSet.ROIContours?.length) {
throw new Error(
'The structureSet does not contain any ROIContours. Please ensure the structureSet is loaded first.'
);
}
const segments: { [segmentIndex: string]: cstTypes.Segment } = {};
let segmentsCachedStats = {};