From 38a3756b62750a9e7d80c0b8a027b7762de1f184 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Tue, 2 Sep 2025 08:50:20 -0300 Subject: [PATCH 1/7] Add command to load derived display sets --- bun.lock | 88 ++++++++++---------- extensions/cornerstone/src/commandsModule.ts | 43 ++++++++++ 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/bun.lock b/bun.lock index 14fcaef137f..362b0ac3955 100644 --- a/bun.lock +++ b/bun.lock @@ -41,7 +41,7 @@ }, "addOns/externals/devDependencies": { "name": "@externals/devDependencies", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@kitware/vtk.js": "32.12.0", @@ -126,14 +126,14 @@ }, "addOns/externals/dicom-microscopy-viewer": { "name": "@externals/dicom-microscopy-viewer", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "dicom-microscopy-viewer": "^0.48.6", }, }, "extensions/cornerstone": { "name": "@ohif/extension-cornerstone", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -159,8 +159,8 @@ "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/dicom-image-loader": "^4.0.0", - "@ohif/core": "3.12.0-beta.18", - "@ohif/ui": "3.12.0-beta.18", + "@ohif/core": "3.12.0-beta.22", + "@ohif/ui": "3.12.0-beta.22", "dcmjs": "0.43.1", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -172,7 +172,7 @@ }, "extensions/cornerstone-dicom-pmap": { "name": "@ohif/extension-cornerstone-dicom-pmap", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -195,7 +195,7 @@ }, "extensions/cornerstone-dicom-rt": { "name": "@ohif/extension-cornerstone-dicom-rt", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "react-color": "^2.19.3", @@ -215,7 +215,7 @@ }, "extensions/cornerstone-dicom-seg": { "name": "@ohif/extension-cornerstone-dicom-seg", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -238,7 +238,7 @@ }, "extensions/cornerstone-dicom-sr": { "name": "@ohif/extension-cornerstone-dicom-sr", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -247,10 +247,10 @@ "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.12.0-beta.18", - "@ohif/extension-cornerstone": "3.12.0-beta.18", - "@ohif/extension-measurement-tracking": "3.12.0-beta.18", - "@ohif/ui": "3.12.0-beta.18", + "@ohif/core": "3.12.0-beta.22", + "@ohif/extension-cornerstone": "3.12.0-beta.22", + "@ohif/extension-measurement-tracking": "3.12.0-beta.22", + "@ohif/ui": "3.12.0-beta.22", "dcmjs": "0.43.1", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -260,7 +260,7 @@ }, "extensions/cornerstone-dynamic-volume": { "name": "@ohif/extension-cornerstone-dynamic-volume", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -282,7 +282,7 @@ }, "extensions/default": { "name": "@ohif/extension-default", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/calculate-suv": "^1.1.0", @@ -290,8 +290,8 @@ "lodash.uniqby": "^4.7.0", }, "peerDependencies": { - "@ohif/core": "3.12.0-beta.18", - "@ohif/i18n": "3.12.0-beta.18", + "@ohif/core": "3.12.0-beta.22", + "@ohif/i18n": "3.12.0-beta.22", "dcmjs": "0.43.1", "dicomweb-client": "^0.10.4", "prop-types": "^15.6.2", @@ -305,7 +305,7 @@ }, "extensions/dicom-microscopy": { "name": "@ohif/extension-dicom-microscopy", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -330,7 +330,7 @@ }, "extensions/dicom-pdf": { "name": "@ohif/extension-dicom-pdf", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -347,7 +347,7 @@ }, "extensions/dicom-video": { "name": "@ohif/extension-dicom-video", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -364,20 +364,20 @@ }, "extensions/measurement-tracking": { "name": "@ohif/extension-measurement-tracking", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", - "@ohif/ui": "3.12.0-beta.18", + "@ohif/ui": "3.12.0-beta.22", "@xstate/react": "^3.2.2", "xstate": "^4.10.0", }, "peerDependencies": { "@cornerstonejs/core": "^4.0.0", "@cornerstonejs/tools": "^4.0.0", - "@ohif/core": "3.12.0-beta.18", - "@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.18", - "@ohif/extension-default": "3.12.0-beta.18", - "@ohif/ui": "3.12.0-beta.18", + "@ohif/core": "3.12.0-beta.22", + "@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.22", + "@ohif/extension-default": "3.12.0-beta.22", + "@ohif/ui": "3.12.0-beta.22", "classnames": "^2.3.2", "dcmjs": "0.43.1", "lodash.debounce": "^4.0.8", @@ -390,7 +390,7 @@ }, "extensions/test-extension": { "name": "@ohif/extension-test", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -407,7 +407,7 @@ }, "extensions/tmtv": { "name": "@ohif/extension-tmtv", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -424,7 +424,7 @@ }, "extensions/usAnnotation": { "name": "@ohif/extension-ultrasound-pleura-bline", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -476,7 +476,7 @@ }, "modes/basic-dev-mode": { "name": "@ohif/mode-basic-dev-mode", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -496,7 +496,7 @@ }, "modes/basic-test-mode": { "name": "@ohif/mode-test", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -518,7 +518,7 @@ }, "modes/longitudinal": { "name": "@ohif/mode-longitudinal", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -541,7 +541,7 @@ }, "modes/microscopy": { "name": "@ohif/mode-microscopy", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -553,7 +553,7 @@ }, "modes/preclinical-4d": { "name": "@ohif/mode-preclinical-4d", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", }, @@ -572,7 +572,7 @@ }, "modes/segmentation": { "name": "@ohif/mode-segmentation", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -616,7 +616,7 @@ }, "modes/tmtv": { "name": "@ohif/mode-tmtv", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -637,7 +637,7 @@ }, "modes/usAnnotation": { "name": "@ohif/mode-ultrasound-pleura-bline", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -676,7 +676,7 @@ }, "platform/app": { "name": "@ohif/app", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -746,7 +746,7 @@ }, "platform/cli": { "name": "@ohif/cli", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "bin": { "ohif-cli": "src/index.js", }, @@ -770,7 +770,7 @@ }, "platform/core": { "name": "@ohif/core", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "dcmjs": "0.43.1", @@ -797,14 +797,14 @@ "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/core": "^4.0.0", "@cornerstonejs/dicom-image-loader": "^4.0.0", - "@ohif/ui": "3.12.0-beta.18", + "@ohif/ui": "3.12.0-beta.22", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21", }, }, "platform/i18n": { "name": "@ohif/i18n", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@babel/runtime": "^7.20.13", "i18next-locize-backend": "^2.0.0", @@ -829,7 +829,7 @@ }, "platform/ui": { "name": "@ohif/ui", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@testing-library/react": "^13.1.0", "browser-detect": "^0.2.28", @@ -889,7 +889,7 @@ }, "platform/ui-next": { "name": "@ohif/ui-next", - "version": "3.12.0-beta.18", + "version": "3.12.0-beta.22", "dependencies": { "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 1deeecbad7e..2554a83e7d8 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -42,6 +42,7 @@ import { getUpdatedViewportsForSegmentation } from './utils/hydrationUtils'; import { SegmentationRepresentations } from '@cornerstonejs/tools/enums'; import { isMeasurementWithinViewport } from './utils/isMeasurementWithinViewport'; import { getCenterExtent } from './utils/getCenterExtent'; +import { DisplaySet } from 'platform/core/src/types'; const { DefaultHistoryMemo } = csUtils.HistoryMemo; const toggleSyncFunctions = { @@ -145,6 +146,45 @@ function commandsModule({ } const actions = { + loadDerivedDisplaySetsForActiveViewport: () => { + const { displaySetService, userAuthenticationService } = servicesManager.services; + + const getDerivedSequences = (displaySetUID: string): DisplaySet[] => { + const currentDs = displaySetService.getDisplaySetByUID(displaySetUID); + const displaySetCache = displaySetService.getDisplaySetCache(); + return Array.from(displaySetCache.values()).filter( + (ds: any): ds is DisplaySet => + (ds?.referencedDisplaySetInstanceUID === displaySetUID || + ds.referencedSeriesInstanceUID === currentDs.SeriesInstanceUID) && + !ds?.isHydrated + ); + }; + + const activeViewportId = viewportGridService.getActiveViewportId(); + const displaySetInstanceUIDs = + viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId); + + const derivedDisplayInstanceUIDs = getDerivedSequences(displaySetInstanceUIDs[0]).map( + ds => ds.displaySetInstanceUID + ); + + derivedDisplayInstanceUIDs.forEach(async displaySetInstanceUID => { + const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); + if (displaySet.Modality === 'SEG' || displaySet.Modality === 'RTSTRUCT') { + const headers = userAuthenticationService.getAuthorizationHeader(); + await displaySet.load({ headers }).catch(err => { + console.warn(`Failed to load display set ${displaySet.displaySetInstanceUID}:`, err); + }); + segmentationService.addSegmentationRepresentation(activeViewportId, { + segmentationId: displaySet.displaySetInstanceUID, + type: + displaySet.Modality === 'SEG' + ? Enums.SegmentationRepresentations.Labelmap + : Enums.SegmentationRepresentations.Contour, + }); + } + }); + }, jumpToMeasurementViewport: ({ annotationUID, measurement }) => { cornerstoneTools.annotation.selection.setAnnotationSelected(annotationUID, true); const { metadata } = measurement; @@ -2206,6 +2246,9 @@ function commandsModule({ }; const definitions = { + loadDerivedDisplaySetsForActiveViewport: { + commandFn: actions.loadDerivedDisplaySetsForActiveViewport, + }, // The command here is to show the viewer context menu, as being the // context menu showCornerstoneContextMenu: { From 33ded7297a99da710d82a20a2bea547b69f518ac Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Thu, 4 Sep 2025 08:29:56 -0300 Subject: [PATCH 2/7] Update name --- extensions/cornerstone/src/commandsModule.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 2554a83e7d8..30d41fbddf7 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -146,7 +146,7 @@ function commandsModule({ } const actions = { - loadDerivedDisplaySetsForActiveViewport: () => { + loadSegmentationsForActiveViewport: () => { const { displaySetService, userAuthenticationService } = servicesManager.services; const getDerivedSequences = (displaySetUID: string): DisplaySet[] => { @@ -2246,8 +2246,8 @@ function commandsModule({ }; const definitions = { - loadDerivedDisplaySetsForActiveViewport: { - commandFn: actions.loadDerivedDisplaySetsForActiveViewport, + loadSegmentationsForActiveViewport: { + commandFn: actions.loadSegmentationsForActiveViewport, }, // The command here is to show the viewer context menu, as being the // context menu From 8306710d73170ea024706364f408023365367fbe Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Tue, 9 Sep 2025 14:40:44 -0300 Subject: [PATCH 3/7] Update bun --- bun.lock | 88 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/bun.lock b/bun.lock index 362b0ac3955..d13811d0df5 100644 --- a/bun.lock +++ b/bun.lock @@ -41,7 +41,7 @@ }, "addOns/externals/devDependencies": { "name": "@externals/devDependencies", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@kitware/vtk.js": "32.12.0", @@ -126,14 +126,14 @@ }, "addOns/externals/dicom-microscopy-viewer": { "name": "@externals/dicom-microscopy-viewer", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "dicom-microscopy-viewer": "^0.48.6", }, }, "extensions/cornerstone": { "name": "@ohif/extension-cornerstone", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -159,8 +159,8 @@ "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/dicom-image-loader": "^4.0.0", - "@ohif/core": "3.12.0-beta.22", - "@ohif/ui": "3.12.0-beta.22", + "@ohif/core": "3.12.0-beta.23", + "@ohif/ui": "3.12.0-beta.23", "dcmjs": "0.43.1", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -172,7 +172,7 @@ }, "extensions/cornerstone-dicom-pmap": { "name": "@ohif/extension-cornerstone-dicom-pmap", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -195,7 +195,7 @@ }, "extensions/cornerstone-dicom-rt": { "name": "@ohif/extension-cornerstone-dicom-rt", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "react-color": "^2.19.3", @@ -215,7 +215,7 @@ }, "extensions/cornerstone-dicom-seg": { "name": "@ohif/extension-cornerstone-dicom-seg", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -238,7 +238,7 @@ }, "extensions/cornerstone-dicom-sr": { "name": "@ohif/extension-cornerstone-dicom-sr", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^4.0.0", @@ -247,10 +247,10 @@ "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.12.0-beta.22", - "@ohif/extension-cornerstone": "3.12.0-beta.22", - "@ohif/extension-measurement-tracking": "3.12.0-beta.22", - "@ohif/ui": "3.12.0-beta.22", + "@ohif/core": "3.12.0-beta.23", + "@ohif/extension-cornerstone": "3.12.0-beta.23", + "@ohif/extension-measurement-tracking": "3.12.0-beta.23", + "@ohif/ui": "3.12.0-beta.23", "dcmjs": "0.43.1", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -260,7 +260,7 @@ }, "extensions/cornerstone-dynamic-volume": { "name": "@ohif/extension-cornerstone-dynamic-volume", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -282,7 +282,7 @@ }, "extensions/default": { "name": "@ohif/extension-default", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/calculate-suv": "^1.1.0", @@ -290,8 +290,8 @@ "lodash.uniqby": "^4.7.0", }, "peerDependencies": { - "@ohif/core": "3.12.0-beta.22", - "@ohif/i18n": "3.12.0-beta.22", + "@ohif/core": "3.12.0-beta.23", + "@ohif/i18n": "3.12.0-beta.23", "dcmjs": "0.43.1", "dicomweb-client": "^0.10.4", "prop-types": "^15.6.2", @@ -305,7 +305,7 @@ }, "extensions/dicom-microscopy": { "name": "@ohif/extension-dicom-microscopy", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -330,7 +330,7 @@ }, "extensions/dicom-pdf": { "name": "@ohif/extension-dicom-pdf", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -347,7 +347,7 @@ }, "extensions/dicom-video": { "name": "@ohif/extension-dicom-video", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -364,20 +364,20 @@ }, "extensions/measurement-tracking": { "name": "@ohif/extension-measurement-tracking", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", - "@ohif/ui": "3.12.0-beta.22", + "@ohif/ui": "3.12.0-beta.23", "@xstate/react": "^3.2.2", "xstate": "^4.10.0", }, "peerDependencies": { "@cornerstonejs/core": "^4.0.0", "@cornerstonejs/tools": "^4.0.0", - "@ohif/core": "3.12.0-beta.22", - "@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.22", - "@ohif/extension-default": "3.12.0-beta.22", - "@ohif/ui": "3.12.0-beta.22", + "@ohif/core": "3.12.0-beta.23", + "@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.23", + "@ohif/extension-default": "3.12.0-beta.23", + "@ohif/ui": "3.12.0-beta.23", "classnames": "^2.3.2", "dcmjs": "0.43.1", "lodash.debounce": "^4.0.8", @@ -390,7 +390,7 @@ }, "extensions/test-extension": { "name": "@ohif/extension-test", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -407,7 +407,7 @@ }, "extensions/tmtv": { "name": "@ohif/extension-tmtv", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -424,7 +424,7 @@ }, "extensions/usAnnotation": { "name": "@ohif/extension-ultrasound-pleura-bline", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -476,7 +476,7 @@ }, "modes/basic-dev-mode": { "name": "@ohif/mode-basic-dev-mode", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -496,7 +496,7 @@ }, "modes/basic-test-mode": { "name": "@ohif/mode-test", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -518,7 +518,7 @@ }, "modes/longitudinal": { "name": "@ohif/mode-longitudinal", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -541,7 +541,7 @@ }, "modes/microscopy": { "name": "@ohif/mode-microscopy", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -553,7 +553,7 @@ }, "modes/preclinical-4d": { "name": "@ohif/mode-preclinical-4d", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", }, @@ -572,7 +572,7 @@ }, "modes/segmentation": { "name": "@ohif/mode-segmentation", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -616,7 +616,7 @@ }, "modes/tmtv": { "name": "@ohif/mode-tmtv", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -637,7 +637,7 @@ }, "modes/usAnnotation": { "name": "@ohif/mode-ultrasound-pleura-bline", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^4.0.0", @@ -676,7 +676,7 @@ }, "platform/app": { "name": "@ohif/app", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -746,7 +746,7 @@ }, "platform/cli": { "name": "@ohif/cli", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "bin": { "ohif-cli": "src/index.js", }, @@ -770,7 +770,7 @@ }, "platform/core": { "name": "@ohif/core", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "dcmjs": "0.43.1", @@ -797,14 +797,14 @@ "@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/core": "^4.0.0", "@cornerstonejs/dicom-image-loader": "^4.0.0", - "@ohif/ui": "3.12.0-beta.22", + "@ohif/ui": "3.12.0-beta.23", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21", }, }, "platform/i18n": { "name": "@ohif/i18n", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@babel/runtime": "^7.20.13", "i18next-locize-backend": "^2.0.0", @@ -829,7 +829,7 @@ }, "platform/ui": { "name": "@ohif/ui", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@testing-library/react": "^13.1.0", "browser-detect": "^0.2.28", @@ -889,7 +889,7 @@ }, "platform/ui-next": { "name": "@ohif/ui-next", - "version": "3.12.0-beta.22", + "version": "3.12.0-beta.23", "dependencies": { "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", From c85425df15e6b79c9239ed9f2c844e957cec6d04 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Tue, 21 Oct 2025 17:29:31 -0300 Subject: [PATCH 4/7] Refactor method --- extensions/cornerstone/src/commandsModule.ts | 97 ++++++++++++++------ 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 6ab4bd15395..70018051719 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -118,6 +118,7 @@ function commandsModule({ hangingProtocolService, syncGroupService, segmentationService, + userAuthenticationService, displaySetService, } = servicesManager.services as AppTypes.Services; @@ -146,45 +147,85 @@ function commandsModule({ }; } - const actions = { - loadSegmentationsForActiveViewport: () => { - const { displaySetService, userAuthenticationService } = servicesManager.services; - - const getDerivedSequences = (displaySetUID: string): DisplaySet[] => { - const currentDs = displaySetService.getDisplaySetByUID(displaySetUID); - const displaySetCache = displaySetService.getDisplaySetCache(); - return Array.from(displaySetCache.values()).filter( - (ds: any): ds is DisplaySet => - (ds?.referencedDisplaySetInstanceUID === displaySetUID || - ds.referencedSeriesInstanceUID === currentDs.SeriesInstanceUID) && - !ds?.isHydrated - ); - }; + /** + * Retrieves derived segmentations (SEG/RTSTRUCT) that are not yet hydrated + * for the given display set UID. + */ + function _getDerivedSegmentations(displaySetUID: string): DisplaySet[] { + const currentDisplaySet = displaySetService.getDisplaySetByUID(displaySetUID); + if (!currentDisplaySet) { + return []; + } + + const displaySetCache = displaySetService.getDisplaySetCache(); + const allDisplaySets = Array.from(displaySetCache.values()); + + return allDisplaySets.filter((ds): ds is DisplaySet => { + if (!ds?.isOverlayDisplaySet || ds?.isHydrated) { + return false; + } + + /** Check if this is a SEG or RTSTRUCT modality */ + const isSegmentationModality = ds.Modality === 'SEG' || ds.Modality === 'RTSTRUCT'; + if (!isSegmentationModality) { + return false; + } + /** Check if this derived display set references the current display set */ + const referencesDisplaySet = + ds.referencedDisplaySetInstanceUID === displaySetUID || + ds.SeriesInstanceUID === currentDisplaySet.SeriesInstanceUID; + + return referencesDisplaySet; + }); + } + + const actions = { + loadSegmentationsForActiveViewport: async () => { const activeViewportId = viewportGridService.getActiveViewportId(); + if (!activeViewportId) { + console.warn('No active viewport found'); + return; + } + const displaySetInstanceUIDs = viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId); + if (!displaySetInstanceUIDs?.length) { + console.warn('No display sets found for active viewport'); + return; + } - const derivedDisplayInstanceUIDs = getDerivedSequences(displaySetInstanceUIDs[0]).map( - ds => ds.displaySetInstanceUID - ); + const primaryDisplaySetUID = displaySetInstanceUIDs[0]; + const derivedDisplaySets = _getDerivedSegmentations(primaryDisplaySetUID); + if (!derivedDisplaySets.length) { + return; + } + + const headers = userAuthenticationService.getAuthorizationHeader(); + + /** Load all segmentations in parallel for better performance */ + const loadPromises = derivedDisplaySets.map(async displaySet => { + try { + /** Load the display set */ + await displaySet.load({ headers }); + + /** Get the representation type */ + const representationType = + displaySet.Modality === 'SEG' + ? Enums.SegmentationRepresentations.Labelmap + : Enums.SegmentationRepresentations.Contour; - derivedDisplayInstanceUIDs.forEach(async displaySetInstanceUID => { - const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); - if (displaySet.Modality === 'SEG' || displaySet.Modality === 'RTSTRUCT') { - const headers = userAuthenticationService.getAuthorizationHeader(); - await displaySet.load({ headers }).catch(err => { - console.warn(`Failed to load display set ${displaySet.displaySetInstanceUID}:`, err); - }); segmentationService.addSegmentationRepresentation(activeViewportId, { segmentationId: displaySet.displaySetInstanceUID, - type: - displaySet.Modality === 'SEG' - ? Enums.SegmentationRepresentations.Labelmap - : Enums.SegmentationRepresentations.Contour, + type: representationType, }); + } catch (error) { + console.error(`Failed to load segmentation ${displaySet.displaySetInstanceUID}:`, error); + /** Continue with other segmentations even if one fails */ } }); + + await Promise.all(loadPromises); }, jumpToMeasurementViewport: ({ annotationUID, measurement }) => { cornerstoneTools.annotation.selection.setAnnotationSelected(annotationUID, true); From 7afd1b3593b9c4b92a9fa851a56d52420d4a3a81 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Tue, 21 Oct 2025 17:31:47 -0300 Subject: [PATCH 5/7] Add load to display set type --- platform/core/src/types/DisplaySet.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/core/src/types/DisplaySet.ts b/platform/core/src/types/DisplaySet.ts index 7eee952ec94..c5ec90038a7 100644 --- a/platform/core/src/types/DisplaySet.ts +++ b/platform/core/src/types/DisplaySet.ts @@ -51,6 +51,13 @@ export type DisplaySet = { isHydrated?: boolean; isRehydratable?: boolean; + + /** + * Loads the display set. + * @param headers - The headers to use for the request. + * @returns A promise that resolves when the display set is loaded. + */ + load: ({ headers }: { headers?: unknown }) => Promise; }; export type DisplaySetSeriesMetadataInvalidatedEvent = { From e3571f0bfba912c80b9ea85cffcd782401cf1236 Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Mon, 27 Oct 2025 07:38:59 -0300 Subject: [PATCH 6/7] Add sr command --- extensions/cornerstone/src/commandsModule.ts | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 70018051719..44665265121 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -181,7 +181,53 @@ function commandsModule({ } const actions = { + loadSRsForActiveViewport: async () => { + console.info('Loading SRs for active viewport...'); + + const activeViewportId = viewportGridService.getActiveViewportId(); + if (!activeViewportId) { + console.warn('No active viewport found'); + return; + } + + const displaySetInstanceUIDs = + viewportGridService.getDisplaySetsUIDsForViewport(activeViewportId); + if (!displaySetInstanceUIDs?.length) { + console.warn('No display sets found for active viewport'); + return; + } + + const primaryDisplaySetUID = displaySetInstanceUIDs[0]; + const derivedDisplaySets = _getDerivedSegmentations(primaryDisplaySetUID); + if (!derivedDisplaySets.length) { + console.warn('No derived SRs found for active viewport'); + return; + } + + const headers = userAuthenticationService.getAuthorizationHeader(); + + /** Load all segmentations in parallel for better performance */ + const loadPromises = derivedDisplaySets.map(async displaySet => { + try { + /** Load the display set */ + await displaySet.load({ headers }); + + /** Hydrate the SR */ + commandsManager.run('hydrateStructuredReport', { + displaySetInstanceUID: displaySet.displaySetInstanceUID, + }); + } catch (error) { + console.error(`Failed to load segmentation ${displaySet.displaySetInstanceUID}:`, error); + /** Continue with other segmentations even if one fails */ + } + }); + + await Promise.all(loadPromises); + console.info('SRs loaded for active viewport.'); + }, loadSegmentationsForActiveViewport: async () => { + console.info('Loading segmentations for active viewport...'); + const activeViewportId = viewportGridService.getActiveViewportId(); if (!activeViewportId) { console.warn('No active viewport found'); @@ -198,6 +244,7 @@ function commandsModule({ const primaryDisplaySetUID = displaySetInstanceUIDs[0]; const derivedDisplaySets = _getDerivedSegmentations(primaryDisplaySetUID); if (!derivedDisplaySets.length) { + console.warn('No derived segmentations found for active viewport'); return; } @@ -226,6 +273,7 @@ function commandsModule({ }); await Promise.all(loadPromises); + console.info('Segmentations loaded for active viewport.'); }, jumpToMeasurementViewport: ({ annotationUID, measurement }) => { cornerstoneTools.annotation.selection.setAnnotationSelected(annotationUID, true); From d198c3c7be8f49df3e48fb37fc5561d516efdfef Mon Sep 17 00:00:00 2001 From: Igor Octaviano Date: Mon, 3 Nov 2025 11:42:30 -0300 Subject: [PATCH 7/7] Add action --- extensions/cornerstone/src/commandsModule.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 339312525cb..66eca755b2f 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -2592,6 +2592,9 @@ function commandsModule({ }; const definitions = { + loadSRsForActiveViewport: { + commandFn: actions.loadSRsForActiveViewport, + }, loadSegmentationsForActiveViewport: { commandFn: actions.loadSegmentationsForActiveViewport, },