Skip to content

Commit

Permalink
feat(advanced-roi-tools): new tools and icon updates and overlay bug …
Browse files Browse the repository at this point in the history
…fixes (#4014)
  • Loading branch information
IbrahimCSAE authored Apr 5, 2024
1 parent 78fd8cc commit cea27d4
Show file tree
Hide file tree
Showing 52 changed files with 662 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ function CustomizableViewportOverlay({
'cornerstoneOverlayBottomRight'
);

const instance = useMemo(() => {
const instances = useMemo(() => {
if (viewportData != null) {
return _getViewportInstance(viewportData, imageIndex);
return _getViewportInstances(viewportData);
} else {
return null;
}
Expand Down Expand Up @@ -177,7 +177,7 @@ function CustomizableViewportOverlay({
formatTime: formatDICOMTime,
formatNumberPrecision,
},
instance,
instance: instances ? instances[item?.instanceIndex] : null,
voi,
scale,
instanceNumber,
Expand Down Expand Up @@ -207,7 +207,7 @@ function CustomizableViewportOverlay({
viewportId,
servicesManager,
customizationService,
instance,
instances,
voi,
scale,
instanceNumber,
Expand All @@ -217,13 +217,15 @@ function CustomizableViewportOverlay({
const getContent = useCallback(
(customization, defaultItems, keyPrefix) => {
const items = customization?.items ?? defaultItems;

return (
<>
{items.map((item, index) => (
<div key={`${keyPrefix}_${index}`}>
{item?.condition
? item.condition({ instance, formatters: { formatDate: formatDICOMDate } })
? item.condition({
instance: instances ? instances[item?.instanceIndex] : null,
formatters: { formatDate: formatDICOMDate },
})
? _renderOverlayItem(item)
: null
: _renderOverlayItem(item)}
Expand All @@ -235,35 +237,50 @@ function CustomizableViewportOverlay({
[_renderOverlayItem]
);

const studyDateItem = {
id: 'StudyDate',
customizationType: 'ohif.overlayItem',
label: '',
title: 'Study date',
condition: ({ instance }) => instance && instance.StudyDate,
contentF: ({ instance, formatters: { formatDate } }) => formatDate(instance.StudyDate),
};

const seriesDescriptionItem = {
id: 'SeriesDescription',
customizationType: 'ohif.overlayItem',
label: '',
title: 'Series description',
attribute: 'SeriesDescription',
condition: ({ instance }) => {
return instance && instance.SeriesDescription;
},
};

const topLeftItems = instances
? instances
.map((instance, index) => {
return [
{
...studyDateItem,
instanceIndex: index,
},
{
...seriesDescriptionItem,
instanceIndex: index,
},
];
})
.flat()
: [];

return (
<ViewportOverlay
topLeft={
/**
* Inline default overlay items for a more standard expansion
*/
getContent(
topLeftCustomization,
[
{
id: 'StudyDate',
customizationType: 'ohif.overlayItem',
label: '',
title: 'Study date',
condition: ({ instance }) => instance && instance.StudyDate,
contentF: ({ instance, formatters: { formatDate } }) =>
formatDate(instance.StudyDate),
},
{
id: 'SeriesDescription',
customizationType: 'ohif.overlayItem',
label: '',
title: 'Series description',
attribute: 'SeriesDescription',
condition: ({ instance }) => instance && instance.SeriesDescription,
},
],
'topLeftOverlayItem'
)
getContent(topLeftCustomization, [...topLeftItems], 'topLeftOverlayItem')
}
topRight={getContent(topRightCustomization, [], 'topRightOverlayItem')}
bottomLeft={getContent(
Expand Down Expand Up @@ -298,18 +315,26 @@ function CustomizableViewportOverlay({
);
}

function _getViewportInstance(viewportData, imageIndex) {
let imageId = null;
function _getViewportInstances(viewportData) {
const imageIds = [];
if (viewportData.viewportType === Enums.ViewportType.STACK) {
imageId = viewportData.data.imageIds[imageIndex];
imageIds.push(viewportData.data.imageIds[0]);
} else if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC) {
const volumes = viewportData.data;
if (volumes && volumes.length == 1) {
const volume = volumes[0];
imageId = volume.imageIds[imageIndex];
}
volumes.forEach(volume => {
if (!volume?.imageIds) {
return;
}
imageIds.push(volume.imageIds[0]);
});
}
return imageId ? metaData.get('instance', imageId) || {} : {};
const instances = [];

imageIds.forEach(imageId => {
const instance = metaData.get('instance', imageId) || {};
instances.push(instance);
});
return instances;
}

const getInstanceNumber = (viewportData, viewportId, imageIndex, cornerstoneViewportService) => {
Expand All @@ -323,7 +348,8 @@ const getInstanceNumber = (viewportData, viewportId, imageIndex, cornerstoneView
instanceNumber = _getInstanceNumberFromVolume(
viewportData,
viewportId,
cornerstoneViewportService
cornerstoneViewportService,
imageIndex
);
break;
}
Expand Down Expand Up @@ -354,15 +380,20 @@ function _getInstanceNumberFromStack(viewportData, imageIndex) {
// Since volume viewports can be in any view direction, they can render
// a reconstructed image which don't have imageIds; therefore, no instance and instanceNumber
// Here we check if viewport is in the acquisition direction and if so, we get the instanceNumber
function _getInstanceNumberFromVolume(viewportData, viewportId, cornerstoneViewportService) {
const volumes = viewportData.volumes;
function _getInstanceNumberFromVolume(
viewportData,
viewportId,
cornerstoneViewportService,
imageIndex
) {
const volumes = viewportData.data;

// Todo: support fusion of acquisition plane which has instanceNumber
if (!volumes || volumes.length > 1) {
if (!volumes) {
return;
}

const volume = volumes[0];
// Todo: support fusion of acquisition plane which has instanceNumber
const { volume } = volumes[0];
const { direction, imageIds } = volume;

const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
Expand Down Expand Up @@ -445,11 +476,15 @@ function InstanceNumberOverlayItem({
className="overlay-item flex flex-row"
style={{ color: (customization && customization.color) || undefined }}
>
<span className="mr-1 shrink-0">I:</span>
<span>
{instanceNumber !== undefined && instanceNumber !== null
? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})`
: `${imageIndex + 1}/${numberOfSlices}`}
{instanceNumber !== undefined && instanceNumber !== null ? (
<>
<span className="mr-1 shrink-0">I:</span>
<span>{`${instanceNumber} (${imageIndex + 1}/${numberOfSlices})`}</span>
</>
) : (
`${imageIndex + 1}/${numberOfSlices}`
)}
</span>
</div>
);
Expand Down
20 changes: 20 additions & 0 deletions extensions/cornerstone/src/getToolbarModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,26 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
}
},
},
{
name: 'evaluate.isUS',
evaluate: ({ viewportId, disabledText }) => {
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);

if (!displaySetUIDs?.length) {
return;
}

const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
const isUS = displaySets.some(displaySet => displaySet.Modality === 'US');
if (!isUS) {
return {
disabled: true,
className: '!text-common-bright ohif-disabled',
disabledText: disabledText ?? 'Not available on the current viewport',
};
}
},
},
{
name: 'evaluate.viewportProperties.toggle',
evaluate: ({ viewportId, button }) => {
Expand Down
18 changes: 15 additions & 3 deletions extensions/cornerstone/src/initCornerstoneTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
ProbeTool,
AngleTool,
CobbAngleTool,
PlanarFreehandROITool,
MagnifyTool,
CrosshairsTool,
SegmentationDisplayTool,
Expand All @@ -28,6 +27,11 @@ import {
CircleScissorsTool,
RectangleScissorsTool,
SphereScissorsTool,
AdvancedMagnifyTool,
UltrasoundDirectionalTool,
PlanarFreehandROITool,
SplineROITool,
LivewireContourTool,
} from '@cornerstonejs/tools';

import CalibrationLineTool from './tools/CalibrationLineTool';
Expand Down Expand Up @@ -55,7 +59,6 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(DragProbeTool);
addTool(AngleTool);
addTool(CobbAngleTool);
addTool(PlanarFreehandROITool);
addTool(MagnifyTool);
addTool(CrosshairsTool);
addTool(SegmentationDisplayTool);
Expand All @@ -66,6 +69,11 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(RectangleScissorsTool);
addTool(SphereScissorsTool);
addTool(ImageOverlayViewerTool);
addTool(AdvancedMagnifyTool);
addTool(UltrasoundDirectionalTool);
addTool(PlanarFreehandROITool);
addTool(SplineROITool);
addTool(LivewireContourTool);

// Modify annotation tools to use dashed lines on SR
const annotationStyle = {
Expand Down Expand Up @@ -100,7 +108,6 @@ const toolNames = {
Bidirectional: BidirectionalTool.toolName,
Angle: AngleTool.toolName,
CobbAngle: CobbAngleTool.toolName,
PlanarFreehandROI: PlanarFreehandROITool.toolName,
Magnify: MagnifyTool.toolName,
Crosshairs: CrosshairsTool.toolName,
SegmentationDisplay: SegmentationDisplayTool.toolName,
Expand All @@ -111,6 +118,11 @@ const toolNames = {
RectangleScissors: RectangleScissorsTool.toolName,
SphereScissors: SphereScissorsTool.toolName,
ImageOverlayViewer: ImageOverlayViewerTool.toolName,
AdvancedMagnify: AdvancedMagnifyTool.toolName,
UltrasoundDirectional: UltrasoundDirectionalTool.toolName,
SplineROI: SplineROITool.toolName,
LivewireContour: LivewireContourTool.toolName,
PlanarFreehandROI: PlanarFreehandROITool.toolName,
};

export { toolNames };
9 changes: 1 addition & 8 deletions extensions/default/src/Toolbar/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ export function Toolbar({ servicesManager }) {
/>
);

return (
<div
key={id}
className="mr-1"
>
{tool}
</div>
);
return <div key={id}>{tool}</div>;
})}
</>
);
Expand Down
5 changes: 5 additions & 0 deletions modes/basic-test-mode/src/initToolGroups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ function initDefaultToolGroup(extensionManager, toolGroupService, commandsManage
{ toolName: toolNames.Angle },
{ toolName: toolNames.Magnify },
{ toolName: toolNames.SegmentationDisplay },
{ toolName: toolNames.AdvancedMagnify },
{ toolName: toolNames.UltrasoundDirectional },
{ toolName: toolNames.PlanarFreehandROI },
{ toolName: toolNames.SplineROI },
{ toolName: toolNames.LivewireContour },
],
// enabled
enabled: [{ toolName: toolNames.ImageOverlayViewer }],
Expand Down
20 changes: 18 additions & 2 deletions modes/basic-test-mode/src/moreTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const moreTools = [
evaluate: 'evaluate.viewportProperties.toggle',
}),
createButton({
id: 'Probe',
id: 'DragProbe',
icon: 'tool-probe',
label: 'Probe',
tooltip: 'Probe',
Expand Down Expand Up @@ -173,11 +173,27 @@ const moreTools = [
}),
createButton({
id: 'TagBrowser',
icon: 'list-bullets',
icon: 'dicom-tag-browser',
label: 'Dicom Tag Browser',
tooltip: 'Dicom Tag Browser',
commands: 'openDICOMTagViewer',
}),
createButton({
id: 'AdvancedMagnify',
icon: 'icon-tool-loupe',
label: 'Loupe',
tooltip: 'Loupe',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'UltrasoundDirectionalTool',
icon: 'icon-tool-ultrasound-bidirectional',
label: 'Ultrasound Directional',
tooltip: 'Ultrasound Directional',
commands: setToolActiveToolbar,
evaluate: ['evaluate.cornerstoneTool', 'evaluate.isUS'],
}),
],
},
},
Expand Down
24 changes: 24 additions & 0 deletions modes/basic-test-mode/src/toolbarButtons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ const toolbarButtons: Button[] = [
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'PlanarFreehandROI',
icon: 'icon-tool-freehand-roi',
label: 'Freehand ROI',
tooltip: 'Freehand ROI',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'SplineROI',
icon: 'icon-tool-spline-roi',
label: 'Spline ROI',
tooltip: 'Spline ROI',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
createButton({
id: 'LivewireContour',
icon: 'icon-tool-livewire',
label: 'Livewire tool',
tooltip: 'Livewire tool',
commands: setToolActiveToolbar,
evaluate: 'evaluate.cornerstoneTool',
}),
],
},
},
Expand Down
Loading

0 comments on commit cea27d4

Please sign in to comment.