Skip to content

Commit

Permalink
fix: 🐛 Proper error handling for derived display sets (#1708)
Browse files Browse the repository at this point in the history
* fix: 🐛 Proper error handling for derived display sets

* Revert idc.js change
  • Loading branch information
JamesAPetts authored May 4, 2020
1 parent 9ea37a2 commit 5b20d8f
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 109 deletions.
2 changes: 1 addition & 1 deletion extensions/cornerstone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"cornerstone-math": "^0.1.8",
"cornerstone-tools": "4.12.5",
"cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "^0.12.2",
"dcmjs": "^0.12.3",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
"prop-types": "^15.6.2",
Expand Down
2 changes: 1 addition & 1 deletion extensions/dicom-html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"peerDependencies": {
"@ohif/core": "^0.50.0",
"dcmjs": "^0.12.2",
"dcmjs": "^0.12.3",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
Expand Down
2 changes: 1 addition & 1 deletion extensions/dicom-rt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.0.9",
"dcmjs": "^0.12.2",
"dcmjs": "^0.12.3",
"prop-types": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
Expand Down
71 changes: 0 additions & 71 deletions extensions/dicom-segmentation/src/OHIFDicomSegSopClassHandler.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const SegmentationPanel = ({
activeIndex,
isOpen,
onSegItemClick,
UINotificationService,
}) => {
/*
* TODO: wrap get/set interactions with the cornerstoneTools
Expand Down Expand Up @@ -115,7 +116,11 @@ const SegmentationPanel = ({
firstImageId,
activeViewport
);
const segmentList = getSegmentList(labelmap3D, firstImageId, brushStackState);
const segmentList = getSegmentList(
labelmap3D,
firstImageId,
brushStackState
);
setState(state => ({
...state,
brushStackState,
Expand All @@ -130,7 +135,14 @@ const SegmentationPanel = ({
segmentList: [],
}));
}
}, [studies, viewports, activeIndex, getLabelmapList, getSegmentList, state.selectedSegmentation]);
}, [
studies,
viewports,
activeIndex,
getLabelmapList,
getSegmentList,
state.selectedSegmentation,
]);

/* Handle open/closed panel behaviour */
useEffect(() => {
Expand Down Expand Up @@ -170,7 +182,8 @@ const SegmentationPanel = ({
studies,
displaySet,
firstImageId,
brushStackState.activeLabelmapIndex
brushStackState.activeLabelmapIndex,
UINotificationService
);
updateState('selectedSegmentation', activatedLabelmapIndex);
},
Expand Down Expand Up @@ -424,7 +437,9 @@ const SegmentationPanel = ({
<h3>Segmentations</h3>
<div className="segmentations">
<SegmentationSelect
value={state.labelmapList.find(i => i.value === state.selectedSegmentation)}
value={state.labelmapList.find(
i => i.value === state.selectedSegmentation
)}
formatOptionLabel={SegmentationItem}
options={state.labelmapList}
/>
Expand Down Expand Up @@ -509,7 +524,8 @@ const _setActiveLabelmap = async (
studies,
displaySet,
firstImageId,
activeLabelmapIndex
activeLabelmapIndex,
UINotificationService
) => {
if (displaySet.labelmapIndex === activeLabelmapIndex) {
log.warn(`${activeLabelmapIndex} is already the active labelmap`);
Expand All @@ -519,7 +535,22 @@ const _setActiveLabelmap = async (
if (!displaySet.isLoaded) {
// What props does this expect `viewportSpecificData` to have?
// TODO: Should this return the `labelmapIndex`?
await displaySet.load(viewportSpecificData, studies);

const loadPromise = displaySet.load(viewportSpecificData, studies);

loadPromise.catch(error => {
UINotificationService.show({
title: 'DICOM Segmentation Loader',
message: error.message,
type: 'error',
autoClose: false,
});

// Return old index.
return activeLabelmapIndex;
});

await loadPromise;
}

const { state } = cornerstoneTools.getModule('segmentation');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MODULE_TYPES, utils } from '@ohif/core';
import loadSegmentation from './loadSegmentation';

// TODO: Should probably use dcmjs for this
const SOP_CLASS_UIDS = {
DICOM_SEG: '1.2.840.10008.5.1.4.1.1.66.4',
};

const sopClassUIDs = Object.values(SOP_CLASS_UIDS);

export default function getSopClassHandlerModule({ servicesManager }) {
// TODO: Handle the case where there is more than one SOP Class Handler for the
// same SOP Class.
return {
id: 'OHIFDicomSegSopClassHandler',
type: MODULE_TYPES.SOP_CLASS_HANDLER,
sopClassUIDs,
getDisplaySetFromSeries: function(
series,
study,
dicomWebClient,
authorizationHeaders
) {
const instance = series.getFirstInstance();
const metadata = instance.getData().metadata;

const {
SeriesDate,
SeriesTime,
SeriesDescription,
FrameOfReferenceUID,
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = metadata;

const segDisplaySet = {
Modality: 'SEG',
displaySetInstanceUID: utils.guid(),
wadoRoot: study.getData().wadoRoot,
wadoUri: instance.getData().wadouri,
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
FrameOfReferenceUID,
authorizationHeaders,
metadata,
isDerived: true,
referencedDisplaySetUID: null, // Assigned when loaded.
labelmapIndex: null, // Assigned when loaded.
isLoaded: false,
SeriesDate,
SeriesTime,
SeriesDescription,
};

segDisplaySet.load = function(referencedDisplaySet, studies) {
return loadSegmentation(segDisplaySet, referencedDisplaySet, studies);
};

return segDisplaySet;
},
};
}
16 changes: 10 additions & 6 deletions extensions/dicom-segmentation/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import init from './init.js';
import toolbarModule from './toolbarModule.js';
import sopClassHandlerModule from './OHIFDicomSegSopClassHandler.js';
import getSopClassHandlerModule from './getOHIFDicomSegSopClassHandler.js';
import SegmentationPanel from './components/SegmentationPanel/SegmentationPanel.js';

export default {
Expand All @@ -23,14 +23,20 @@ export default {
getToolbarModule({ servicesManager }) {
return toolbarModule;
},
getPanelModule({ commandsManager }) {
getPanelModule({ commandsManager, servicesManager }) {
const ExtendedSegmentationPanel = props => {
const segItemClickHandler = segData => {
commandsManager.runCommand('jumpToImage', segData);
};

const { UINotificationService } = servicesManager.services;

return (
<SegmentationPanel {...props} onSegItemClick={segItemClickHandler} />
<SegmentationPanel
{...props}
onSegItemClick={segItemClickHandler}
UINotificationService={UINotificationService}
/>
);
};

Expand Down Expand Up @@ -72,7 +78,5 @@ export default {
defaultContext: ['VIEWER'],
};
},
getSopClassHandlerModule({ servicesManager }) {
return sopClassHandlerModule;
},
getSopClassHandlerModule,
};
41 changes: 24 additions & 17 deletions extensions/dicom-segmentation/src/loadSegmentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,35 @@ export default async function loadSegmentation(
referencedDisplaySet.SeriesInstanceUID
);

const results = _parseSeg(segArrayBuffer, imageIds);
return new Promise((resolve, reject) => {
let results;

try {
results = _parseSeg(segArrayBuffer, imageIds);
} catch (error) {
segDisplaySet.isLoaded = false;
reject(error);
}

if (!results) {
throw new Error('Fractional segmentations are not yet supported');
}
const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
const { setters } = cornerstoneTools.getModule('segmentation');

const { labelmapBuffer, segMetadata, segmentsOnFrame } = results;
const { setters } = cornerstoneTools.getModule('segmentation');
// TODO: Could define a color LUT based on colors in the SEG.
const labelmapIndex = _getNextLabelmapIndex(imageIds[0]);

// TODO: Could define a color LUT based on colors in the SEG.
const labelmapIndex = _getNextLabelmapIndex(imageIds[0]);
setters.labelmap3DByFirstImageId(
imageIds[0],
labelmapBuffer,
labelmapIndex,
segMetadata,
imageIds.length,
segmentsOnFrame
);

setters.labelmap3DByFirstImageId(
imageIds[0],
labelmapBuffer,
labelmapIndex,
segMetadata,
imageIds.length,
segmentsOnFrame
);
segDisplaySet.labelmapIndex = labelmapIndex;

segDisplaySet.labelmapIndex = labelmapIndex;
resolve(labelmapIndex);
});
}

function _getNextLabelmapIndex(firstImageId) {
Expand Down
10 changes: 7 additions & 3 deletions platform/core/src/utils/loadAndCacheDerivedDisplaySets.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,20 @@ import studyMetadataManager from './studyMetadataManager';
const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;

const promises = [];

const studyMetadata = studyMetadataManager.get(StudyInstanceUID);

if (!studyMetadata) {
return;
return promises;
}

const derivedDisplaySets = studyMetadata.getDerivedDatasets({
referencedSeriesInstanceUID: SeriesInstanceUID,
});

if (!derivedDisplaySets.length) {
return;
return promises;
}

// Filter by type
Expand Down Expand Up @@ -100,8 +102,10 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
}
});

recentDisplaySet.load(referencedDisplaySet, studies);
promises.push(recentDisplaySet.load(referencedDisplaySet, studies));
});

return promises;
};

export default loadAndCacheDerivedDisplaySets;
2 changes: 1 addition & 1 deletion platform/ui/src/components/snackbar/Snackbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@

.sb-message {
font-size: 14px;
word-break: break-all;
word-break: normal;
}

.sb-item {
Expand Down
Loading

0 comments on commit 5b20d8f

Please sign in to comment.