fix(segmentation): List surface representations in the segmentation table for 3D views. (#5700)
This was done by using an array of representation types instead of a single type for a panel. The first element of the array is the primary type of the panel, and the rest are secondary types that can also be displayed in the panel. PR feedback: - added test to check number of segments in side panel for 3D only view - fixed jumping to segment in 3D only view - fixed exception when adding contour segment in 3D only view
This commit is contained in:
1 parent
83c9ce0f5f
commit
82e6a18735
27 files changed
+356
-293
No files matched your search
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/adapters": "4.15.7",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@kitware/vtk.js": "34.15.1",
|
||||
"react-color": "2.19.3"
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/adapters": "4.15.7",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@kitware/vtk.js": "34.15.1",
|
||||
"react-color": "2.19.3"
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/tools": "4.15.6",
|
||||
"@cornerstonejs/adapters": "4.15.7",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@cornerstonejs/tools": "4.15.7",
|
||||
"classnames": "2.5.1"
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/tools": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@cornerstonejs/tools": "4.15.7",
|
||||
"classnames": "2.5.1"
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "1.3.0",
|
||||
"@cornerstonejs/codec-openjph": "2.4.7",
|
||||
"@cornerstonejs/dicom-image-loader": "4.15.6",
|
||||
"@cornerstonejs/dicom-image-loader": "4.15.7",
|
||||
"@ohif/core": "3.12.0-beta.121",
|
||||
"@ohif/ui": "3.12.0-beta.121",
|
||||
"dcmjs": "0.45.0",
|
||||
@@ -53,12 +53,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.6",
|
||||
"@cornerstonejs/ai": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/labelmap-interpolation": "4.15.6",
|
||||
"@cornerstonejs/polymorphic-segmentation": "4.15.6",
|
||||
"@cornerstonejs/tools": "4.15.6",
|
||||
"@cornerstonejs/adapters": "4.15.7",
|
||||
"@cornerstonejs/ai": "4.15.7",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@cornerstonejs/labelmap-interpolation": "4.15.7",
|
||||
"@cornerstonejs/polymorphic-segmentation": "4.15.7",
|
||||
"@cornerstonejs/tools": "4.15.7",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "34.15.1",
|
||||
"html2canvas": "1.4.1",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { utils } from '../..';
|
||||
import { useViewportSegmentations } from '../../hooks';
|
||||
import { useMeasurementTracking } from '../../hooks/useMeasurementTracking';
|
||||
import { useViewportDisplaySets } from '../../hooks/useViewportDisplaySets';
|
||||
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
|
||||
|
||||
/**
|
||||
* NavigationComponent provides navigation controls for viewports containing
|
||||
@@ -27,7 +28,11 @@ function NavigationComponent({ viewportId }: { viewportId: string }) {
|
||||
viewportId,
|
||||
});
|
||||
|
||||
const hasSegmentations = segmentationsWithRepresentations.length > 0;
|
||||
const hasSegmentations =
|
||||
segmentationsWithRepresentations.length > 0 &&
|
||||
segmentationsWithRepresentations.some(
|
||||
segmentation => segmentation?.representation?.type !== SegmentationRepresentations.Surface
|
||||
);
|
||||
|
||||
// prefer segment navigation if available
|
||||
const navigationMode = hasSegmentations
|
||||
|
||||
@@ -26,7 +26,7 @@ export const CustomDropdownMenuContent = () => {
|
||||
exportOptions,
|
||||
activeSegmentation,
|
||||
activeSegmentationId,
|
||||
segmentationRepresentationType,
|
||||
segmentationRepresentationTypes,
|
||||
disableEditing,
|
||||
} = useSegmentationTableContext('CustomDropdownMenu');
|
||||
|
||||
@@ -79,7 +79,12 @@ export const CustomDropdownMenuContent = () => {
|
||||
<DropdownMenuContent align="start">
|
||||
{!disableEditing && (
|
||||
<DropdownMenuItem
|
||||
onClick={() => onSegmentationAdd({ segmentationId, segmentationRepresentationType })}
|
||||
onClick={() =>
|
||||
onSegmentationAdd({
|
||||
segmentationId,
|
||||
segmentationRepresentationType: segmentationRepresentationTypes?.[0],
|
||||
})
|
||||
}
|
||||
>
|
||||
<Icons.Add className="text-foreground" />
|
||||
<span className="pl-2">{t('Create New Segmentation')}</span>
|
||||
@@ -97,7 +102,7 @@ export const CustomDropdownMenuContent = () => {
|
||||
</DropdownMenuItem>
|
||||
<ExportSegmentationSubMenuItem
|
||||
segmentationId={segmentationId}
|
||||
segmentationRepresentationType={segmentationRepresentationType}
|
||||
segmentationRepresentationType={segmentationRepresentationTypes?.[0]}
|
||||
allowExport={allowExport}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
configuration={{
|
||||
...props?.configuration,
|
||||
}}
|
||||
segmentationRepresentationType={props?.segmentationRepresentationType}
|
||||
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -38,20 +38,20 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
configuration={{
|
||||
...props?.configuration,
|
||||
}}
|
||||
segmentationRepresentationType={props?.segmentationRepresentationType}
|
||||
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const wrappedPanelSegmentationWithTools = props => {
|
||||
const { t } = useTranslation('SegmentationPanel');
|
||||
const tKey = `${props.segmentationRepresentationType ?? 'Segmentation'} tools`;
|
||||
const tKey = `${props.segmentationRepresentationTypes?.[0] ?? 'Segmentation'} tools`;
|
||||
const tValue = t(tKey);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toolbox
|
||||
buttonSectionId={toolSectionMap[props.segmentationRepresentationType]}
|
||||
buttonSectionId={toolSectionMap[props.segmentationRepresentationTypes?.[0]]}
|
||||
title={tValue}
|
||||
/>
|
||||
<PanelSegmentation
|
||||
@@ -61,7 +61,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
configuration={{
|
||||
...props?.configuration,
|
||||
}}
|
||||
segmentationRepresentationType={props?.segmentationRepresentationType}
|
||||
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -103,7 +103,10 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
component: props =>
|
||||
wrappedPanelSegmentationWithTools({
|
||||
...props,
|
||||
segmentationRepresentationType: SegmentationRepresentations.Labelmap,
|
||||
segmentationRepresentationTypes: [
|
||||
SegmentationRepresentations.Labelmap,
|
||||
SegmentationRepresentations.Surface,
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -114,7 +117,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
component: props =>
|
||||
wrappedPanelSegmentationWithTools({
|
||||
...props,
|
||||
segmentationRepresentationType: SegmentationRepresentations.Contour,
|
||||
segmentationRepresentationTypes: [SegmentationRepresentations.Contour],
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -21,13 +21,14 @@ import {
|
||||
type PanelSegmentationProps = {
|
||||
children?: React.ReactNode;
|
||||
|
||||
// The representation type for this segmentation panel. Undefined means all types.
|
||||
segmentationRepresentationType?: SegmentationRepresentations;
|
||||
// The representation types for this segmentation panel. Undefined means all types.
|
||||
// The first element is the primary type. Additional elements are secondary types.
|
||||
segmentationRepresentationTypes?: SegmentationRepresentations[];
|
||||
} & withAppTypes;
|
||||
|
||||
export default function PanelSegmentation({
|
||||
children,
|
||||
segmentationRepresentationType,
|
||||
segmentationRepresentationTypes,
|
||||
}: PanelSegmentationProps) {
|
||||
const { commandsManager, servicesManager } = useSystem();
|
||||
const {
|
||||
@@ -48,11 +49,20 @@ export default function PanelSegmentation({
|
||||
store => store.selectedSegmentationsForViewport[activeViewportId]
|
||||
);
|
||||
|
||||
const selectedSegmentationIdForType = segmentationRepresentationType
|
||||
? selectedSegmentationsForViewportMap?.get(segmentationRepresentationType)
|
||||
const selectedSegmentationIdForType = segmentationRepresentationTypes
|
||||
? segmentationRepresentationTypes.reduce(
|
||||
(selectedSegmentation, type) =>
|
||||
selectedSegmentation ||
|
||||
(selectedSegmentationsForViewportMap?.has(type)
|
||||
? selectedSegmentationsForViewportMap?.get(type)
|
||||
: undefined),
|
||||
undefined
|
||||
)
|
||||
: segmentationService?.getActiveSegmentation(activeViewportId)?.segmentationId;
|
||||
|
||||
const buttonSection = utilitiesSectionMap[segmentationRepresentationType];
|
||||
const buttonSection = segmentationRepresentationTypes?.[0]
|
||||
? utilitiesSectionMap[segmentationRepresentationTypes[0]]
|
||||
: undefined;
|
||||
|
||||
const { activeToolOptions: activeUtilityOptions } = useActiveToolOptions({
|
||||
buttonSectionId: buttonSection,
|
||||
@@ -129,7 +139,7 @@ export default function PanelSegmentation({
|
||||
commandsManager.run('deleteSegment', { segmentationId, segmentIndex });
|
||||
},
|
||||
onSegmentCopy:
|
||||
segmentationRepresentationType === SegmentationRepresentations.Contour
|
||||
segmentationRepresentationTypes?.[0] === SegmentationRepresentations.Contour
|
||||
? (segmentationId, segmentIndex) => {
|
||||
commandsManager.run('copyContourSegment', {
|
||||
sourceSegmentInfo: { segmentationId, segmentIndex },
|
||||
@@ -227,13 +237,13 @@ export default function PanelSegmentation({
|
||||
disabled,
|
||||
data: segmentationsWithRepresentations,
|
||||
mode: segmentationTableMode,
|
||||
title: `${segmentationRepresentationType ? `${segmentationRepresentationType} ` : ''}Segmentations`,
|
||||
title: `${segmentationRepresentationTypes?.[0] ? `${segmentationRepresentationTypes[0]} ` : ''}Segmentations`,
|
||||
exportOptions,
|
||||
disableEditing,
|
||||
onSegmentationAdd,
|
||||
showAddSegment,
|
||||
renderInactiveSegmentations: handlers.getRenderInactiveSegmentations(),
|
||||
segmentationRepresentationType,
|
||||
segmentationRepresentationTypes,
|
||||
selectedSegmentationIdForType,
|
||||
...handlers,
|
||||
};
|
||||
|
||||
@@ -1271,6 +1271,10 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
viewportIds.forEach(viewportId => {
|
||||
const { viewport } = getEnabledElementByViewportId(viewportId);
|
||||
if (!viewport?.jumpToWorld) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewport.jumpToWorld(world);
|
||||
|
||||
highlightSegment &&
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/tools": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@cornerstonejs/tools": "4.15.7",
|
||||
"@ohif/core": "3.12.0-beta.121",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
|
||||
"@ohif/extension-default": "3.12.0-beta.121",
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/core": "4.15.6",
|
||||
"@cornerstonejs/tools": "4.15.6",
|
||||
"@cornerstonejs/core": "4.15.7",
|
||||
"@cornerstonejs/tools": "4.15.7",
|
||||
"@ohif/core": "3.12.0-beta.121",
|
||||
"@ohif/extension-cornerstone": "3.12.0-beta.121",
|
||||
"@ohif/extension-default": "3.12.0-beta.121",
|
||||
|
||||
Reference in new issue
Block a user