ohif-viewer/extensions/cornerstone/src/utils/toggleVOISliceSync.ts
Belbin-GK 1aa4431121
fix: skip VOI sync for empty viewports (#5599)
Co-authored-by: trenser-belbin <belbin.kunjumon@prenuvo.com>
2025-12-03 15:36:30 -05:00

104 lines
3.2 KiB
TypeScript

import { DisplaySetService, ViewportGridService } from '@ohif/core';
const VOI_SYNC_NAME = 'VOI_SYNC';
const getSyncId = modality => `${VOI_SYNC_NAME}_${modality}`;
export default function toggleVOISliceSync({
servicesManager,
viewports: providedViewports,
syncId,
}: withAppTypes) {
const { syncGroupService, viewportGridService, displaySetService, cornerstoneViewportService } =
servicesManager.services;
const viewports =
providedViewports || groupViewportsByModality(viewportGridService, displaySetService);
// Todo: right now we don't have a proper way to define specific
// viewports to add to synchronizers, and right now it is global or not
// after we do that, we should do fine grained control of the synchronizers
// we can apply voi sync within each modality group
for (const [modality, modalityViewports] of Object.entries(viewports)) {
const syncIdToUse = syncId || getSyncId(modality);
const someViewportHasSync = modalityViewports.some(viewport => {
const syncStates = syncGroupService.getSynchronizersForViewport(
viewport.viewportOptions.viewportId
);
const imageSync = syncStates.find(syncState => syncState.id === syncIdToUse);
return !!imageSync;
});
if (someViewportHasSync) {
return disableSync(modalityViewports, syncIdToUse, servicesManager);
}
// create synchronization group and add the modalityViewports to it.
modalityViewports.forEach(gridViewport => {
const { viewportId } = gridViewport.viewportOptions;
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!viewport) {
return;
}
syncGroupService.addViewportToSyncGroup(viewportId, viewport.getRenderingEngine().id, {
type: 'voi',
id: syncIdToUse as string,
source: true,
target: true,
});
});
}
}
function disableSync(modalityViewports, syncId, servicesManager: AppTypes.ServicesManager) {
const { syncGroupService, cornerstoneViewportService } = servicesManager.services;
const viewports = modalityViewports;
viewports.forEach(gridViewport => {
const { viewportId } = gridViewport.viewportOptions;
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!viewport) {
return;
}
syncGroupService.removeViewportFromSyncGroup(
viewport.id,
viewport.getRenderingEngine().id,
syncId
);
});
}
function groupViewportsByModality(
viewportGridService: ViewportGridService,
displaySetService: DisplaySetService
) {
const { viewports } = viewportGridService.getState();
const viewportsArray = [...viewports.values()];
// group the viewports by modality
return viewportsArray.reduce((acc, viewport) => {
const { displaySetInstanceUIDs } = viewport;
// Todo: add proper fusion support
// Fix: Skip processing if the viewport is empty.
if (!displaySetInstanceUIDs?.length) {
return acc;
}
const displaySetInstanceUID = displaySetInstanceUIDs[0];
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
const modality = displaySet.Modality;
if (!acc[modality]) {
acc[modality] = [];
}
acc[modality].push(viewport);
return acc;
}, {});
}