feat(segmentation): segment statistics, labelmap interpolation and segment bidirectional (#4865)
This commit is contained in:
1 parent
694f3e9611
commit
ec79b5523e
73 files changed
+3603
-1563
No files matched your search
@@ -1,20 +1,26 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import React, { ReactNode, useState, Children, isValidElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PanelSection } from '../PanelSection';
|
||||
import { SegmentationTableProvider, SegmentationTableContext } from './SegmentationTableContext';
|
||||
import {
|
||||
SegmentationTableProvider,
|
||||
SegmentationTableContextType,
|
||||
ViewportSegmentationInfo,
|
||||
} from './contexts';
|
||||
import { SegmentationSegments } from './SegmentationSegments';
|
||||
import { SegmentStatistics } from './SegmentStatistics';
|
||||
import { SegmentationTableConfig } from './SegmentationTableConfig';
|
||||
import { AddSegmentRow } from './AddSegmentRow';
|
||||
import { AddSegmentationRow } from './AddSegmentationRow';
|
||||
import { SegmentationSelectorHeader } from './SegmentationSelectorHeader';
|
||||
import { SegmentationHeader } from './SegmentationHeader';
|
||||
import { SegmentationCollapsed } from './SegmentationCollapsed';
|
||||
import { SegmentationExpanded } from './SegmentationExpanded';
|
||||
import Icons from '../Icons';
|
||||
|
||||
interface SegmentationTableProps extends SegmentationTableContext {
|
||||
disabled?: boolean;
|
||||
// Only include props that aren't part of the context
|
||||
interface SegmentationTableProps extends Omit<SegmentationTableContextType, 'setShowConfig'> {
|
||||
title?: string;
|
||||
children?: ReactNode;
|
||||
setShowConfig?: (value: boolean) => void;
|
||||
}
|
||||
|
||||
interface SegmentationTableComponent extends React.FC<SegmentationTableProps> {
|
||||
@@ -22,55 +28,118 @@ interface SegmentationTableComponent extends React.FC<SegmentationTableProps> {
|
||||
Config: typeof SegmentationTableConfig;
|
||||
AddSegmentRow: typeof AddSegmentRow;
|
||||
AddSegmentationRow: typeof AddSegmentationRow;
|
||||
SelectorHeader: typeof SegmentationSelectorHeader;
|
||||
Header: typeof SegmentationHeader;
|
||||
Collapsed: typeof SegmentationCollapsed;
|
||||
Expanded: typeof SegmentationExpanded;
|
||||
SegmentStatistics: typeof SegmentStatistics;
|
||||
}
|
||||
|
||||
export const SegmentationTable: SegmentationTableComponent = (props: SegmentationTableProps) => {
|
||||
export const SegmentationTableRoot = (props: SegmentationTableProps) => {
|
||||
const { t } = useTranslation('SegmentationTable');
|
||||
const { data = [], mode, title, disableEditing, disabled, children, ...contextProps } = props;
|
||||
const {
|
||||
data = [],
|
||||
mode,
|
||||
title,
|
||||
disableEditing = false,
|
||||
disabled = false,
|
||||
children,
|
||||
showConfig: externalShowConfig,
|
||||
...contextProps
|
||||
} = props;
|
||||
|
||||
const [internalShowConfig, setInternalShowConfig] = useState(false);
|
||||
const showConfig = externalShowConfig !== undefined ? externalShowConfig : internalShowConfig;
|
||||
|
||||
// Find the active segmentation info based on which representation is active
|
||||
const activeSegmentationInfo = data.find(info => info.representation?.active);
|
||||
|
||||
const activeSegmentationId = activeSegmentationInfo?.segmentation?.segmentationId;
|
||||
const activeRepresentation = activeSegmentationInfo?.representation;
|
||||
const activeSegmentation = activeSegmentationInfo?.segmentation;
|
||||
const { fillAlpha, fillAlphaInactive, outlineWidth, renderFill, renderOutline } =
|
||||
activeRepresentation?.styles ?? {};
|
||||
// Get the active segmentation ID
|
||||
const activeSegmentationId =
|
||||
props.activeSegmentationId || activeSegmentationInfo?.segmentation?.segmentationId;
|
||||
const activeRepresentation = props.activeRepresentation || activeSegmentationInfo?.representation;
|
||||
const activeSegmentation = props.activeSegmentation || activeSegmentationInfo?.segmentation;
|
||||
|
||||
// Extract style properties or use defaults
|
||||
const {
|
||||
fillAlpha = props.fillAlpha || 0.5,
|
||||
fillAlphaInactive = props.fillAlphaInactive || 0.2,
|
||||
outlineWidth = props.outlineWidth || 1,
|
||||
renderFill = props.renderFill !== undefined ? props.renderFill : true,
|
||||
renderOutline = props.renderOutline !== undefined ? props.renderOutline : true,
|
||||
} = activeRepresentation?.styles ?? {};
|
||||
|
||||
// Check if SegmentationTableConfig is present in children
|
||||
const hasConfigComponent = Children.toArray(children).some(
|
||||
child => isValidElement(child) && child.type === SegmentationTableConfig
|
||||
);
|
||||
|
||||
// Process children to conditionally render the config component based on showConfig
|
||||
const processedChildren = Children.map(children, child => {
|
||||
if (isValidElement(child) && child.type === SegmentationTableConfig) {
|
||||
// Only render the Config component if showConfig is true
|
||||
return showConfig ? child : null;
|
||||
}
|
||||
return child;
|
||||
});
|
||||
|
||||
const toggleShowConfig = () => {
|
||||
if (props.setShowConfig) {
|
||||
props.setShowConfig(!showConfig);
|
||||
} else {
|
||||
setInternalShowConfig(!internalShowConfig);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SegmentationTableProvider
|
||||
data={data}
|
||||
mode={mode}
|
||||
disabled={disabled}
|
||||
disableEditing={disableEditing}
|
||||
fillAlpha={fillAlpha}
|
||||
fillAlphaInactive={fillAlphaInactive}
|
||||
outlineWidth={outlineWidth}
|
||||
renderFill={renderFill}
|
||||
renderOutline={renderOutline}
|
||||
activeSegmentationId={activeSegmentationId}
|
||||
activeSegmentation={activeSegmentation}
|
||||
activeRepresentation={activeRepresentation}
|
||||
{...contextProps}
|
||||
value={{
|
||||
data,
|
||||
mode,
|
||||
showConfig,
|
||||
disabled,
|
||||
disableEditing,
|
||||
fillAlpha,
|
||||
fillAlphaInactive,
|
||||
outlineWidth,
|
||||
renderFill,
|
||||
renderOutline,
|
||||
activeSegmentationId,
|
||||
activeSegmentation,
|
||||
activeRepresentation,
|
||||
...contextProps,
|
||||
setShowConfig: toggleShowConfig,
|
||||
}}
|
||||
>
|
||||
<PanelSection defaultOpen={true}>
|
||||
<PanelSection.Header>
|
||||
<PanelSection.Header className="flex items-center justify-between">
|
||||
<span>{t(title)}</span>
|
||||
{hasConfigComponent && (
|
||||
<div className="ml-auto mr-2">
|
||||
<Icons.Settings
|
||||
className="text-primary-active h-4 w-4"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
toggleShowConfig();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</PanelSection.Header>
|
||||
<PanelSection.Content>{children}</PanelSection.Content>
|
||||
<PanelSection.Content>{processedChildren}</PanelSection.Content>
|
||||
</PanelSection>
|
||||
</SegmentationTableProvider>
|
||||
);
|
||||
};
|
||||
|
||||
SegmentationTable.Segments = SegmentationSegments;
|
||||
SegmentationTable.Config = SegmentationTableConfig;
|
||||
SegmentationTable.AddSegmentRow = AddSegmentRow;
|
||||
SegmentationTable.AddSegmentationRow = AddSegmentationRow;
|
||||
SegmentationTable.SelectorHeader = SegmentationSelectorHeader;
|
||||
SegmentationTable.Header = SegmentationHeader;
|
||||
SegmentationTable.Collapsed = SegmentationCollapsed;
|
||||
SegmentationTable.Expanded = SegmentationExpanded;
|
||||
const SegmentationTable = Object.assign(SegmentationTableRoot, {
|
||||
Segments: SegmentationSegments,
|
||||
Config: SegmentationTableConfig,
|
||||
AddSegmentRow: AddSegmentRow,
|
||||
AddSegmentationRow: AddSegmentationRow,
|
||||
Collapsed: SegmentationCollapsed,
|
||||
Expanded: SegmentationExpanded,
|
||||
SegmentStatistics: SegmentStatistics,
|
||||
Header: SegmentationHeader,
|
||||
}) as SegmentationTableComponent;
|
||||
|
||||
export { SegmentationTable };
|
||||
Reference in new issue
Block a user