Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions extensions/cornerstone/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
import { EasingFunctionEnum } from './utils/transitions';

const { DefaultHistoryMemo } = csUtils.HistoryMemo;
Expand Down Expand Up @@ -117,6 +118,7 @@ function commandsModule({
hangingProtocolService,
syncGroupService,
segmentationService,
userAuthenticationService,
displaySetService,
} = servicesManager.services as AppTypes.Services;

Expand Down Expand Up @@ -145,7 +147,86 @@ function commandsModule({
};
}

/**
* 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 primaryDisplaySetUID = displaySetInstanceUIDs[0];
const derivedDisplaySets = _getDerivedSegmentations(primaryDisplaySetUID);
if (!derivedDisplaySets.length) {
return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do a console.warn here too?

}

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;

segmentationService.addSegmentationRepresentation(activeViewportId, {
segmentationId: displaySet.displaySetInstanceUID,
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);
const { metadata } = measurement;
Expand Down Expand Up @@ -2260,6 +2341,9 @@ function commandsModule({
};

const definitions = {
loadSegmentationsForActiveViewport: {
commandFn: actions.loadSegmentationsForActiveViewport,
},
// The command here is to show the viewer context menu, as being the
// context menu
showCornerstoneContextMenu: {
Expand Down
7 changes: 7 additions & 0 deletions platform/core/src/types/DisplaySet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>;
};

export type DisplaySetSeriesMetadataInvalidatedEvent = {
Expand Down