From cb20b3e57ca2746c2d9417ea9327a275bd1205a3 Mon Sep 17 00:00:00 2001 From: rodrigobasilio2022 Date: Wed, 9 Aug 2023 11:59:54 -0300 Subject: [PATCH 1/4] adds auto hydration to the mode --- src/index.js | 16 ++++ src/loadDerivedDisplaySets.ts | 151 ++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/loadDerivedDisplaySets.ts diff --git a/src/index.js b/src/index.js index 00be3b9..d2af929 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,8 @@ import { hotkeys } from '@ohif/core'; import toolbarButtons from './toolbarButtons.js'; import { id } from './id.js'; import initToolGroups from './initToolGroups.js'; +import loadDerivedDisplaySets from './loadDerivedDisplaySets'; +import { eventTarget, EVENTS } from '@cornerstonejs/core'; // Allow this mode by excluding non-imaging modalities such as SR, SEG // Also, SM is not a simple imaging modalities, so exclude it. @@ -65,6 +67,7 @@ const extensionDependencies = { function modeFactory() { let _activatePanelTriggersSubscriptions = []; + let boundedLoadDerivedDisplaySets; return { // TODO: We're using this as a route segment // We should not be. @@ -82,6 +85,11 @@ function modeFactory() { segmentationService, } = servicesManager.services; + boundedLoadDerivedDisplaySets = loadDerivedDisplaySets.bind( + null, + servicesManager, + extensionManager + ); measurementService.clearMeasurements(); // Init Default and SR ToolGroups @@ -152,6 +160,10 @@ function modeFactory() { // }, // ]), // ]; + eventTarget.addEventListener( + EVENTS.STACK_VIEWPORT_NEW_STACK, + boundedLoadDerivedDisplaySets + ); }, onModeExit: ({ servicesManager }) => { const { @@ -162,6 +174,10 @@ function modeFactory() { cornerstoneViewportService, } = servicesManager.services; + eventTarget.removeEventListener( + EVENTS.STACK_VIEWPORT_NEW_STACK, + boundedLoadDerivedDisplaySets + ); _activatePanelTriggersSubscriptions.forEach(sub => sub.unsubscribe()); _activatePanelTriggersSubscriptions = []; diff --git a/src/loadDerivedDisplaySets.ts b/src/loadDerivedDisplaySets.ts new file mode 100644 index 0000000..e92ac49 --- /dev/null +++ b/src/loadDerivedDisplaySets.ts @@ -0,0 +1,151 @@ +import { hydrateSEGDisplaySet } from '@ohif/extension-cornerstone-dicom-seg'; +import { hydrateRTDisplaySet } from '@ohif/extension-cornerstone-dicom-rt'; +import { hydrateStructuredReport } from '@ohif/extension-cornerstone-dicom-sr'; +import { cache as cs3DCache, volumeLoader } from '@cornerstonejs/core'; + +const delay = 0; + +function getDerivedSequences(displaySetUID, servicesManager) { + const { displaySetService } = servicesManager.services; + + const displaySetCache = displaySetService.getDisplaySetCache(); + const derivedDisplaySets = [...displaySetCache.values()].filter(ds => { + if (ds?.getReferenceDisplaySet) { + ds?.getReferenceDisplaySet(); + } + return ( + (ds?.referencedDisplaySetInstanceUID === displaySetUID || + ds.Modality === 'SR') && + !ds?.isHydrated + ); + }); + return derivedDisplaySets; +} + +export default function loadDerivedDisplaySets( + servicesManager, + extensionManager, + evt +) { + async function checkVolume(displaySet, imageIds) { + const VOLUME_LOADER_SCHEME = 'cornerstoneStreamingImageVolume'; + const volumeLoaderSchema = + displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME; + + const volumeId = `${volumeLoaderSchema}:${displaySet.displaySetInstanceUID}`; + + let volume = cs3DCache.getVolume(volumeId); + + if (!volume) { + volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds }); + } + } + + const { + userAuthenticationService, + segmentationService, + displaySetService, + viewportGridService, + } = servicesManager.services; + + const { viewports } = viewportGridService.getState(); + const { viewportId, imageIds } = evt.detail; + let viewportIndex = -1; + for (let i = 0; i < viewports.length; i++) { + if ((viewports[i].viewportId = viewportId)) { + viewportIndex = i; + break; + } + } + const mainViewport = viewports[viewportIndex]; + if (viewportIndex > -1) { + if (mainViewport.displaySetInstanceUIDs.length === 1) { + const mainDisplaySet = displaySetService.getDisplaySetByUID( + mainViewport.displaySetInstanceUIDs[0] + ); + const derivedDisplaySets = getDerivedSequences( + mainViewport.displaySetInstanceUIDs[0], + servicesManager + ); + + derivedDisplaySets.forEach(async displaySet => { + const headers = userAuthenticationService.getAuthorizationHeader(); + await checkVolume(mainDisplaySet, imageIds); + await displaySet.load({ headers }); + const derivedDisplaySetInstanceUID = displaySet.displaySetInstanceUID; + + if (displaySet.Modality === 'SEG') { + let segmentationId = null; + + // We need the hydration to notify panels about the new segmentation added + const suppressEvents = false; + + segmentationId = await segmentationService.createSegmentationForSEGDisplaySet( + displaySet, + segmentationId, + suppressEvents + ); + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateSEGDisplaySet({ + segDisplaySet: displaySet, + viewportIndex, + servicesManager, + }); + }, delay); + } else if (displaySet.Modality === 'RTSTRUCT') { + let segmentationId = null; + + // We need the hydration to notify panels about the new segmentation added + const suppressEvents = false; + + segmentationId = await segmentationService.createSegmentationForRTDisplaySet( + displaySet, + segmentationId, + suppressEvents + ); + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateRTDisplaySet({ + rtDisplaySet: displaySet, + viewportIndex, + servicesManager, + }); + }, delay); + } else if (displaySet.Modality === 'SR') { + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateStructuredReport( + { servicesManager, extensionManager }, + derivedDisplaySetInstanceUID + ); + }, delay); + } + }); + } + } +} From b2f298b2e45ac741e40bd12eced1a28d4f554e60 Mon Sep 17 00:00:00 2001 From: rodrigobasilio2022 Date: Fri, 25 Aug 2023 14:45:58 -0300 Subject: [PATCH 2/4] Sets disableEditing and future minDisplaySetsToRunHP in mode --- src/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index d2af929..75868cb 100644 --- a/src/index.js +++ b/src/index.js @@ -76,7 +76,7 @@ function modeFactory() { /** * Lifecycle hooks */ - onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => { + onModeEnter: ({ servicesManager, extensionManager, commandsManager, appConfig }) => { const { measurementService, toolbarService, @@ -84,6 +84,8 @@ function modeFactory() { panelService, segmentationService, } = servicesManager.services; + appConfig.disableEditing = true; + appConfig.minDisplaySetsToRunHP = 10; boundedLoadDerivedDisplaySets = loadDerivedDisplaySets.bind( null, @@ -165,7 +167,7 @@ function modeFactory() { boundedLoadDerivedDisplaySets ); }, - onModeExit: ({ servicesManager }) => { + onModeExit: ({ servicesManager, appConfig }) => { const { toolGroupService, syncGroupService, @@ -173,6 +175,9 @@ function modeFactory() { segmentationService, cornerstoneViewportService, } = servicesManager.services; + appConfig.disableEditing = false; + appConfig.minDisplaySetsToRunHP = undefined; + eventTarget.removeEventListener( EVENTS.STACK_VIEWPORT_NEW_STACK, From 880ebad2a74c7d1591254b2b49c5a5ed8d4a9c24 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Fri, 29 Sep 2023 18:20:16 -0300 Subject: [PATCH 3/4] Address regression issue --- src/index.js | 3 ++- src/loadDerivedDisplaySets.ts | 22 +++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/index.js b/src/index.js index f902f9a..d30f803 100644 --- a/src/index.js +++ b/src/index.js @@ -93,7 +93,8 @@ function modeFactory() { boundedLoadDerivedDisplaySets = loadDerivedDisplaySets.bind( null, servicesManager, - extensionManager + extensionManager, + commandsManager ); measurementService.clearMeasurements(); diff --git a/src/loadDerivedDisplaySets.ts b/src/loadDerivedDisplaySets.ts index e92ac49..46a979e 100644 --- a/src/loadDerivedDisplaySets.ts +++ b/src/loadDerivedDisplaySets.ts @@ -1,4 +1,3 @@ -import { hydrateSEGDisplaySet } from '@ohif/extension-cornerstone-dicom-seg'; import { hydrateRTDisplaySet } from '@ohif/extension-cornerstone-dicom-rt'; import { hydrateStructuredReport } from '@ohif/extension-cornerstone-dicom-sr'; import { cache as cs3DCache, volumeLoader } from '@cornerstonejs/core'; @@ -25,6 +24,7 @@ function getDerivedSequences(displaySetUID, servicesManager) { export default function loadDerivedDisplaySets( servicesManager, extensionManager, + commandsManager, evt ) { async function checkVolume(displaySet, imageIds) { @@ -50,15 +50,8 @@ export default function loadDerivedDisplaySets( const { viewports } = viewportGridService.getState(); const { viewportId, imageIds } = evt.detail; - let viewportIndex = -1; - for (let i = 0; i < viewports.length; i++) { - if ((viewports[i].viewportId = viewportId)) { - viewportIndex = i; - break; - } - } - const mainViewport = viewports[viewportIndex]; - if (viewportIndex > -1) { + const mainViewport = viewports.get(viewportId); + if (mainViewport) { if (mainViewport.displaySetInstanceUIDs.length === 1) { const mainDisplaySet = displaySetService.getDisplaySetByUID( mainViewport.displaySetInstanceUIDs[0] @@ -95,10 +88,9 @@ export default function loadDerivedDisplaySets( derivedDisplaySetInstanceUID ); } - hydrateSEGDisplaySet({ - segDisplaySet: displaySet, - viewportIndex, - servicesManager, + commandsManager.runCommand('loadSegmentationDisplaySetsForViewport', { + displaySets: [displaySet], + viewportId, }); }, delay); } else if (displaySet.Modality === 'RTSTRUCT') { @@ -124,7 +116,7 @@ export default function loadDerivedDisplaySets( } hydrateRTDisplaySet({ rtDisplaySet: displaySet, - viewportIndex, + viewportId, servicesManager, }); }, delay); From 6f9ec6a73ecdf890dcb4428148aecf1da752b81a Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Fri, 29 Sep 2023 18:31:39 -0300 Subject: [PATCH 4/4] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d847564..3459529 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ohif-idc-mode", - "version": "0.0.1", + "version": "0.0.2", "description": "OHIF IDC Mode", "author": "IDC", "license": "MIT",