Skip to content

Commit

Permalink
feat(handler): Add handler for unsupported sopclassUIDs (#3601)
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigobasilio2022 authored Aug 16, 2023
1 parent de6976d commit f845f87
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 67 deletions.
38 changes: 20 additions & 18 deletions extensions/default/src/Panels/PanelStudyBrowser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function PanelStudyBrowser({
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaySets?
if (imageId) {
if (imageId && !displaySet?.unsupported) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(
imageId
Expand Down Expand Up @@ -175,20 +175,22 @@ function PanelStudyBrowser({
const displaySet = displaySetService.getDisplaySetByUID(
dSet.displaySetInstanceUID
);
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaysets?
if (imageId) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(
imageId,
dSet.initialViewport
);
if (isMounted.current) {
setThumbnailImageSrcMap(prevState => {
return { ...prevState, ...newImageSrcEntry };
});
if (!displaySet?.unsupported) {
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaysets?
if (imageId) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(
imageId,
dSet.initialViewport
);
if (isMounted.current) {
setThumbnailImageSrcMap(prevState => {
return { ...prevState, ...newImageSrcEntry };
});
}
}
}
});
Expand Down Expand Up @@ -308,7 +310,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
.filter(ds => !ds.excludeFromThumbnailBrowser)
.forEach(ds => {
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
const componentType = _getComponentType(ds.Modality);
const componentType = _getComponentType(ds);

const array =
componentType === 'thumbnail'
Expand Down Expand Up @@ -348,8 +350,8 @@ const thumbnailNoImageModalities = [
'RTDOSE',
];

function _getComponentType(Modality) {
if (thumbnailNoImageModalities.includes(Modality)) {
function _getComponentType(ds) {
if (thumbnailNoImageModalities.includes(ds.Modality) || ds?.unsupported) {
// TODO probably others.
return 'thumbnailNoImage';
}
Expand Down
30 changes: 30 additions & 0 deletions extensions/default/src/getDisplaySetsFromUnsupportedSeries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ImageSet from '@ohif/core/src/classes/ImageSet';
import { DisplaySetMessage, DisplaySetMessageList } from '@ohif/core';
/**
* Default handler for a instance list with an unsupported sopClassUID
*/
export default function getDisplaySetsFromUnsupportedSeries(instances) {
const imageSet = new ImageSet(instances);
const messages = new DisplaySetMessageList();
messages.addMessage(DisplaySetMessage.CODES.UNSUPPORTED_DISPLAYSET);
const instance = instances[0];

imageSet.setAttributes({
displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID
SeriesDate: instance.SeriesDate,
SeriesTime: instance.SeriesTime,
SeriesInstanceUID: instance.SeriesInstanceUID,
StudyInstanceUID: instance.StudyInstanceUID,
SeriesNumber: instance.SeriesNumber || 0,
FrameRate: instance.FrameTime,
SOPClassUID: instance.SOPClassUID,
SeriesDescription: instance.SeriesDescription || '',
Modality: instance.Modality,
numImageFrames: instances.length,
unsupported: true,
SOPClassHandlerId: 'unsupported',
isReconstructable: false,
messages,
});
return [imageSet];
}
6 changes: 6 additions & 0 deletions extensions/default/src/getSopClassHandlerModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ImageSet from '@ohif/core/src/classes/ImageSet';
import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable';
import { id } from './id';
import getDisplaySetMessages from './getDisplaySetMessages';
import getDisplaySetsFromUnsupportedSeries from './getDisplaySetsFromUnsupportedSeries';

const sopClassHandlerName = 'stack';

Expand Down Expand Up @@ -213,6 +214,11 @@ function getSopClassHandlerModule() {
sopClassUids,
getDisplaySetsFromSeries,
},
{
name: 'not-supported-display-sets-handler',
sopClassUids: [],
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries,
},
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function PanelStudyBrowserTracking({
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaysets?
if (imageId) {
if (imageId && !displaySet?.unsupported) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(
imageId
Expand Down Expand Up @@ -212,23 +212,24 @@ function PanelStudyBrowserTracking({
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);

if (options.madeInClient) {
setJumpToDisplaySet(displaySetInstanceUID);
}

const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaysets?
if (imageId) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[displaySetInstanceUID] = await getImageSrc(
imageId
);
setThumbnailImageSrcMap(prevState => {
return { ...prevState, ...newImageSrcEntry };
});
if (!displaySet?.unsupported) {
if (options.madeInClient) {
setJumpToDisplaySet(displaySetInstanceUID);
}

const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
const imageId = imageIds[Math.floor(imageIds.length / 2)];

// TODO: Is it okay that imageIds are not returned here for SR displaysets?
if (imageId) {
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
newImageSrcEntry[displaySetInstanceUID] = await getImageSrc(
imageId
);
setThumbnailImageSrcMap(prevState => {
return { ...prevState, ...newImageSrcEntry };
});
}
}
});
}
Expand Down Expand Up @@ -424,7 +425,7 @@ function _mapDisplaySets(
.filter(ds => !ds.excludeFromThumbnailBrowser)
.forEach(ds => {
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
const componentType = _getComponentType(ds.Modality);
const componentType = _getComponentType(ds);
const numPanes = viewportGridService.getNumViewportPanes();
const viewportIdentificator =
numPanes === 1
Expand Down Expand Up @@ -471,7 +472,7 @@ function _mapDisplaySets(

if (componentType === 'thumbnailNoImage') {
if (dataSource.reject && dataSource.reject.series) {
thumbnailProps.canReject = true;
thumbnailProps.canReject = !ds?.unsupported;
thumbnailProps.onReject = () => {
uiDialogService.create({
id: 'ds-reject-sr',
Expand Down Expand Up @@ -564,8 +565,8 @@ const thumbnailNoImageModalities = [
'OT',
];

function _getComponentType(Modality) {
if (thumbnailNoImageModalities.includes(Modality)) {
function _getComponentType(ds) {
if (thumbnailNoImageModalities.includes(ds.Modality) || ds?.unsupported) {
return 'thumbnailNoImage';
}

Expand Down
4 changes: 4 additions & 0 deletions platform/app/src/components/ViewportGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ function ViewerViewportGrid(props) {
displaySetService.getDisplaySetByUID(displaySetInstanceUID) || {}
);
}
).filter(
(displaySet) => {
return !displaySet?.unsupported;
}
);

const ViewportComponent = _getViewportComponent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class DisplaySetMessage {
INCONSISTENT_COMPONENTS: 10,
INCONSISTENT_ORIENTATIONS: 11,
INCONSISTENT_POSITION_INFORMATION: 12,
UNSUPPORTED_DISPLAYSET: 13,
};

constructor(id: number) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type DisplaySet = {
StudyInstanceUID: string;
SeriesInstanceUID?: string;
numImages?: number;
unsupported?: boolean;
};

const displaySetCache = new Map<string, DisplaySet>();
Expand Down Expand Up @@ -48,6 +49,7 @@ export default class DisplaySetService extends PubSubService {
};

public activeDisplaySets = [];
public unsuportedSOPClassHandler;
extensionManager: ExtensionManager;

protected activeDisplaySetsMap = new Map<string, DisplaySet>();
Expand All @@ -58,6 +60,8 @@ export default class DisplaySetService extends PubSubService {

constructor() {
super(EVENTS);
this.unsuportedSOPClassHandler =
'@ohif/extension-default.sopClassHandlerModule.not-supported-display-sets-handler';
}

public init(extensionManager, SOPClassHandlerIds): void {
Expand Down Expand Up @@ -85,6 +89,14 @@ export default class DisplaySetService extends PubSubService {
});
}

/**
* Sets the handler for unsupported sop classes
* @param sopClassHandlerUID
*/
public setUnsuportedSOPClassHandler(sopClassHandler) {
this.unsuportedSOPClassHandler = sopClassHandler;
}

/**
* Adds new display sets directly, as specified.
* Use this function when the display sets are created externally directly
Expand Down Expand Up @@ -256,6 +268,47 @@ export default class DisplaySetService extends PubSubService {
this.activeDisplaySetsMap.clear();
}

/**
* This function hides the old makeDisplaySetForInstances function to first
* separate the instances by sopClassUID so each call have only instances
* with the same sopClassUID, to avoid a series composed by different
* sopClassUIDs be filtered inside one of the SOPClassHandler functions and
* didn't appear in the series list.
* @param instancesSrc
* @param settings
* @returns
*/
public makeDisplaySetForInstances(
instancesSrc: InstanceMetadata[],
settings
): DisplaySet[] {
// creating a sopClassUID list and for each sopClass associate its respective
// instance list
const instancesForSetSOPClasses = instancesSrc.reduce(
(sopClassList, instance) => {
if (!(instance.SOPClassUID in sopClassList)) {
sopClassList[instance.SOPClassUID] = [];
}
sopClassList[instance.SOPClassUID].push(instance);
return sopClassList;
},
{}
);
// for each sopClassUID, call the old makeDisplaySetForInstances with a
// instance list composed only by instances with the same sopClassUID and
// accumulate the displaySets in the variable allDisplaySets
const sopClasses = Object.keys(instancesForSetSOPClasses);
let allDisplaySets = [];
sopClasses.forEach(sopClass => {
const displaySets = this._makeDisplaySetForInstances(
instancesForSetSOPClasses[sopClass],
settings
);
allDisplaySets = [...allDisplaySets, ...displaySets];
});
return allDisplaySets;
}

/**
* Creates new display sets for the instances contained in instancesSrc
* according to the sop class handlers registered.
Expand All @@ -272,7 +325,7 @@ export default class DisplaySetService extends PubSubService {
* @param settings are settings to add
* @returns Array of the display sets added.
*/
public makeDisplaySetForInstances(
private _makeDisplaySetForInstances(
instancesSrc: InstanceMetadata[],
settings
): DisplaySet[] {
Expand Down Expand Up @@ -355,6 +408,26 @@ export default class DisplaySetService extends PubSubService {
allDisplaySets.push(...displaySets);
}
}
// applying the default sopClassUID handler
if (allDisplaySets.length === 0) {
// applying hp-defined viewport settings to the displaysets
const handler = this.extensionManager.getModuleEntry(
this.unsuportedSOPClassHandler
);
const displaySets = handler.getDisplaySetsFromSeries(instances);
if (displaySets?.length) {
displaySets.forEach(ds => {
Object.keys(settings).forEach(key => {
ds[key] = settings[key];
});
});

this._addDisplaySetsToCache(displaySets);
this._addActiveDisplaySets(displaySets);

allDisplaySets.push(...displaySets);
}
}
return allDisplaySets;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ interface IDisplaySet {
StudyInstanceUID: string;
SeriesInstanceUID?: string;
SeriesNumber?: string;
unsupported?: boolean;
}

export default IDisplaySet;
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,13 @@ export default class HangingProtocolService extends PubSubService {
}

getViewportsRequireUpdate(viewportIndex, displaySetInstanceUID) {
const { displaySetService } = this._servicesManager.services;
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
if (displaySet?.unsupported) {
throw new Error('Unsupported displaySet');
}
const newDisplaySetInstanceUID = displaySetInstanceUID;
const protocol = this.protocol;
const protocolStage = protocol.stages[this.stageIndex];
Expand Down Expand Up @@ -1431,7 +1438,7 @@ export default class HangingProtocolService extends PubSubService {
}

const studyDisplaySets = this.displaySets.filter(
it => it.StudyInstanceUID === study.StudyInstanceUID
it => it.StudyInstanceUID === study.StudyInstanceUID && !it?.unsupported
);

const studyMatchDetails = this.protocolEngine.findMatch(
Expand Down
3 changes: 2 additions & 1 deletion platform/i18n/src/locales/en-US/Messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"9": "DisplaySet has inconsistent dimensions between frames.",
"10": "DisplaySet has frames with inconsistent number of components.",
"11": "DisplaySet has frames with inconsistent orientations.",
"12": "DisplaySet has inconsistent position information."
"12": "DisplaySet has inconsistent position information.",
"13": "Unsupported displaySet."
}
3 changes: 2 additions & 1 deletion platform/i18n/src/locales/pt-BR/Messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"9": "Série possui dimensões inconsistentes entre frames.",
"10": "Série possui frames com componentes inconsistentes.",
"11": "Série possui frames com orientações inconsistentes.",
"12": "Série possui informação de posição inconsistentes."
"12": "Série possui informação de posição inconsistentes.",
"13": "Série não suportada."
}
Loading

0 comments on commit f845f87

Please sign in to comment.