From e9e7b4f61ccbca3650895c09e8430e20fe711a86 Mon Sep 17 00:00:00 2001 From: Alireza Date: Thu, 24 Mar 2022 21:22:47 -0400 Subject: [PATCH 01/20] initial state change --- .../segmentation/segmentationState.ts | 9 +- packages/tools/src/types/LabelmapTypes.ts | 17 ++ .../types/SegmentationRepresentationTypes.ts | 23 --- .../tools/src/types/SegmentationStateTypes.ts | 192 +++--------------- 4 files changed, 48 insertions(+), 193 deletions(-) create mode 100644 packages/tools/src/types/LabelmapTypes.ts delete mode 100644 packages/tools/src/types/SegmentationRepresentationTypes.ts diff --git a/packages/tools/src/stateManagement/segmentation/segmentationState.ts b/packages/tools/src/stateManagement/segmentation/segmentationState.ts index d04f6740e..7ba67c05e 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationState.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationState.ts @@ -3,14 +3,7 @@ import { triggerSegmentationStateModified, triggerSegmentationGlobalStateModified, } from './triggerSegmentationEvents' -import { - GlobalSegmentationState, - GlobalSegmentationData, - ColorLUT, - ToolGroupSpecificSegmentationState, - ToolGroupSpecificSegmentationData, - SegmentationConfig, -} from '../../types/SegmentationStateTypes' +import { ColorLUT } from '../../types/SegmentationStateTypes' import { getDefaultRepresentationConfig, diff --git a/packages/tools/src/types/LabelmapTypes.ts b/packages/tools/src/types/LabelmapTypes.ts new file mode 100644 index 000000000..4e627a292 --- /dev/null +++ b/packages/tools/src/types/LabelmapTypes.ts @@ -0,0 +1,17 @@ +import type { vtkColorTransferFunction } from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction' +import type { vtkPiecewiseFunction } from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction' + +/** + * Labelmap representation type + */ +export type LabelmapRenderingConfig = { + /** color transfer function */ + cfun?: vtkColorTransferFunction + /** opacity transfer function */ + ofun?: vtkPiecewiseFunction +} + +export type LabelmapMainRepresentation = { + volumeId: string + referenceVolumeId?: string +} diff --git a/packages/tools/src/types/SegmentationRepresentationTypes.ts b/packages/tools/src/types/SegmentationRepresentationTypes.ts deleted file mode 100644 index e3e987bee..000000000 --- a/packages/tools/src/types/SegmentationRepresentationTypes.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { vtkColorTransferFunction } from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction' -import type { vtkPiecewiseFunction } from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction' -import Representations from '../enums/SegmentationRepresentations' - -/** - * Labelmap representation type - */ -export type LabelmapRepresentation = { - /** labelmap representation type */ - type: typeof Representations.Labelmap - /** config */ - config: { - /** color transfer function */ - cfun?: vtkColorTransferFunction - /** opacity transfer function */ - ofun?: vtkPiecewiseFunction - } -} - -/** - * Segmentation representation. Currently only Labelmap is supported. - */ -export type SegmentationRepresentation = LabelmapRepresentation diff --git a/packages/tools/src/types/SegmentationStateTypes.ts b/packages/tools/src/types/SegmentationStateTypes.ts index dddf02603..cf632c778 100644 --- a/packages/tools/src/types/SegmentationStateTypes.ts +++ b/packages/tools/src/types/SegmentationStateTypes.ts @@ -1,6 +1,9 @@ -import { SegmentationRepresentation } from './SegmentationRepresentationTypes' - +import SegmentationRepresentations from '../enums/SegmentationRepresentations' import type { LabelmapConfig } from '../tools/displayTools/Labelmap/LabelmapConfig' +import { + LabelmapMainRepresentation, + LabelmapRenderingConfig, +} from './LabelmapTypes' /** * Four elements RGBA as 0-255 @@ -13,15 +16,10 @@ export type Color = [number, number, number, number] */ export type ColorLUT = Array -/** - * Representation Config - */ -export type RepresentationConfig = LabelmapConfig - /** * Segmentation Config */ -export type SegmentationConfig = { +export type SegmentationRepresentationConfig = { /** Whether to render Inactive segmentations */ renderInactiveSegmentations: boolean /** Representations configuration */ @@ -34,15 +32,11 @@ export type SegmentationConfig = { /** * Global Segmentation Data which is used for the segmentation */ -export type GlobalSegmentationData = { - /** volume Id of the segmentation in the cache */ - volumeId: string +export type Segmentation = { + segmentationId: string + type: SegmentationRepresentations /** segmentation label */ label: string - /** volumeId of the data that the segmentation was derived from - if any */ - referenceVolumeId?: string - /** imageId of the image that the segmentation was derived from - if any */ - referenceImageId?: string /** * Active segment index in the segmentation, this index will get used * inside the segmentation tools @@ -57,37 +51,16 @@ export type GlobalSegmentationData = { * If there is any derived statistics for the segmentation (e.g., mean, volume, etc) */ cachedStats: { [key: string]: number } -} -/** - * Global Segmentation State which is array of global segmentation data - */ -export type GlobalSegmentationState = GlobalSegmentationData[] - -/** - * Global Segmentation State with the shared config for all the segmentations - */ -export type GlobalSegmentationStateWithConfig = { - /** Global segmentation state */ - segmentations: GlobalSegmentationState - /** shared config for all the segmentations */ - config: SegmentationConfig + representations: { + LABELMAP?: LabelmapMainRepresentation + } } -/** - * ToolGroup Specific Segmentation Data for segmentations. As one segmentation - * can be represented in various ways (currently only labelmap is supported) - * we store ToolGroup specific segmentation data in this object - */ -export type ToolGroupSpecificSegmentationData = { - /** - * VolumeId for the segmentation - */ - volumeId: string - /** - * unique id for this segmentationData in this viewport which will be `{volumeId}-{representationType}` - */ - segmentationDataUID: string +type RepresentationData = { + segmentationRepresentationUID: string + segmentationId: string + type: SegmentationRepresentations /** * Whether the segmentation is the active (manipulatable) segmentation or not * which means it is inactive @@ -106,135 +79,30 @@ export type ToolGroupSpecificSegmentationData = { * using to render */ colorLUTIndex: number - /** - * The representation type and representation config for this segmentation - */ - representation: SegmentationRepresentation } /** - * ToolGroup Specific Segmentation State which is array of ToolGroup specific segmentation data - */ -export type ToolGroupSpecificSegmentationState = - ToolGroupSpecificSegmentationData[] - -/** - * ToolGroup Specific Segmentation State with the shared config for all the segmentations - * in the toolGroup + * ToolGroup Specific Segmentation Data for segmentations. As one segmentation + * can be represented in various ways (currently only labelmap is supported) + * we store ToolGroup specific segmentation data in this object */ -export type ToolGroupSpecificSegmentationStateWithConfig = { - segmentations: ToolGroupSpecificSegmentationState - config: SegmentationConfig -} +export type ToolGroupSpecificSegmentationRepresentation = RepresentationData & + LabelmapRenderingConfig // Todo: add more representations -/** - * Segmentation State. It stores both the global and the toolGroup specific - * segmentation data and the shared config for all the segmentations in the - * toolGroup and the global segmentation data. - * - * An example of segmentation state looks like - * @example - * ```js - * { - * colorLUT: [], - * global: { - * segmentations: [ - * { - * volumeId: 'labelmapUID2', - * label: 'label1', - * referenceVolumeId: 'referenceVolumeName', - * referenceImageId: 'referenceImageId', - * activeSegmentIndex: 1, - * segmentsLocked: Set(), - * cacheStats: {}, - * }, - * { - * volumeId: 'labelmapUID2', - * label: 'label1', - * referenceVolumeId: 'referenceVolumeName', - * referenceImageId: 'referenceImageId', - * activeSegmentIndex: 1, - * segmentsLocked: Set(), - * cacheStats: {}, - * }, - * ], - * config: { - * renderInactiveSegmentations: true, - * representations:{ - * LABELMAP: { - * renderOutline: true, - * outlineWidth: 3, - * outlineWidthActive: 3, - * outlineWidthInactive: 2, - * renderFill: true, - * fillAlpha: 0.9, - * fillAlphaInactive: 0.85, - * } - * } - * } - * } - * }, - * toolGroups: { - * toolGroupId1: { - * segmentations: [ - * { - * volumeId: 'labelmapUID1', - * segmentationDataUID: "123123" - * active: true, - * colorLUTIndex: 0, - * visibility: true, - * segmentsHidden: Set(), - * representation: { - * type: "labelmap" - * config: { - * cfun: cfun, - * ofun: ofun, - * }, - * } - * }, - * { - * volumeId: 'labelmapUID1', - * segmentationDataUID: "5987123" - * colorLUTIndex: 1, - * visibility: true, - * segmentsHidden: Set(), - * representation: { - * type: "labelmap" - * config: { - * cfun: cfun, - * ofun: ofun, - * }, - * } - * }, - * ], - * ], - * config: { - * renderInactiveSegmentations: true, - * representations:{ - * LABELMAP: { - * renderOutline: false, - * } - * } - * } - * }, - * toolGroup2: { - * // - * } - * }, - * }, - * } - */ export interface SegmentationState { /** Array of colorLUT for segmentation to render */ colorLutTables: ColorLUT[] /** global segmentation state with config */ - global: GlobalSegmentationStateWithConfig + globalConfig: SegmentationRepresentationConfig /** * ToolGroup specific segmentation state with config */ toolGroups: { /** toolGroupId and their toolGroup specific segmentation state with config */ - [key: string]: ToolGroupSpecificSegmentationStateWithConfig + [key: string]: { + segmentationRepresentations: ToolGroupSpecificSegmentationRepresentation[] + config: SegmentationRepresentationConfig + } } } @@ -242,7 +110,7 @@ export interface SegmentationState { * SegmentationDataInput that is used to add a segmentation to * a tooLGroup. It is partial of ToolGroupSpecificSegmentationData BUT REQUIRES volumeId */ -export type SegmentationDataInput = - Partial & { - toolGroupId: string - } +// export type SegmentationDataInput = +// Partial & { +// toolGroupId: string +// } From 40f52ddc5c971ae4bd807e0dd84d513107aaebec Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 25 Mar 2022 10:18:44 -0400 Subject: [PATCH 02/20] change getToolGroupByToolGroupId to getToolGroupById --- common/reviews/api/tools.api.md | 12 ++--- .../demo/src/ExampleSegmentationRender.tsx | 8 ++- .../examples/annotationToolModes/index.ts | 2 +- .../examples/stackAnnotationTools/index.ts | 2 +- .../segmentation/SegmentationStateManager.ts | 7 +-- .../segmentation/activeSegmentation.ts | 6 +-- .../addSegmentationsForToolGroup.ts | 52 ++++++++----------- .../createNewSegmentationForToolGroup.ts | 4 +- .../helpers/checkSegmentationDataIsValid.ts | 25 --------- .../segmentation/helpers/index.ts | 4 +- .../helpers/validateSegmentationInputArray.ts | 35 +++++++++++++ .../segmentation/segmentIndex.ts | 13 ++--- .../segmentation/segmentLocking.ts | 15 +++--- .../segmentation/segmentationState.ts | 19 +++---- .../src/store/ToolGroupManager/destroy.ts | 6 +-- ...ToolGroupId.ts => destroyToolGroupById.ts} | 4 +- ...upByToolGroupId.ts => getToolGroupById.ts} | 6 +-- .../tools/src/store/ToolGroupManager/index.ts | 8 +-- .../displayTools/Labelmap/LabelmapDisplay.ts | 6 +-- .../displayTools/SegmentationDisplayTool.ts | 4 +- .../tools/src/types/SegmentationStateTypes.ts | 5 ++ .../segmentation/thresholdVolumeByRange.ts | 2 +- .../segmentation/thresholdVolumeByRoiStats.ts | 2 +- .../utilities/triggerSegmentationRender.ts | 7 +-- packages/tools/test/BidirectionalTool_test.js | 2 +- packages/tools/test/CrosshairsTool_test.js | 2 +- packages/tools/test/EllipseROI_test.js | 4 +- packages/tools/test/LengthTool_test.js | 6 +-- packages/tools/test/ProbeTool_test.js | 4 +- packages/tools/test/RectangleROI_test.js | 4 +- .../StackScrollToolMouseWheelTool_test.js | 2 +- packages/tools/test/ToolGroupManager_test.js | 16 +++--- .../tools/test/cpu_BidirectionalTool_test.js | 2 +- packages/tools/test/cpu_EllipseROI_test.js | 2 +- packages/tools/test/cpu_LengthTool_test.js | 2 +- packages/tools/test/cpu_ProbeTool_test.js | 2 +- packages/tools/test/cpu_RectangleROI_test.js | 2 +- .../test/segmentationConfigController_test.js | 2 +- .../test/segmentationRectangleScissor_test.js | 2 +- .../tools/test/segmentationRender_test.js | 2 +- ...segmentationSegmentIndexController_test.js | 2 +- .../test/segmentationSphereScissor_test.js | 2 +- packages/tools/test/segmentationState_test.js | 5 +- .../segmentationVisibilityController_test.js | 2 +- .../tools/test/synchronizerManager_test.js | 4 +- 45 files changed, 154 insertions(+), 171 deletions(-) delete mode 100644 packages/tools/src/stateManagement/segmentation/helpers/checkSegmentationDataIsValid.ts create mode 100644 packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts rename packages/tools/src/store/ToolGroupManager/{destroyToolGroupByToolGroupId.ts => destroyToolGroupById.ts} (86%) rename packages/tools/src/store/ToolGroupManager/{getToolGroupByToolGroupId.ts => getToolGroupById.ts} (73%) diff --git a/common/reviews/api/tools.api.md b/common/reviews/api/tools.api.md index 78003b99f..ba23ca36d 100644 --- a/common/reviews/api/tools.api.md +++ b/common/reviews/api/tools.api.md @@ -813,7 +813,7 @@ function destroy_3(): void; function destroySynchronizerById(synchronizerId: string): void; // @public (undocumented) -function destroyToolGroupByToolGroupId(toolGroupId: string): void; +function destroyToolGroupById(toolGroupId: string): void; // @public (undocumented) function distanceToPoint(lineStart: Types_2.Point2, lineEnd: Types_2.Point2, point: Types_2.Point2): number; @@ -1180,7 +1180,7 @@ function getGlobalSegmentationConfig(): SegmentationConfig; function getGlobalSegmentationConfig_2(): SegmentationConfig; // @public (undocumented) -function getGlobalSegmentationDataByUID(segmentationUID: string): GlobalSegmentationData; +function getSegmentation(segmentationUID: string): GlobalSegmentationData; // @public (undocumented) function getGlobalSegmentationState(): GlobalSegmentationState | []; @@ -1241,7 +1241,7 @@ function getTextBoxCoordsCanvas(annotationCanvasPoints: Array): function getToolGroup(viewportId: string, renderingEngineId: string): IToolGroup | undefined; // @public (undocumented) -function getToolGroupByToolGroupId(toolGroupId: string): IToolGroup | undefined; +function getToolGroupById(toolGroupId: string): IToolGroup | undefined; // @public (undocumented) function getToolGroups(): string[]; @@ -2896,7 +2896,7 @@ declare namespace state_2 { addColorLUT, getColorLut, getGlobalSegmentationState, - getGlobalSegmentationDataByUID, + getSegmentation, addGlobalSegmentationData, getSegmentationState, addSegmentationData, @@ -3009,8 +3009,8 @@ declare namespace ToolGroupManager { export { createToolGroup, destroy_3 as destroy, - destroyToolGroupByToolGroupId, - getToolGroupByToolGroupId, + destroyToolGroupById, + getToolGroupById, getToolGroup, getAllToolGroups } diff --git a/packages/demo/src/ExampleSegmentationRender.tsx b/packages/demo/src/ExampleSegmentationRender.tsx index 61a1a627f..a32a55a52 100644 --- a/packages/demo/src/ExampleSegmentationRender.tsx +++ b/packages/demo/src/ExampleSegmentationRender.tsx @@ -564,11 +564,9 @@ class SegmentationExample extends Component { toolGroupId, [ { - volumeId: segmentationUID, + type: csToolsEnums.SegmentationRepresentations.Labelmap, + representation: {}, active: true, - representation: { - type: csToolsEnums.SegmentationRepresentations.Labelmap, - }, }, ], { @@ -704,7 +702,7 @@ class SegmentationExample extends Component { this.state.selectedToolGroupName, this.state.selectedsegmentationUID ) - const globalState = segmentation.state.getGlobalSegmentationDataByUID( + const globalState = segmentation.state.getSegmentation( segmentationData.volumeId ) diff --git a/packages/tools/examples/annotationToolModes/index.ts b/packages/tools/examples/annotationToolModes/index.ts index 325c61dc4..85d720e4a 100644 --- a/packages/tools/examples/annotationToolModes/index.ts +++ b/packages/tools/examples/annotationToolModes/index.ts @@ -54,7 +54,7 @@ const selectedToolMode = ToolModes.Active addDropdownToToolbar( { options: toolModes, defaultOption: selectedToolMode }, (newToolMode) => { - const toolGroup = ToolGroupManager.getToolGroupByToolGroupId(toolGroupId) + const toolGroup = ToolGroupManager.getToolGroupById(toolGroupId) // Set the new tool active toolGroup[`setTool${newToolMode}`](LengthTool.toolName, { diff --git a/packages/tools/examples/stackAnnotationTools/index.ts b/packages/tools/examples/stackAnnotationTools/index.ts index 2d9eba89b..e4240466c 100644 --- a/packages/tools/examples/stackAnnotationTools/index.ts +++ b/packages/tools/examples/stackAnnotationTools/index.ts @@ -58,7 +58,7 @@ let selectedToolName = toolsNames[0] addDropdownToToolbar( { options: toolsNames, defaultOption: selectedToolName }, (newSelectedToolName) => { - const toolGroup = ToolGroupManager.getToolGroupByToolGroupId(toolGroupId) + const toolGroup = ToolGroupManager.getToolGroupById(toolGroupId) // Set the new tool active toolGroup.setToolActive(newSelectedToolName, { diff --git a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts index a41d1f1a4..763d38f29 100644 --- a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts +++ b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts @@ -87,9 +87,7 @@ export default class SegmentationStateManager { * @returns - The global segmentation data for the * segmentation with the given UID. */ - getGlobalSegmentationData( - segmentationUID: string - ): GlobalSegmentationData | undefined { + getSegmentation(segmentationUID: string): GlobalSegmentationData | undefined { return this.state.global.segmentations?.find( (segmentationState) => segmentationState.volumeId === segmentationUID ) @@ -281,8 +279,7 @@ export default class SegmentationStateManager { this._initDefaultColorLutIfNecessary() // Don't allow overwriting existing labelmapState with the same labelmapUID - const existingGlobalSegmentationData = - this.getGlobalSegmentationData(volumeId) + const existingGlobalSegmentationData = this.getSegmentation(volumeId) // merge the new state with the existing state const updatedState = { diff --git a/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts b/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts index 46707f871..0abb54c2c 100644 --- a/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts +++ b/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts @@ -1,7 +1,7 @@ import { getActiveSegmentationData, setActiveSegmentationData, - getGlobalSegmentationDataByUID, + getSegmentation, } from './segmentationState' /** @@ -21,9 +21,7 @@ function getActiveSegmentationInfo(toolGroupId: string): { return null } - const globalState = getGlobalSegmentationDataByUID( - activeSegmentationData.volumeId - ) + const globalState = getSegmentation(activeSegmentationData.volumeId) return { volumeId: activeSegmentationData.volumeId, diff --git a/packages/tools/src/stateManagement/segmentation/addSegmentationsForToolGroup.ts b/packages/tools/src/stateManagement/segmentation/addSegmentationsForToolGroup.ts index 356a7a186..13d93bb99 100644 --- a/packages/tools/src/stateManagement/segmentation/addSegmentationsForToolGroup.ts +++ b/packages/tools/src/stateManagement/segmentation/addSegmentationsForToolGroup.ts @@ -2,12 +2,12 @@ import { utilities as csUtils } from '@cornerstonejs/core' import _cloneDeep from 'lodash.clonedeep' import { - SegmentationDataInput, - SegmentationConfig, + SegmentationRepresentationConfig, + SegmentationPublicInput, } from '../../types/SegmentationStateTypes' -import { checkSegmentationDataIsValid } from './helpers' +import { validateSegmentationInputArray } from './helpers' import Representations from '../../enums/SegmentationRepresentations' -import { getToolGroupByToolGroupId } from '../../store/ToolGroupManager' +import { getToolGroupById } from '../../store/ToolGroupManager' import { LabelmapDisplay } from '../../tools/displayTools/Labelmap' @@ -16,33 +16,32 @@ import { LabelmapDisplay } from '../../tools/displayTools/Labelmap' * provided segmentationDataArray to create and configure the segmentation based * on the representation type and representation specific configuration. * @param toolGroupId - The Id of the toolGroup to add the segmentation to. - * @param segmentationDataArray - minimum of volumeId should be provided, it will - * throw an error if not. If no representation type is provided, it will use - * the default labelmap representation. + * @param segmentationInput - The type of the segmentation representation to be shown + * and its required properties for rendering * @param toolGroupSpecificConfig - The toolGroup specific configuration * for the segmentation display. */ async function addSegmentationsForToolGroup( toolGroupId: string, - segmentationDataArray: SegmentationDataInput[], - toolGroupSpecificConfig?: SegmentationConfig + segmentationInputArray: SegmentationPublicInput[], + toolGroupSpecificConfig?: SegmentationRepresentationConfig ): Promise { - checkSegmentationDataIsValid(segmentationDataArray) + validateSegmentationInputArray(segmentationInputArray) // Check if there exists a toolGroup with the toolGroupId - const toolGroup = getToolGroupByToolGroupId(toolGroupId) + const toolGroup = getToolGroupById(toolGroupId) if (!toolGroup) { throw new Error(`No tool group found for toolGroupId: ${toolGroupId}`) } - const promises = segmentationDataArray.map(async (segData) => { - const segmentationData = _cloneDeep(segData) + const promises = segmentationInputArray.map(async (segInput) => { + const segmentationInput = _cloneDeep(segInput) - segmentationData.segmentationDataUID = csUtils.uuidv4() + // segmentationData.segmentationDataUID = csUtils.uuidv4() return _addSegmentation( toolGroupId, - segmentationData, + segmentationInput, toolGroupSpecificConfig ) }) @@ -51,30 +50,23 @@ async function addSegmentationsForToolGroup( } async function _addSegmentation( - toolGroupId, - segmentationData, - toolGroupSpecificConfig + toolGroupId: string, + segmentationInput: SegmentationPublicInput, + toolGroupSpecificConfig: SegmentationRepresentationConfig ) { - const representationType = segmentationData.representation?.type - ? segmentationData.representation.type + const representationType = segmentationInput.type + ? segmentationInput.type : Representations.Labelmap - // create representation config if not provided by - if (!segmentationData.representation) { - segmentationData.representation = { - type: representationType, - } - } - // Create empty config if not provided by. // Note: this is representation-required configuration for the segmentation // For Labelmap, it is the cfun and ofun. Todo: maybe we change this to props? - if (!segmentationData.representation.config) { - segmentationData.representation.config = {} + if (!segmentationInput.representation.config) { + segmentationInput.representation.config = {} } if (representationType === Representations.Labelmap) { - await LabelmapDisplay.addSegmentationData( + await LabelmapDisplay.addSegmentationInput( toolGroupId, segmentationData, toolGroupSpecificConfig diff --git a/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts b/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts index 1e9a112a5..0db2e9620 100644 --- a/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts +++ b/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts @@ -7,7 +7,7 @@ import { } from '@cornerstonejs/core' import type { Types } from '@cornerstonejs/core' -import { getToolGroupByToolGroupId } from '../../store/ToolGroupManager' +import { getToolGroupById } from '../../store/ToolGroupManager' /** * Create a new 3D segmentation volume from the default imageData presented in @@ -33,7 +33,7 @@ async function createNewSegmentationForToolGroup( direction?: Float32Array } ): Promise { - const toolGroup = getToolGroupByToolGroupId(toolGroupId) + const toolGroup = getToolGroupById(toolGroupId) if (!toolGroup) { throw new Error(`ToolGroup with Id ${toolGroupId} not found`) diff --git a/packages/tools/src/stateManagement/segmentation/helpers/checkSegmentationDataIsValid.ts b/packages/tools/src/stateManagement/segmentation/helpers/checkSegmentationDataIsValid.ts deleted file mode 100644 index 4dd87c58c..000000000 --- a/packages/tools/src/stateManagement/segmentation/helpers/checkSegmentationDataIsValid.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { SegmentationDataInput } from '../../../types/SegmentationStateTypes' - -/** - * Checks if the segmentationDataArray is valid meaning it contains - * volumeId of the segmentation. - * - * @param segmentationDataArray - Array of segmentationData - * @internal - */ -function checkSegmentationDataIsValid( - segmentationDataArray: SegmentationDataInput[] -): void { - if (!segmentationDataArray || !segmentationDataArray.length) { - throw new Error('The segmentationDataArray undefined or empty array') - } - - // check if volumeId is present in all the segmentationDataArray - segmentationDataArray.forEach((segmentationData) => { - if (!segmentationData.volumeId) { - throw new Error('volumeId is missing in the segmentationData') - } - }) -} - -export default checkSegmentationDataIsValid diff --git a/packages/tools/src/stateManagement/segmentation/helpers/index.ts b/packages/tools/src/stateManagement/segmentation/helpers/index.ts index 206d1859f..371371b5b 100644 --- a/packages/tools/src/stateManagement/segmentation/helpers/index.ts +++ b/packages/tools/src/stateManagement/segmentation/helpers/index.ts @@ -1,9 +1,9 @@ -import checkSegmentationDataIsValid from './checkSegmentationDataIsValid' +import validateSegmentationInputArray from './validateSegmentationInputArray' import internalAddSegmentationToElement from './internalAddSegmentationToElement' import internalRemoveSegmentationFromElement from './internalRemoveSegmentationFromElement' export { - checkSegmentationDataIsValid, + validateSegmentationInputArray, internalAddSegmentationToElement, internalRemoveSegmentationFromElement, } diff --git a/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts b/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts new file mode 100644 index 000000000..51f25ea9e --- /dev/null +++ b/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts @@ -0,0 +1,35 @@ +import { SegmentationRepresentations } from 'tools/src/enums' +import { SegmentationPublicInput } from '../../../types/SegmentationStateTypes' + +/** + * Checks if the segmentationInputArray is valid meaning it contains + * correct representationProps for the representation type that is being used. + * + * @param segmentationInputArray - Array of segmentation inputs + * @internal + */ +function validateSegmentationInputArray( + segmentationInputArray: SegmentationPublicInput[] +): void { + if (!segmentationInputArray || !segmentationInputArray.length) { + throw new Error('The segmentationInputArray undefined or empty array') + } + + segmentationInputArray.forEach((segmentationInput) => { + if (segmentationInput.type === SegmentationRepresentations.Labelmap) { + _validateLabelmapRepresentationProp(segmentationInput) + } + }) +} + +function _validateLabelmapRepresentationProp( + segmentationInput: SegmentationPublicInput +): void { + if (!segmentationInput.representationProps.volumeId) { + throw new Error( + 'The segmentationInput.representationProps.volumeId is undefined' + ) + } +} + +export default validateSegmentationInputArray diff --git a/packages/tools/src/stateManagement/segmentation/segmentIndex.ts b/packages/tools/src/stateManagement/segmentation/segmentIndex.ts index 4b1d47dbe..2cfdd825b 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentIndex.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentIndex.ts @@ -1,5 +1,5 @@ import { getActiveSegmentationInfo } from './activeSegmentation' -import { getGlobalSegmentationDataByUID } from './segmentationState' +import { getSegmentation } from './segmentationState' import { triggerSegmentationGlobalStateModified } from './triggerSegmentationEvents' /** @@ -16,7 +16,7 @@ function getActiveSegmentIndex(toolGroupId: string): number | undefined { } const { volumeId } = segmentationInfo - const activeSegmentationGlobalState = getGlobalSegmentationDataByUID(volumeId) + const activeSegmentationGlobalState = getSegmentation(volumeId) if (activeSegmentationGlobalState) { return activeSegmentationGlobalState.activeSegmentIndex @@ -42,8 +42,7 @@ function setActiveSegmentIndex( } const { volumeId: segmentationUID } = segmentationInfo - const activeSegmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const activeSegmentationGlobalState = getSegmentation(segmentationUID) if (activeSegmentationGlobalState?.activeSegmentIndex !== segmentIndex) { activeSegmentationGlobalState.activeSegmentIndex = segmentIndex @@ -64,8 +63,7 @@ function setActiveSegmentIndexForSegmentation( segmentationUID: string, segmentIndex: number ): void { - const activeSegmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const activeSegmentationGlobalState = getSegmentation(segmentationUID) if (activeSegmentationGlobalState?.activeSegmentIndex !== segmentIndex) { activeSegmentationGlobalState.activeSegmentIndex = segmentIndex @@ -82,8 +80,7 @@ function setActiveSegmentIndexForSegmentation( function getActiveSegmentIndexForSegmentation( segmentationUID: string ): number | undefined { - const activeSegmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const activeSegmentationGlobalState = getSegmentation(segmentationUID) if (activeSegmentationGlobalState) { return activeSegmentationGlobalState.activeSegmentIndex diff --git a/packages/tools/src/stateManagement/segmentation/segmentLocking.ts b/packages/tools/src/stateManagement/segmentation/segmentLocking.ts index f44422a7d..fc2082eea 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentLocking.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentLocking.ts @@ -1,6 +1,6 @@ import { getActiveSegmentationInfo } from './activeSegmentation' -import { getGlobalSegmentationDataByUID } from '../../stateManagement/segmentation/segmentationState' +import { getSegmentation } from '../../stateManagement/segmentation/segmentationState' import { triggerSegmentationGlobalStateModified } from './triggerSegmentationEvents' /** @@ -23,8 +23,7 @@ function getSegmentIndexLocked( } const { volumeId: segmentationUID } = activeSegmentationInfo - const segmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const segmentationGlobalState = getSegmentation(segmentationUID) const lockedSegments = segmentationGlobalState.segmentsLocked @@ -56,8 +55,7 @@ function setSegmentIndexLocked( const { volumeId: segmentationUID } = activeSegmentationInfo - const segmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const segmentationGlobalState = getSegmentation(segmentationUID) const { segmentsLocked } = segmentationGlobalState @@ -81,7 +79,7 @@ function getSegmentIndexLockedForSegmentation( segmentationUID: string, segmentIndex: number ): boolean { - const globalState = getGlobalSegmentationDataByUID(segmentationUID) + const globalState = getSegmentation(segmentationUID) if (!globalState) { throw new Error(`No segmentation state found for ${segmentationUID}`) @@ -102,8 +100,7 @@ function setSegmentIndexLockedForSegmentation( segmentIndex: number, locked = true ): void { - const segmentationGlobalState = - getGlobalSegmentationDataByUID(segmentationUID) + const segmentationGlobalState = getSegmentation(segmentationUID) if (!segmentationGlobalState) { throw new Error(`No segmentation state found for ${segmentationUID}`) @@ -129,7 +126,7 @@ function setSegmentIndexLockedForSegmentation( function getSegmentsLockedForSegmentation( segmentationUID: string ): number[] | [] { - const globalState = getGlobalSegmentationDataByUID(segmentationUID) + const globalState = getSegmentation(segmentationUID) if (!globalState) { throw new Error(`No segmentation state found for ${segmentationUID}`) diff --git a/packages/tools/src/stateManagement/segmentation/segmentationState.ts b/packages/tools/src/stateManagement/segmentation/segmentationState.ts index 7ba67c05e..93d14f02e 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationState.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationState.ts @@ -3,7 +3,7 @@ import { triggerSegmentationStateModified, triggerSegmentationGlobalStateModified, } from './triggerSegmentationEvents' -import { ColorLUT } from '../../types/SegmentationStateTypes' +import { ColorLUT, Segmentation } from '../../types/SegmentationStateTypes' import { getDefaultRepresentationConfig, @@ -25,16 +25,13 @@ function getDefaultSegmentationStateManager() { **************************/ /** - * Get the global segmentation data for a given segmentation UID - * @param segmentationUID - The UID of the segmentation to get the global - * data for. + * Get the segmentation for the given segmentationId + * @param segmentationId - The Id of the segmentation * @returns A GlobalSegmentationData object */ -function getGlobalSegmentationDataByUID( - segmentationUID: string -): GlobalSegmentationData { +function getSegmentation(segmentationId: string): Segmentation | undefined { const segmentationStateManager = getDefaultSegmentationStateManager() - return segmentationStateManager.getGlobalSegmentationData(segmentationUID) + return segmentationStateManager.getSegmentation(segmentationId) } /** @@ -350,9 +347,7 @@ function _initGlobalStateIfNecessary( segmentationStateManager, segmentationData ) { - const globalSegmentationData = getGlobalSegmentationDataByUID( - segmentationData.volumeId - ) + const globalSegmentationData = getSegmentation(segmentationData.volumeId) // for the representation, if no global config exists, create default one const { representation: { type: representationType }, @@ -430,7 +425,7 @@ export { getColorLut, // get/set global state getGlobalSegmentationState, - getGlobalSegmentationDataByUID, + getSegmentation, addGlobalSegmentationData, // toolGroup state getSegmentationState, diff --git a/packages/tools/src/store/ToolGroupManager/destroy.ts b/packages/tools/src/store/ToolGroupManager/destroy.ts index bc783e561..d87a269f8 100644 --- a/packages/tools/src/store/ToolGroupManager/destroy.ts +++ b/packages/tools/src/store/ToolGroupManager/destroy.ts @@ -1,10 +1,10 @@ // `BaseManager` or IManager interface for duplicate API between ToolGroup/Synchronizer? import { state as csToolsState } from '../index' -import destroyToolGroupByToolGroupId from './destroyToolGroupByToolGroupId' +import destroyToolGroupById from './destroyToolGroupById' // ToolGroups function entirely by their "state" being queried and leveraged // removing a ToolGroup from state is equivalent to killing it. Calling -// destroyToolGroupByToolGroupId() to make sure the SegmentationDisplayTools +// destroyToolGroupById() to make sure the SegmentationDisplayTools // have been removed from the toolGroup Viewports. //Todo: this makes more sense // to be based on events, but we don't have any toolGroup created/removed events @@ -15,7 +15,7 @@ function destroy(): void { const toolGroups = [...csToolsState.toolGroups] for (const toolGroup of toolGroups) { - destroyToolGroupByToolGroupId(toolGroup.id) + destroyToolGroupById(toolGroup.id) } csToolsState.toolGroups = [] diff --git a/packages/tools/src/store/ToolGroupManager/destroyToolGroupByToolGroupId.ts b/packages/tools/src/store/ToolGroupManager/destroyToolGroupById.ts similarity index 86% rename from packages/tools/src/store/ToolGroupManager/destroyToolGroupByToolGroupId.ts rename to packages/tools/src/store/ToolGroupManager/destroyToolGroupById.ts index d0d45efc2..ac703399c 100644 --- a/packages/tools/src/store/ToolGroupManager/destroyToolGroupByToolGroupId.ts +++ b/packages/tools/src/store/ToolGroupManager/destroyToolGroupById.ts @@ -10,7 +10,7 @@ import { removeSegmentationsFromToolGroup } from '../../stateManagement/segmenta * * @param toolGroupId - The Id of the tool group to be destroyed. */ -function destroyToolGroupByToolGroupId(toolGroupId: string): void { +function destroyToolGroupById(toolGroupId: string): void { const toolGroupIndex = state.toolGroups.findIndex( (tg) => tg.id === toolGroupId ) @@ -22,4 +22,4 @@ function destroyToolGroupByToolGroupId(toolGroupId: string): void { } } -export default destroyToolGroupByToolGroupId +export default destroyToolGroupById diff --git a/packages/tools/src/store/ToolGroupManager/getToolGroupByToolGroupId.ts b/packages/tools/src/store/ToolGroupManager/getToolGroupById.ts similarity index 73% rename from packages/tools/src/store/ToolGroupManager/getToolGroupByToolGroupId.ts rename to packages/tools/src/store/ToolGroupManager/getToolGroupById.ts index 91015dc19..b0a016a3a 100644 --- a/packages/tools/src/store/ToolGroupManager/getToolGroupByToolGroupId.ts +++ b/packages/tools/src/store/ToolGroupManager/getToolGroupById.ts @@ -7,10 +7,8 @@ import { IToolGroup } from '../../types' * @returns The tool group that has the same id as the tool group id that was * passed in. */ -function getToolGroupByToolGroupId( - toolGroupId: string -): IToolGroup | undefined { +function getToolGroupById(toolGroupId: string): IToolGroup | undefined { return state.toolGroups.find((s) => s.id === toolGroupId) } -export default getToolGroupByToolGroupId +export default getToolGroupById diff --git a/packages/tools/src/store/ToolGroupManager/index.ts b/packages/tools/src/store/ToolGroupManager/index.ts index 819fa7097..2baa7d1c2 100644 --- a/packages/tools/src/store/ToolGroupManager/index.ts +++ b/packages/tools/src/store/ToolGroupManager/index.ts @@ -1,15 +1,15 @@ import createToolGroup from './createToolGroup' -import destroyToolGroupByToolGroupId from './destroyToolGroupByToolGroupId' +import destroyToolGroupById from './destroyToolGroupById' import destroy from './destroy' -import getToolGroupByToolGroupId from './getToolGroupByToolGroupId' +import getToolGroupById from './getToolGroupById' import getToolGroup from './getToolGroup' import getAllToolGroups from './getAllToolGroups' export { createToolGroup, destroy, - destroyToolGroupByToolGroupId, - getToolGroupByToolGroupId, + destroyToolGroupById, + getToolGroupById, getToolGroup, getAllToolGroups, } diff --git a/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts b/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts index 7d1258634..2c350e4d8 100644 --- a/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts +++ b/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts @@ -6,7 +6,7 @@ import { cache, getEnabledElementByIds, Types } from '@cornerstonejs/core' import * as SegmentationState from '../../../stateManagement/segmentation/segmentationState' import { LabelmapRepresentation } from '../../../types/SegmentationRepresentationTypes' import Representations from '../../../enums/SegmentationRepresentations' -import { getToolGroupByToolGroupId } from '../../../store/ToolGroupManager' +import { getToolGroupById } from '../../../store/ToolGroupManager' import type { LabelmapConfig } from './LabelmapConfig' import { SegmentationConfig, @@ -276,7 +276,7 @@ function _removeLabelmapFromToolGroupViewports( toolGroupId: string, segmentationDataUID: string ): void { - const toolGroup = getToolGroupByToolGroupId(toolGroupId) + const toolGroup = getToolGroupById(toolGroupId) if (toolGroup === undefined) { throw new Error(`ToolGroup with ToolGroupId ${toolGroupId} does not exist`) @@ -303,7 +303,7 @@ async function _addLabelmapToToolGroupViewports( toolGroupId, segmentationData ): Promise { - const toolGroup = getToolGroupByToolGroupId(toolGroupId) as IToolGroup + const toolGroup = getToolGroupById(toolGroupId) as IToolGroup const { viewportsInfo } = toolGroup for (const viewportInfo of viewportsInfo) { diff --git a/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts b/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts index f9abf410f..16ff7b382 100644 --- a/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts +++ b/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts @@ -5,7 +5,7 @@ import { getSegmentationState } from '../../stateManagement/segmentation/segment import { LabelmapDisplay } from './Labelmap' import { segmentationConfig } from '../../stateManagement/segmentation' import { triggerSegmentationStateModified } from '../../stateManagement/segmentation/triggerSegmentationEvents' -import { getToolGroupByToolGroupId } from '../../store/ToolGroupManager' +import { getToolGroupById } from '../../store/ToolGroupManager' import { ToolGroupSpecificSegmentationData, SegmentationConfig, @@ -99,7 +99,7 @@ export default class SegmentationDisplayTool extends BaseTool { * @param toolGroupId - the toolGroupId */ renderSegmentation = (toolGroupId: string): void => { - const toolGroup = getToolGroupByToolGroupId(toolGroupId) + const toolGroup = getToolGroupById(toolGroupId) if (!toolGroup) { return diff --git a/packages/tools/src/types/SegmentationStateTypes.ts b/packages/tools/src/types/SegmentationStateTypes.ts index cf632c778..6b4b88479 100644 --- a/packages/tools/src/types/SegmentationStateTypes.ts +++ b/packages/tools/src/types/SegmentationStateTypes.ts @@ -106,6 +106,11 @@ export interface SegmentationState { } } +export type SegmentationPublicInput = { + type: SegmentationRepresentations + representationProps: LabelmapMainRepresentation +} + /** * SegmentationDataInput that is used to add a segmentation to * a tooLGroup. It is partial of ToolGroupSpecificSegmentationData BUT REQUIRES volumeId diff --git a/packages/tools/src/utilities/segmentation/thresholdVolumeByRange.ts b/packages/tools/src/utilities/segmentation/thresholdVolumeByRange.ts index da92f2a2b..a251208e8 100644 --- a/packages/tools/src/utilities/segmentation/thresholdVolumeByRange.ts +++ b/packages/tools/src/utilities/segmentation/thresholdVolumeByRange.ts @@ -53,7 +53,7 @@ function thresholdVolumeByRange( throw new Error('thresholding more than one volumes is not supported yet') } - const globalState = SegmentationState.getGlobalSegmentationDataByUID( + const globalState = SegmentationState.getSegmentation( segmentationData.volumeId ) diff --git a/packages/tools/src/utilities/segmentation/thresholdVolumeByRoiStats.ts b/packages/tools/src/utilities/segmentation/thresholdVolumeByRoiStats.ts index cc86d91f6..46c7ec35c 100644 --- a/packages/tools/src/utilities/segmentation/thresholdVolumeByRoiStats.ts +++ b/packages/tools/src/utilities/segmentation/thresholdVolumeByRoiStats.ts @@ -41,7 +41,7 @@ function thresholdVolumeByRoiStats( throw new Error('thresholding more than one volumes is not supported yet') } - const globalState = SegmentationState.getGlobalSegmentationDataByUID( + const globalState = SegmentationState.getSegmentation( segmentationData.volumeId ) diff --git a/packages/tools/src/utilities/triggerSegmentationRender.ts b/packages/tools/src/utilities/triggerSegmentationRender.ts index e03cb177e..ab1d4d9db 100644 --- a/packages/tools/src/utilities/triggerSegmentationRender.ts +++ b/packages/tools/src/utilities/triggerSegmentationRender.ts @@ -6,10 +6,7 @@ import { Types, } from '@cornerstonejs/core' import { Events as csToolsEvents } from '../enums' -import { - getToolGroupByToolGroupId, - getToolGroup, -} from '../store/ToolGroupManager' +import { getToolGroupById, getToolGroup } from '../store/ToolGroupManager' import SegmentationDisplayTool from '../tools/displayTools/SegmentationDisplayTool' import { SegmentationRenderedEventDetail } from '../types/EventTypes' @@ -97,7 +94,7 @@ class SegmentationRenderingEngine { } } _triggerRender(toolGroupId) { - const toolGroup = getToolGroupByToolGroupId(toolGroupId) + const toolGroup = getToolGroupById(toolGroupId) if (!toolGroup) { console.warn(`No tool group found with toolGroupId: ${toolGroupId}`) diff --git a/packages/tools/test/BidirectionalTool_test.js b/packages/tools/test/BidirectionalTool_test.js index a89255c8c..33210daed 100644 --- a/packages/tools/test/BidirectionalTool_test.js +++ b/packages/tools/test/BidirectionalTool_test.js @@ -103,7 +103,7 @@ describe('Cornerstone Tools: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/CrosshairsTool_test.js b/packages/tools/test/CrosshairsTool_test.js index 2e654a9a5..4a9a9bb0b 100644 --- a/packages/tools/test/CrosshairsTool_test.js +++ b/packages/tools/test/CrosshairsTool_test.js @@ -122,7 +122,7 @@ describe('Cornerstone Tools: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('volume') + ToolGroupManager.destroyToolGroupById('volume') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/EllipseROI_test.js b/packages/tools/test/EllipseROI_test.js index 9dcb426f0..c657859ac 100644 --- a/packages/tools/test/EllipseROI_test.js +++ b/packages/tools/test/EllipseROI_test.js @@ -97,7 +97,7 @@ describe('Ellipse Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { el.parentNode.removeChild(el) @@ -354,7 +354,7 @@ describe('Ellipse Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/LengthTool_test.js b/packages/tools/test/LengthTool_test.js index 94acd93d6..baad17abe 100644 --- a/packages/tools/test/LengthTool_test.js +++ b/packages/tools/test/LengthTool_test.js @@ -105,7 +105,7 @@ describe('LengthTool:', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -958,7 +958,7 @@ describe('LengthTool:', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -1124,7 +1124,7 @@ describe('LengthTool:', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/ProbeTool_test.js b/packages/tools/test/ProbeTool_test.js index ddb51de9c..58a38f1c8 100644 --- a/packages/tools/test/ProbeTool_test.js +++ b/packages/tools/test/ProbeTool_test.js @@ -95,7 +95,7 @@ describe('Probe Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -735,7 +735,7 @@ describe('Probe Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/RectangleROI_test.js b/packages/tools/test/RectangleROI_test.js index d50dc5bd5..69973908b 100644 --- a/packages/tools/test/RectangleROI_test.js +++ b/packages/tools/test/RectangleROI_test.js @@ -95,7 +95,7 @@ describe('Rectangle Roi Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -828,7 +828,7 @@ describe('Rectangle Roi Tool: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/StackScrollToolMouseWheelTool_test.js b/packages/tools/test/StackScrollToolMouseWheelTool_test.js index be19eb74e..45355943f 100644 --- a/packages/tools/test/StackScrollToolMouseWheelTool_test.js +++ b/packages/tools/test/StackScrollToolMouseWheelTool_test.js @@ -89,7 +89,7 @@ describe('Cornerstone Tools Scroll Wheel: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId(StackScrollTool.toolName) + ToolGroupManager.destroyToolGroupById(StackScrollTool.toolName) this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/ToolGroupManager_test.js b/packages/tools/test/ToolGroupManager_test.js index 4853d7362..a1e938e9a 100644 --- a/packages/tools/test/ToolGroupManager_test.js +++ b/packages/tools/test/ToolGroupManager_test.js @@ -118,7 +118,7 @@ describe('ToolGroup Manager: ', () => { this.toolGroup.addViewport(viewportId1, this.renderingEngine.id) - const tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + const tg = ToolGroupManager.getToolGroupById('volume1') expect(tg).toBeDefined() }) }) @@ -147,7 +147,7 @@ describe('ToolGroup Manager: ', () => { afterEach(function () { // Destroy synchronizer manager to test it first since csTools3D also destroy // synchronizers - ToolGroupManager.destroyToolGroupByToolGroupId('volume1') + ToolGroupManager.destroyToolGroupById('volume1') csTools3d.destroy() cache.purgeCache() this.renderingEngine.destroy() @@ -188,7 +188,7 @@ describe('ToolGroup Manager: ', () => { this.toolGroup.addViewport(viewportId1, this.renderingEngine.id) - const tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + const tg = ToolGroupManager.getToolGroupById('volume1') expect(tg).toBeDefined() const tg2 = ToolGroupManager.getToolGroup(viewportId1, renderingEngineId) @@ -229,19 +229,19 @@ describe('ToolGroup Manager: ', () => { ]) // Remove viewports - let tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + let tg = ToolGroupManager.getToolGroupById('volume1') tg.addViewport(viewportId1, this.renderingEngine.id) expect(tg.viewportsInfo.length).toBe(1) tg.removeViewports(renderingEngineId) - tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + tg = ToolGroupManager.getToolGroupById('volume1') expect(tg.viewportsInfo.length).toBe(0) // tg.addViewport(viewportId1, this.renderingEngine.id) - tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + tg = ToolGroupManager.getToolGroupById('volume1') expect(tg.viewportsInfo.length).toBe(1) tg.removeViewports(renderingEngineId, viewportId2) @@ -277,7 +277,7 @@ describe('ToolGroup Manager: ', () => { this.toolGroup.addViewport(viewportId1, this.renderingEngine.id) // Remove viewports - let tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + let tg = ToolGroupManager.getToolGroupById('volume1') expect(tg.getToolInstance(ProbeTool.toolName).mode).toBe('Active') expect(tg.getToolInstance(LengthTool.toolName)).toBeUndefined() @@ -314,7 +314,7 @@ describe('ToolGroup Manager: ', () => { this.toolGroup.addViewport(viewportId1, this.renderingEngine.id) // Remove viewports - let tg = ToolGroupManager.getToolGroupByToolGroupId('volume1') + let tg = ToolGroupManager.getToolGroupById('volume1') tg.setToolActive() tg.setToolPassive() tg.setToolEnabled() diff --git a/packages/tools/test/cpu_BidirectionalTool_test.js b/packages/tools/test/cpu_BidirectionalTool_test.js index 7b1aa1e49..9f6b45d7e 100644 --- a/packages/tools/test/cpu_BidirectionalTool_test.js +++ b/packages/tools/test/cpu_BidirectionalTool_test.js @@ -108,7 +108,7 @@ describe('Bidirectional Tool (CPU): ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/cpu_EllipseROI_test.js b/packages/tools/test/cpu_EllipseROI_test.js index 01d60b2e0..f00b1d6dc 100644 --- a/packages/tools/test/cpu_EllipseROI_test.js +++ b/packages/tools/test/cpu_EllipseROI_test.js @@ -102,7 +102,7 @@ describe('EllipticalRoiTool (CPU):', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/cpu_LengthTool_test.js b/packages/tools/test/cpu_LengthTool_test.js index 35741c7d1..910c1c97a 100644 --- a/packages/tools/test/cpu_LengthTool_test.js +++ b/packages/tools/test/cpu_LengthTool_test.js @@ -107,7 +107,7 @@ describe('Length Tool (CPU):', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/cpu_ProbeTool_test.js b/packages/tools/test/cpu_ProbeTool_test.js index e61ff9c3d..9dea5327d 100644 --- a/packages/tools/test/cpu_ProbeTool_test.js +++ b/packages/tools/test/cpu_ProbeTool_test.js @@ -101,7 +101,7 @@ describe('ProbeTool (CPU):', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/cpu_RectangleROI_test.js b/packages/tools/test/cpu_RectangleROI_test.js index c93110342..f6c9d6c78 100644 --- a/packages/tools/test/cpu_RectangleROI_test.js +++ b/packages/tools/test/cpu_RectangleROI_test.js @@ -100,7 +100,7 @@ describe('RectangleRoiTool (CPU):', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) imageLoader.unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('stack') + ToolGroupManager.destroyToolGroupById('stack') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationConfigController_test.js b/packages/tools/test/segmentationConfigController_test.js index a1afc1b0c..4a7096688 100644 --- a/packages/tools/test/segmentationConfigController_test.js +++ b/packages/tools/test/segmentationConfigController_test.js @@ -108,7 +108,7 @@ describe('Segmentation Controller --', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId(TOOL_GROUP_ID) + ToolGroupManager.destroyToolGroupById(TOOL_GROUP_ID) this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationRectangleScissor_test.js b/packages/tools/test/segmentationRectangleScissor_test.js index 76ccafaa6..f6ac0b9f1 100644 --- a/packages/tools/test/segmentationRectangleScissor_test.js +++ b/packages/tools/test/segmentationRectangleScissor_test.js @@ -108,7 +108,7 @@ describe('Segmentation Tools --', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('segToolGroup') + ToolGroupManager.destroyToolGroupById('segToolGroup') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationRender_test.js b/packages/tools/test/segmentationRender_test.js index 66f8c9a7b..6799ca8eb 100644 --- a/packages/tools/test/segmentationRender_test.js +++ b/packages/tools/test/segmentationRender_test.js @@ -106,7 +106,7 @@ describe('Segmentation Render -- ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('segToolGroup') + ToolGroupManager.destroyToolGroupById('segToolGroup') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationSegmentIndexController_test.js b/packages/tools/test/segmentationSegmentIndexController_test.js index fe691fe6a..ed1b2ee29 100644 --- a/packages/tools/test/segmentationSegmentIndexController_test.js +++ b/packages/tools/test/segmentationSegmentIndexController_test.js @@ -109,7 +109,7 @@ describe('Segmentation Index Controller --', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId(TOOL_GROUP_ID) + ToolGroupManager.destroyToolGroupById(TOOL_GROUP_ID) this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationSphereScissor_test.js b/packages/tools/test/segmentationSphereScissor_test.js index 2408c7ec6..6b77f7532 100644 --- a/packages/tools/test/segmentationSphereScissor_test.js +++ b/packages/tools/test/segmentationSphereScissor_test.js @@ -110,7 +110,7 @@ describe('Segmentation Tools --', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('segToolGroup') + ToolGroupManager.destroyToolGroupById('segToolGroup') this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/segmentationState_test.js b/packages/tools/test/segmentationState_test.js index 9104bdd8c..19d96df25 100644 --- a/packages/tools/test/segmentationState_test.js +++ b/packages/tools/test/segmentationState_test.js @@ -94,7 +94,7 @@ describe('Segmentation State -- ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('segToolGroup') + ToolGroupManager.destroyToolGroupById('segToolGroup') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -115,8 +115,7 @@ describe('Segmentation State -- ', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const globalState = - segmentation.state.getGlobalSegmentationDataByUID(segVolumeId) + const globalState = segmentation.state.getSegmentation(segVolumeId) expect(evt.detail.segmentationUID.includes(segVolumeId)).toBe(true) diff --git a/packages/tools/test/segmentationVisibilityController_test.js b/packages/tools/test/segmentationVisibilityController_test.js index 2eb1c133f..81b9f2be3 100644 --- a/packages/tools/test/segmentationVisibilityController_test.js +++ b/packages/tools/test/segmentationVisibilityController_test.js @@ -105,7 +105,7 @@ describe('Segmentation Controller --', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId(TOOL_GROUP_ID) + ToolGroupManager.destroyToolGroupById(TOOL_GROUP_ID) this.DOMElements.forEach((el) => { if (el.parentNode) { diff --git a/packages/tools/test/synchronizerManager_test.js b/packages/tools/test/synchronizerManager_test.js index cd351e19b..9af155b7b 100644 --- a/packages/tools/test/synchronizerManager_test.js +++ b/packages/tools/test/synchronizerManager_test.js @@ -92,7 +92,7 @@ describe('Synchronizer Manager: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('volume1') + ToolGroupManager.destroyToolGroupById('volume1') this.DOMElements.forEach((el) => { if (el.parentNode) { @@ -236,7 +236,7 @@ describe('Synchronizer Manager: ', () => { this.renderingEngine.destroy() metaData.removeProvider(fakeMetaDataProvider) unregisterAllImageLoaders() - ToolGroupManager.destroyToolGroupByToolGroupId('volume1') + ToolGroupManager.destroyToolGroupById('volume1') this.DOMElements.forEach((el) => { if (el.parentNode) { From eb44e9c6073540e0b12faeab2e187d75dc2cd4ed Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 25 Mar 2022 09:27:37 -0400 Subject: [PATCH 03/20] renamed segmentation state types --- packages/tools/src/types/LabelmapTypes.ts | 2 +- .../tools/src/types/SegmentationStateTypes.ts | 157 ++++++++++++++---- 2 files changed, 130 insertions(+), 29 deletions(-) diff --git a/packages/tools/src/types/LabelmapTypes.ts b/packages/tools/src/types/LabelmapTypes.ts index 4e627a292..e58fcb613 100644 --- a/packages/tools/src/types/LabelmapTypes.ts +++ b/packages/tools/src/types/LabelmapTypes.ts @@ -11,7 +11,7 @@ export type LabelmapRenderingConfig = { ofun?: vtkPiecewiseFunction } -export type LabelmapMainRepresentation = { +export type LabelmapRepresentationData = { volumeId: string referenceVolumeId?: string } diff --git a/packages/tools/src/types/SegmentationStateTypes.ts b/packages/tools/src/types/SegmentationStateTypes.ts index 6b4b88479..e71bfd89b 100644 --- a/packages/tools/src/types/SegmentationStateTypes.ts +++ b/packages/tools/src/types/SegmentationStateTypes.ts @@ -1,7 +1,7 @@ -import SegmentationRepresentations from '../enums/SegmentationRepresentations' +import * as Enums from '../enums' import type { LabelmapConfig } from '../tools/displayTools/Labelmap/LabelmapConfig' -import { - LabelmapMainRepresentation, +import type { + LabelmapRepresentationData, LabelmapRenderingConfig, } from './LabelmapTypes' @@ -19,22 +19,31 @@ export type ColorLUT = Array /** * Segmentation Config */ + +export type RepresentationConfig = { + /** labelmap configuration */ + LABELMAP?: LabelmapConfig +} + export type SegmentationRepresentationConfig = { /** Whether to render Inactive segmentations */ renderInactiveSegmentations: boolean /** Representations configuration */ - representations: { - /** labelmap configuration */ - LABELMAP?: LabelmapConfig - } + representations: RepresentationConfig +} + +type SegmentationRepresentationData = { + LABELMAP?: LabelmapRepresentationData } /** * Global Segmentation Data which is used for the segmentation */ export type Segmentation = { + /** segmentation id */ segmentationId: string - type: SegmentationRepresentations + /** segmentation main representation type */ + type: Enums.SegmentationRepresentations /** segmentation label */ label: string /** @@ -51,16 +60,33 @@ export type Segmentation = { * If there is any derived statistics for the segmentation (e.g., mean, volume, etc) */ cachedStats: { [key: string]: number } - - representations: { - LABELMAP?: LabelmapMainRepresentation - } + /** + * Representations of the segmentation. Each segmentation "can" be viewed + * in various representations. For instance, if a DICOM SEG is loaded, the main + * representation is the labelmap. However, for DICOM RT the main representation + * is contours, and other representations can be derived from the contour (currently + * only labelmap representation is supported) + */ + representations: SegmentationRepresentationData } -type RepresentationData = { +/** + * Representation state of the segmentation which is common between all + * representations (we don't need to separate these states for each representation) + */ +type ToolGroupSpecificRepresentationState = { + /** + * Segmentation Representation UID + */ segmentationRepresentationUID: string + /** + * The segmentationId that this representation is derived from + */ segmentationId: string - type: SegmentationRepresentations + /** + * The representation type + */ + type: Enums.SegmentationRepresentations /** * Whether the segmentation is the active (manipulatable) segmentation or not * which means it is inactive @@ -86,9 +112,90 @@ type RepresentationData = { * can be represented in various ways (currently only labelmap is supported) * we store ToolGroup specific segmentation data in this object */ -export type ToolGroupSpecificSegmentationRepresentation = RepresentationData & - LabelmapRenderingConfig // Todo: add more representations +export type ToolGroupSpecificLabelmapRepresentation = + ToolGroupSpecificRepresentationState & LabelmapRenderingConfig + +export type ToolGroupSpecificRepresentation = + ToolGroupSpecificLabelmapRepresentation // | other ones +/** + * Segmentation State stored inside the cornerstone3DTools + * + * ```js + * { + * colorLUT: [], + * globalConfig: { + * renderInactiveSegmentations: false, + * representations: { + * LABELMAP: { + * renderFill: true, + * renderOutline: true, + * }, + * }, + * }, + * segmentations: [ + * { + * segmentationId: 'segmentation1', + * mainType: 'Labelmap', + * activeSegmentIndex: 0, + * segmentsLocked: new Set(), + * label: 'segmentation1', + * cachedStats: {}, + * representations: { + * LABELMAP: { + * volumeId: 'segmentation1', + * }, + * CONTOUR: { + * point: Float32Array, + * }, + * }, + * }, + * { + * segmentationId: 'segmentation2', + * type: 'Labelmap', + * activeSegmentIndex: 1, + * segmentsLocked: new Set(), + * label: 'segmentation2', + * cachedStats: {}, + * representations: { + * CONTOUR: { + * points: Float32Array, + * }, + * }, + * }, + * ], + * toolGroups: { + * toolGroupUID1: { + * segmentationRepresentations: [ + * { + * segmentationRepresentationUID: '12123123123132', + * segmentationId: '123123', + * type: 'Labelmap', + * active: true, + * colorLUTIndex: 0, + * visibility: true, + * segmentsHidden: Set(), + * // LabelmapRenderingConfig + * config: { + * "cfun", + * "ofun", + * }, + * }, + * ], + * config: { + * renderInactiveSegmentations: false, + * representations: { + * LABELMAP: { + * renderFill: true, + * renderOutline: true, + * }, + * }, + * }, + * }, + * }, + * } + * ``` + */ export interface SegmentationState { /** Array of colorLUT for segmentation to render */ colorLutTables: ColorLUT[] @@ -100,22 +207,16 @@ export interface SegmentationState { toolGroups: { /** toolGroupId and their toolGroup specific segmentation state with config */ [key: string]: { - segmentationRepresentations: ToolGroupSpecificSegmentationRepresentation[] + segmentationRepresentations: ToolGroupSpecificRepresentation[] config: SegmentationRepresentationConfig } } } export type SegmentationPublicInput = { - type: SegmentationRepresentations - representationProps: LabelmapMainRepresentation + segmentationId: string + representationData: { + type: Enums.SegmentationRepresentations + data: LabelmapRepresentationData + } } - -/** - * SegmentationDataInput that is used to add a segmentation to - * a tooLGroup. It is partial of ToolGroupSpecificSegmentationData BUT REQUIRES volumeId - */ -// export type SegmentationDataInput = -// Partial & { -// toolGroupId: string -// } From 865852adec4c9611c9dea547c322ee840ab93eeb Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 25 Mar 2022 09:56:24 -0400 Subject: [PATCH 04/20] add segmentation to global --- .../segmentation/addSegmentations.ts | 27 ++++++++++ .../segmentation/helpers/index.ts | 4 +- .../helpers/validateSegmentationInput.ts | 41 ++++++++++++++ .../helpers/validateSegmentationInputArray.ts | 35 ------------ .../segmentation/segmentationState.ts | 54 ++++++++++++------- .../segmentation/triggerSegmentationEvents.ts | 4 +- .../Labelmap/validateRepresentationData.ts | 28 ++++++++++ .../tools/src/types/SegmentationStateTypes.ts | 2 +- 8 files changed, 136 insertions(+), 59 deletions(-) create mode 100644 packages/tools/src/stateManagement/segmentation/addSegmentations.ts create mode 100644 packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInput.ts delete mode 100644 packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts create mode 100644 packages/tools/src/tools/displayTools/Labelmap/validateRepresentationData.ts diff --git a/packages/tools/src/stateManagement/segmentation/addSegmentations.ts b/packages/tools/src/stateManagement/segmentation/addSegmentations.ts new file mode 100644 index 000000000..0f91b83f4 --- /dev/null +++ b/packages/tools/src/stateManagement/segmentation/addSegmentations.ts @@ -0,0 +1,27 @@ +import _cloneDeep from 'lodash.clonedeep' +import { SegmentationPublicInput } from '../../types/SegmentationStateTypes' +import { validateSegmentationInput } from './helpers' +import { addSegmentation as addSegmentationToState } from './segmentationState' +/** + * Adds the segmentation to the cornerstone3D segmentation state. It should be + * noted that segmentations are not added to any toolGroup's viewports. In order to + * do so, you should add a "representation" of the segmentation to the toolGroup + * using setSegmentationRepresentation helper. The reason for this is that there + * can be multiple representations of the same segmentation (e.g. Labelmap and + * Contour, etc. - Currently only Labelmap representations is supported). + * @param segmentationInputArray - The array of segmentation input, each of which + * defining the segmentationId and the main representation data for the segmentation. + */ +function addSegmentations( + segmentationInputArray: SegmentationPublicInput[] +): void { + validateSegmentationInput(segmentationInputArray) + + segmentationInputArray.map(async (segInput) => { + const segmentationInput = _cloneDeep(segInput) + + addSegmentationToState(segmentationInput) + }) +} + +export default addSegmentations diff --git a/packages/tools/src/stateManagement/segmentation/helpers/index.ts b/packages/tools/src/stateManagement/segmentation/helpers/index.ts index 371371b5b..1b3d28328 100644 --- a/packages/tools/src/stateManagement/segmentation/helpers/index.ts +++ b/packages/tools/src/stateManagement/segmentation/helpers/index.ts @@ -1,9 +1,9 @@ -import validateSegmentationInputArray from './validateSegmentationInputArray' +import validateSegmentationInput from './validateSegmentationInput' import internalAddSegmentationToElement from './internalAddSegmentationToElement' import internalRemoveSegmentationFromElement from './internalRemoveSegmentationFromElement' export { - validateSegmentationInputArray, + validateSegmentationInput, internalAddSegmentationToElement, internalRemoveSegmentationFromElement, } diff --git a/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInput.ts b/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInput.ts new file mode 100644 index 000000000..f9c0658a4 --- /dev/null +++ b/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInput.ts @@ -0,0 +1,41 @@ +import * as Enums from '../../../enums' +import { SegmentationPublicInput } from '../../../types/SegmentationStateTypes' +import validateLabelmap from '../../../tools/displayTools/Labelmap/validateRepresentationData' + +/** + * Checks if the segmentationInputArray is valid meaning it contains + * correct representationProps for the representation type that is being used. + * + * @param segmentationInputArray - Array of segmentation inputs + * @internal + */ +function validateSegmentationInput( + segmentationInputArray: SegmentationPublicInput[] +): void { + if (!segmentationInputArray || !segmentationInputArray.length) { + throw new Error('The segmentationInputArray undefined or empty array') + } + + segmentationInputArray.forEach((segmentationInput) => { + if (segmentationInput.segmentationId === undefined) { + throw new Error( + 'The segmentationInput.segmentationId is undefined, please provide a valid segmentationId' + ) + } + + if (segmentationInput.representation === undefined) { + throw new Error( + 'The segmentationInput.representation is undefined, please provide a valid representation' + ) + } + + if ( + segmentationInput.representation.type === + Enums.SegmentationRepresentations.Labelmap + ) { + validateLabelmap(segmentationInput) + } + }) +} + +export default validateSegmentationInput diff --git a/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts b/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts deleted file mode 100644 index 51f25ea9e..000000000 --- a/packages/tools/src/stateManagement/segmentation/helpers/validateSegmentationInputArray.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { SegmentationRepresentations } from 'tools/src/enums' -import { SegmentationPublicInput } from '../../../types/SegmentationStateTypes' - -/** - * Checks if the segmentationInputArray is valid meaning it contains - * correct representationProps for the representation type that is being used. - * - * @param segmentationInputArray - Array of segmentation inputs - * @internal - */ -function validateSegmentationInputArray( - segmentationInputArray: SegmentationPublicInput[] -): void { - if (!segmentationInputArray || !segmentationInputArray.length) { - throw new Error('The segmentationInputArray undefined or empty array') - } - - segmentationInputArray.forEach((segmentationInput) => { - if (segmentationInput.type === SegmentationRepresentations.Labelmap) { - _validateLabelmapRepresentationProp(segmentationInput) - } - }) -} - -function _validateLabelmapRepresentationProp( - segmentationInput: SegmentationPublicInput -): void { - if (!segmentationInput.representationProps.volumeId) { - throw new Error( - 'The segmentationInput.representationProps.volumeId is undefined' - ) - } -} - -export default validateSegmentationInputArray diff --git a/packages/tools/src/stateManagement/segmentation/segmentationState.ts b/packages/tools/src/stateManagement/segmentation/segmentationState.ts index 93d14f02e..072153b9a 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationState.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationState.ts @@ -3,7 +3,11 @@ import { triggerSegmentationStateModified, triggerSegmentationGlobalStateModified, } from './triggerSegmentationEvents' -import { ColorLUT, Segmentation } from '../../types/SegmentationStateTypes' +import { + ColorLUT, + Segmentation, + SegmentationPublicInput, +} from '../../types/SegmentationStateTypes' import { getDefaultRepresentationConfig, @@ -34,6 +38,17 @@ function getSegmentation(segmentationId: string): Segmentation | undefined { return segmentationStateManager.getSegmentation(segmentationId) } +function addSegmentation( + segmentationInput: SegmentationPublicInput, + suppressEvents?: boolean +): void { + const segmentationStateManager = getDefaultSegmentationStateManager() + segmentationStateManager.addSegmentation(segmentationInput) + if (!suppressEvents) { + triggerSegmentationGlobalStateModified(segmentationInput.segmentationId) + } +} + /** * Add a new global segmentation data to the segmentation state manager, and * triggers SEGMENTATION_STATE_MODIFIED event if not suppressed. @@ -415,27 +430,28 @@ function _initGlobalStateIfNecessary( } export { + getSegmentation, + addSegmentation, // config - getGlobalSegmentationConfig, - getSegmentationConfig, - setGlobalSegmentationConfig, - setSegmentationConfig, + // getGlobalSegmentationConfig, + // getSegmentationConfig, + // setGlobalSegmentationConfig, + // setSegmentationConfig, // colorLUT - addColorLUT, - getColorLut, + // addColorLUT, + // getColorLut, // get/set global state - getGlobalSegmentationState, - getSegmentation, - addGlobalSegmentationData, + // getGlobalSegmentationState, + // addGlobalSegmentationData, // toolGroup state - getSegmentationState, - addSegmentationData, - removeSegmentationData, - getSegmentationDataByUID, - setActiveSegmentationData, - getActiveSegmentationData, - getToolGroupsWithSegmentation, - getToolGroups, + // getSegmentationState, + // addSegmentationData, + // removeSegmentationData, + // getSegmentationDataByUID, + // setActiveSegmentationData, + // getActiveSegmentationData, + // getToolGroupsWithSegmentation, + // getToolGroups, // Utility - getDefaultSegmentationStateManager, + // getDefaultSegmentationStateManager, } diff --git a/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts b/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts index 7757a6a03..7c1c97de6 100644 --- a/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts +++ b/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts @@ -27,11 +27,11 @@ function triggerSegmentationStateModified(toolGroupId: string): void { /** * Triggers segmentation global state updated event, notifying all toolGroups - * that the global state has been updated, If a segmentationUID is provided + * that the global state has been updated, If a segmentationId is provided * the event will only be triggered for that segmentation, otherwise it will * be triggered for all segmentations. * - * @param segmentationUID - The UID of the segmentation that has been updated + * @param segmentationId - The id of the segmentation that has been updated */ function triggerSegmentationGlobalStateModified( segmentationUID?: string diff --git a/packages/tools/src/tools/displayTools/Labelmap/validateRepresentationData.ts b/packages/tools/src/tools/displayTools/Labelmap/validateRepresentationData.ts new file mode 100644 index 000000000..29cd9673a --- /dev/null +++ b/packages/tools/src/tools/displayTools/Labelmap/validateRepresentationData.ts @@ -0,0 +1,28 @@ +import { SegmentationPublicInput } from 'tools/src/types/SegmentationStateTypes' +import { cache } from '@cornerstonejs/core' + +function validate(segmentationInput: SegmentationPublicInput): void { + if (!segmentationInput.representation.data) { + throw new Error( + 'The segmentationInput.representationData.data is undefined, please provide a valid representationData.data' + ) + } + + const representationData = segmentationInput.representation.data + + if (!representationData.volumeId) { + throw new Error( + 'The segmentationInput.representationData.volumeId is undefined, please provide a valid representationData.volumeId' + ) + } + + const cachedVolume = cache.getVolume(representationData.volumeId) + + if (!cachedVolume) { + throw new Error( + `volumeId of ${representationData.volumeId} not found in cache, you should load and cache volume before adding segmentation` + ) + } +} + +export default validate diff --git a/packages/tools/src/types/SegmentationStateTypes.ts b/packages/tools/src/types/SegmentationStateTypes.ts index e71bfd89b..8a3623620 100644 --- a/packages/tools/src/types/SegmentationStateTypes.ts +++ b/packages/tools/src/types/SegmentationStateTypes.ts @@ -215,7 +215,7 @@ export interface SegmentationState { export type SegmentationPublicInput = { segmentationId: string - representationData: { + representation: { type: Enums.SegmentationRepresentations data: LabelmapRepresentationData } From d785a9c7ab2f6478028e3889dd0c8703b3b31b5b Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 25 Mar 2022 10:25:37 -0400 Subject: [PATCH 05/20] rename segmentationUID to segmentationId --- common/reviews/api/tools.api.md | 20 +++++----- .../demo/src/ExampleSegmentationRender.tsx | 24 +++++------ .../segmentation/SegmentationStateManager.ts | 18 ++++----- .../segmentation/activeSegmentation.ts | 2 +- .../createNewSegmentationForToolGroup.ts | 8 ++-- .../helpers/normalizeSegmentationInput.ts | 28 +++++++++++++ .../segmentation/segmentIndex.ts | 22 +++++----- .../segmentation/segmentLocking.ts | 40 +++++++++---------- .../segmentation/segmentationColor.ts | 2 +- .../segmentation/segmentationState.ts | 20 +++++----- .../segmentation/segmentationVisibility.ts | 4 +- .../segmentation/triggerSegmentationEvents.ts | 20 +++++----- .../displayTools/Labelmap/LabelmapDisplay.ts | 4 +- .../displayTools/SegmentationDisplayTool.ts | 2 +- .../segmentation/RectangleRoiThresholdTool.ts | 4 +- packages/tools/src/types/EventTypes.ts | 2 +- .../test/segmentationRectangleScissor_test.js | 24 +++++------ ...segmentationSegmentIndexController_test.js | 24 +++++------ .../test/segmentationSphereScissor_test.js | 8 ++-- packages/tools/test/segmentationState_test.js | 2 +- 20 files changed, 153 insertions(+), 125 deletions(-) create mode 100644 packages/tools/src/stateManagement/segmentation/helpers/normalizeSegmentationInput.ts diff --git a/common/reviews/api/tools.api.md b/common/reviews/api/tools.api.md index ba23ca36d..9066c1c6f 100644 --- a/common/reviews/api/tools.api.md +++ b/common/reviews/api/tools.api.md @@ -1108,7 +1108,7 @@ function getActiveSegmentationInfo(toolGroupId: string): { function getActiveSegmentIndex(toolGroupId: string): number | undefined; // @public (undocumented) -function getActiveSegmentIndexForSegmentation(segmentationUID: string): number | undefined; +function getActiveSegmentIndexForSegmentation(segmentationId: string): number | undefined; // @public (undocumented) function getAllSynchronizers(): Array; @@ -1180,7 +1180,7 @@ function getGlobalSegmentationConfig(): SegmentationConfig; function getGlobalSegmentationConfig_2(): SegmentationConfig; // @public (undocumented) -function getSegmentation(segmentationUID: string): GlobalSegmentationData; +function getSegmentation(segmentationId: string): GlobalSegmentationData; // @public (undocumented) function getGlobalSegmentationState(): GlobalSegmentationState | []; @@ -1210,10 +1210,10 @@ function getSegmentationVisibility(toolGroupId: string, segmentationDataUID: str function getSegmentIndexLocked(toolGroupId: string, segmentIndex: number): boolean; // @public (undocumented) -function getSegmentIndexLockedForSegmentation(segmentationUID: string, segmentIndex: number): boolean; +function getSegmentIndexLockedForSegmentation(segmentationId: string, segmentIndex: number): boolean; // @public (undocumented) -function getSegmentsLockedForSegmentation(segmentationUID: string): number[] | []; +function getSegmentsLockedForSegmentation(segmentationId: string): number[] | []; // @public (undocumented) function getSliceRange(volumeActor: Types_2.VolumeActor, viewPlaneNormal: Types_2.Point3, focalPoint: Types_2.Point3): { @@ -1247,7 +1247,7 @@ function getToolGroupById(toolGroupId: string): IToolGroup | undefined; function getToolGroups(): string[]; // @public (undocumented) -function getToolGroupsWithSegmentation(segmentationUID: string): string[]; +function getToolGroupsWithSegmentation(segmentationId: string): string[]; // @public (undocumented) function getViewportIdsWithToolToRender(element: HTMLElement, toolName: string, requireSameOrientation?: boolean): string[]; @@ -2398,7 +2398,7 @@ export class RectangleRoiThresholdTool extends RectangleRoiTool { points: Types_2.Point3[]; activeHandleIndex: any; }; - segmentationUID: any; + segmentationId: any; }; }; // (undocumented) @@ -2646,7 +2646,7 @@ export class SegmentationDisplayTool extends BaseTool { // @public (undocumented) type SegmentationGlobalStateModifiedEventDetail = { - segmentationUID: string; + segmentationId: string; }; // @public (undocumented) @@ -2719,7 +2719,7 @@ function setActiveSegmentationData(toolGroupId: string, segmentationDataUID: str function setActiveSegmentIndex(toolGroupId: string, segmentIndex: number): void; // @public (undocumented) -function setActiveSegmentIndexForSegmentation(segmentationUID: string, segmentIndex: number): void; +function setActiveSegmentIndexForSegmentation(segmentationId: string, segmentIndex: number): void; // @public (undocumented) function setAnnotationLocked(annotation: Annotation, locked?: boolean): void; @@ -2764,7 +2764,7 @@ function setSegmentationVisibility(toolGroupId: string, segmentationDataUID: str function setSegmentIndexLocked(toolGroupId: string, segmentIndex: number, locked?: boolean): void; // @public (undocumented) -function setSegmentIndexLockedForSegmentation(segmentationUID: string, segmentIndex: number, locked?: boolean): void; +function setSegmentIndexLockedForSegmentation(segmentationId: string, segmentIndex: number, locked?: boolean): void; // @public (undocumented) type SetToolBindingsType = { @@ -3089,7 +3089,7 @@ declare namespace triggerSegmentationEvents { } // @public (undocumented) -function triggerSegmentationGlobalStateModified(segmentationUID?: string): void; +function triggerSegmentationGlobalStateModified(segmentationId?: string): void; // @public (undocumented) function triggerSegmentationStateModified(toolGroupId: string): void; diff --git a/packages/demo/src/ExampleSegmentationRender.tsx b/packages/demo/src/ExampleSegmentationRender.tsx index a32a55a52..9422ee922 100644 --- a/packages/demo/src/ExampleSegmentationRender.tsx +++ b/packages/demo/src/ExampleSegmentationRender.tsx @@ -346,7 +346,7 @@ class SegmentationExample extends Component { } onGlobalSegmentationStateUpdated = (evt) => { - const { segmentationUID } = evt.detail + const { segmentationId } = evt.detail const allSegmentationUIDs = segmentation.state .getGlobalSegmentationState() .map(({ volumeId }) => volumeId) @@ -426,12 +426,12 @@ class SegmentationExample extends Component { segmentation .createNewSegmentationForToolGroup(this.state.selectedToolGroupName) - .then((segmentationUID) => { + .then((segmentationId) => { segmentation.addSegmentationsForToolGroup( this.state.selectedToolGroupName, [ { - volumeId: segmentationUID, + volumeId: segmentationId, // default representation which is labelmap }, ] @@ -546,13 +546,13 @@ class SegmentationExample extends Component { this.setState({ segmentationStatus: 'done' }) } - loadSegmentation = async (segmentationUID, initialConfig) => { + loadSegmentation = async (segmentationId, initialConfig) => { const toolGroupId = this.state.selectedToolGroupName if (!initialConfig) { await segmentation.addSegmentationsForToolGroup(toolGroupId, [ { - volumeId: segmentationUID, + volumeId: segmentationId, active: true, representation: { type: csToolsEnums.SegmentationRepresentations.Labelmap, @@ -1155,9 +1155,9 @@ class SegmentationExample extends Component { }} size={3} > - {this.state.allSegmentationUIDs.map((segmentationUID) => ( - ))} @@ -1224,12 +1224,12 @@ class SegmentationExample extends Component { size={3} > {this.state.selectedToolGroupSegmentationDataUIDs.map( - (segmentationUID) => ( + (segmentationId) => ( ) )} diff --git a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts index 763d38f29..cdc686ce5 100644 --- a/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts +++ b/packages/tools/src/stateManagement/segmentation/SegmentationStateManager.ts @@ -80,16 +80,16 @@ export default class SegmentationStateManager { } /** - * Given a segmentation UID, return the global segmentation data for that + * Given a segmentation Id, return the global segmentation data for that * segmentation - * @param segmentationUID - The UID of the segmentation to get the + * @param segmentationId - The id of the segmentation to get the * global data for. * @returns - The global segmentation data for the - * segmentation with the given UID. + * segmentation with the given Id. */ - getSegmentation(segmentationUID: string): GlobalSegmentationData | undefined { + getSegmentation(segmentationId: string): GlobalSegmentationData | undefined { return this.state.global.segmentations?.find( - (segmentationState) => segmentationState.volumeId === segmentationUID + (segmentationState) => segmentationState.volumeId === segmentationId ) } @@ -121,13 +121,13 @@ export default class SegmentationStateManager { } /** - * Given a segmentation UID, return a list of tool group IDs that have that + * Given a segmentation Id, return a list of tool group IDs that have that * segmentation in their segmentation state (segmentation has been added * to the tool group). - * @param segmentationUID - The UID of the segmentation volume. + * @param segmentationId - The id of the segmentation volume. * @returns An array of toolGroupIds. */ - getToolGroupsWithSegmentation(segmentationUID: string): string[] { + getToolGroupsWithSegmentation(segmentationId: string): string[] { const toolGroupIds = Object.keys(this.state.toolGroups) const foundToolGroupIds = [] @@ -137,7 +137,7 @@ export default class SegmentationStateManager { ) as ToolGroupSpecificSegmentationState const segmentationData = toolGroupSegmentationState.find( - (segmentationData) => segmentationData.volumeId === segmentationUID + (segmentationData) => segmentationData.volumeId === segmentationId ) if (segmentationData) { diff --git a/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts b/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts index 0abb54c2c..3110a592a 100644 --- a/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts +++ b/packages/tools/src/stateManagement/segmentation/activeSegmentation.ts @@ -35,7 +35,7 @@ function getActiveSegmentationInfo(toolGroupId: string): { * * @param toolGroupId - The Id of the tool group to set the active * segmentation for. - * @param segmentationDataUID - The UID of the segmentation data to set as + * @param segmentationDataUID - The id of the segmentation data to set as * active. */ function setActiveSegmentation( diff --git a/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts b/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts index 0db2e9620..1d194496d 100644 --- a/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts +++ b/packages/tools/src/stateManagement/segmentation/createNewSegmentationForToolGroup.ts @@ -54,7 +54,7 @@ async function createNewSegmentationForToolGroup( const { uid } = viewport.getDefaultActor() // Name the segmentation volume with the viewport Id - const segmentationUID = `${uid}-based-segmentation-${ + const segmentationId = `${uid}-based-segmentation-${ options?.volumeId ?? csUtils.uuidv4().slice(0, 8) }` @@ -62,16 +62,16 @@ async function createNewSegmentationForToolGroup( // create a new labelmap with its own properties // This allows creation of a higher resolution labelmap vs reference volume const properties = _cloneDeep(options) - await volumeLoader.createLocalVolume(properties, segmentationUID) + await volumeLoader.createLocalVolume(properties, segmentationId) } else { // create a labelmap from a reference volume const { uid: volumeId } = viewport.getDefaultActor() await volumeLoader.createAndCacheDerivedVolume(volumeId, { - volumeId: segmentationUID, + volumeId: segmentationId, }) } - return segmentationUID + return segmentationId } export default createNewSegmentationForToolGroup diff --git a/packages/tools/src/stateManagement/segmentation/helpers/normalizeSegmentationInput.ts b/packages/tools/src/stateManagement/segmentation/helpers/normalizeSegmentationInput.ts new file mode 100644 index 000000000..5b76f3a2d --- /dev/null +++ b/packages/tools/src/stateManagement/segmentation/helpers/normalizeSegmentationInput.ts @@ -0,0 +1,28 @@ +import { + SegmentationPublicInput, + Segmentation, +} from '../../../types/SegmentationStateTypes' + +function normalizeSegmentationInput( + segmentationInput: SegmentationPublicInput +): Segmentation { + const { segmentationId, representation } = segmentationInput + + // Todo: we should be able to let the user pass in non-default values for + // cachedStats, label, activeSegmentIndex, etc. + return { + segmentationId, + cachedStats: {}, + label: segmentationId, + segmentsLocked: new Set(), + type: representation.type, + activeSegmentIndex: 0, + representations: { + [representation.type]: { + ...representation.data, + }, + }, + } +} + +export default normalizeSegmentationInput diff --git a/packages/tools/src/stateManagement/segmentation/segmentIndex.ts b/packages/tools/src/stateManagement/segmentation/segmentIndex.ts index 2cfdd825b..a8296ee34 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentIndex.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentIndex.ts @@ -41,46 +41,46 @@ function setActiveSegmentIndex( throw new Error('element does not contain an active segmentation') } - const { volumeId: segmentationUID } = segmentationInfo - const activeSegmentationGlobalState = getSegmentation(segmentationUID) + const { volumeId: segmentationId } = segmentationInfo + const activeSegmentationGlobalState = getSegmentation(segmentationId) if (activeSegmentationGlobalState?.activeSegmentIndex !== segmentIndex) { activeSegmentationGlobalState.activeSegmentIndex = segmentIndex - triggerSegmentationGlobalStateModified(segmentationUID) + triggerSegmentationGlobalStateModified(segmentationId) } } /** - * Set the active segment index for a segmentation UID. It fires a global state + * Set the active segment index for a segmentation Id. It fires a global state * modified event. * * @triggers SEGMENTATION_GLOBAL_STATE_MODIFIED - * @param segmentationUID - The UID of the segmentation that the segment belongs to. + * @param segmentationId - The id of the segmentation that the segment belongs to. * @param segmentIndex - The index of the segment to be activated. */ function setActiveSegmentIndexForSegmentation( - segmentationUID: string, + segmentationId: string, segmentIndex: number ): void { - const activeSegmentationGlobalState = getSegmentation(segmentationUID) + const activeSegmentationGlobalState = getSegmentation(segmentationId) if (activeSegmentationGlobalState?.activeSegmentIndex !== segmentIndex) { activeSegmentationGlobalState.activeSegmentIndex = segmentIndex - triggerSegmentationGlobalStateModified(segmentationUID) + triggerSegmentationGlobalStateModified(segmentationId) } } /** * Get the active segment index for a segmentation in the global state - * @param segmentationUID - The UID of the segmentation to get the active segment index from. + * @param segmentationId - The id of the segmentation to get the active segment index from. * @returns The active segment index for the given segmentation. */ function getActiveSegmentIndexForSegmentation( - segmentationUID: string + segmentationId: string ): number | undefined { - const activeSegmentationGlobalState = getSegmentation(segmentationUID) + const activeSegmentationGlobalState = getSegmentation(segmentationId) if (activeSegmentationGlobalState) { return activeSegmentationGlobalState.activeSegmentIndex diff --git a/packages/tools/src/stateManagement/segmentation/segmentLocking.ts b/packages/tools/src/stateManagement/segmentation/segmentLocking.ts index fc2082eea..f4730a51f 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentLocking.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentLocking.ts @@ -11,7 +11,7 @@ import { triggerSegmentationGlobalStateModified } from './triggerSegmentationEve * @param segmentIndex - The index of the segment * @returns A boolean value indicating whether the segment is locked or not for modification */ -// Todo: should this be based on a segmentationUID instead of a toolGroupId? +// Todo: should this be based on a segmentationId instead of a toolGroupId? function getSegmentIndexLocked( toolGroupId: string, segmentIndex: number @@ -22,8 +22,8 @@ function getSegmentIndexLocked( throw new Error('element does not contain an active segmentation') } - const { volumeId: segmentationUID } = activeSegmentationInfo - const segmentationGlobalState = getSegmentation(segmentationUID) + const { volumeId: segmentationId } = activeSegmentationInfo + const segmentationGlobalState = getSegmentation(segmentationId) const lockedSegments = segmentationGlobalState.segmentsLocked @@ -41,7 +41,7 @@ function getSegmentIndexLocked( * @param segmentIndex - the index of the segment to lock/unlock * @param locked - boolean */ -// Todo: shouldn't this be a based on a segmentationUID instead of a toolGroupId? +// Todo: shouldn't this be a based on a segmentationId instead of a toolGroupId? function setSegmentIndexLocked( toolGroupId: string, segmentIndex: number, @@ -53,9 +53,9 @@ function setSegmentIndexLocked( throw new Error('element does not contain an active segmentation') } - const { volumeId: segmentationUID } = activeSegmentationInfo + const { volumeId: segmentationId } = activeSegmentationInfo - const segmentationGlobalState = getSegmentation(segmentationUID) + const segmentationGlobalState = getSegmentation(segmentationId) const { segmentsLocked } = segmentationGlobalState @@ -65,24 +65,24 @@ function setSegmentIndexLocked( segmentsLocked.delete(segmentIndex) } - triggerSegmentationGlobalStateModified(segmentationUID) + triggerSegmentationGlobalStateModified(segmentationId) } /** * Get the locked status for a segment index in a segmentation - * @param segmentationUID - The UID of the segmentation that the segment + * @param segmentationId - The id of the segmentation that the segment * belongs to. * @param segmentIndex - The index of the segment * @returns A boolean value indicating whether the segment is locked or not. */ function getSegmentIndexLockedForSegmentation( - segmentationUID: string, + segmentationId: string, segmentIndex: number ): boolean { - const globalState = getSegmentation(segmentationUID) + const globalState = getSegmentation(segmentationId) if (!globalState) { - throw new Error(`No segmentation state found for ${segmentationUID}`) + throw new Error(`No segmentation state found for ${segmentationId}`) } const { segmentsLocked } = globalState @@ -91,19 +91,19 @@ function getSegmentIndexLockedForSegmentation( /** * Set the locked status of a segment index in a segmentation - * @param segmentationUID - The UID of the segmentation whose segment + * @param segmentationId - The id of the segmentation whose segment * index is being modified. * @param segmentIndex - The index of the segment to lock/unlock. */ function setSegmentIndexLockedForSegmentation( - segmentationUID: string, + segmentationId: string, segmentIndex: number, locked = true ): void { - const segmentationGlobalState = getSegmentation(segmentationUID) + const segmentationGlobalState = getSegmentation(segmentationId) if (!segmentationGlobalState) { - throw new Error(`No segmentation state found for ${segmentationUID}`) + throw new Error(`No segmentation state found for ${segmentationId}`) } const { segmentsLocked } = segmentationGlobalState @@ -114,22 +114,22 @@ function setSegmentIndexLockedForSegmentation( segmentsLocked.delete(segmentIndex) } - triggerSegmentationGlobalStateModified(segmentationUID) + triggerSegmentationGlobalStateModified(segmentationId) } /** * Get the locked segments for a segmentation - * @param segmentationUID - The UID of the segmentation to get locked + * @param segmentationId - The id of the segmentation to get locked * segments for. * @returns An array of locked segment indices. */ function getSegmentsLockedForSegmentation( - segmentationUID: string + segmentationId: string ): number[] | [] { - const globalState = getSegmentation(segmentationUID) + const globalState = getSegmentation(segmentationId) if (!globalState) { - throw new Error(`No segmentation state found for ${segmentationUID}`) + throw new Error(`No segmentation state found for ${segmentationId}`) } const { segmentsLocked } = globalState diff --git a/packages/tools/src/stateManagement/segmentation/segmentationColor.ts b/packages/tools/src/stateManagement/segmentation/segmentationColor.ts index 2d2aa05d9..781d13bea 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationColor.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationColor.ts @@ -33,7 +33,7 @@ function addColorLUT(colorLUT: ColorLUT, colorLUTIndex: number): void { * display the color of their annotation. * * @param toolGroupId - The Id of the tool group that owns the segmentation data. - * @param segmentationDataUID - The UID of the segmentation data + * @param segmentationDataUID - The id of the segmentation data * @param segmentIndex - The index of the segment in the segmentation * @returns A color. */ diff --git a/packages/tools/src/stateManagement/segmentation/segmentationState.ts b/packages/tools/src/stateManagement/segmentation/segmentationState.ts index 072153b9a..d129d183a 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationState.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationState.ts @@ -14,6 +14,7 @@ import { isValidRepresentationConfig, } from '../../utilities/segmentation' import { deepMerge } from '../../utilities' +import normalizeSegmentationInput from './helpers/normalizeSegmentationInput' /** * It returns the defaultSegmentationStateManager. @@ -43,9 +44,10 @@ function addSegmentation( suppressEvents?: boolean ): void { const segmentationStateManager = getDefaultSegmentationStateManager() - segmentationStateManager.addSegmentation(segmentationInput) + const segmentation = normalizeSegmentationInput(segmentationInput) + segmentationStateManager.addSegmentation(segmentation) if (!suppressEvents) { - triggerSegmentationGlobalStateModified(segmentationInput.segmentationId) + triggerSegmentationGlobalStateModified(segmentation.segmentationId) } } @@ -104,7 +106,7 @@ function getSegmentationState( * data objects and returns the first one that matches the UID. * @param toolGroupId - The Id of the tool group that the segmentation * data belongs to. - * @param segmentationDataUID - The UID of the segmentation data to + * @param segmentationDataUID - The id of the segmentation data to * retrieve. * @returns Segmentation Data object. */ @@ -127,7 +129,7 @@ function getSegmentationDataByUID( * * @param toolGroupId - The Id of the tool group that the segmentation * data belongs to. - * @param segmentationDataUID - The UID of the segmentation data to + * @param segmentationDataUID - The id of the segmentation data to * remove. */ function removeSegmentationData( @@ -254,14 +256,14 @@ function getSegmentationConfig(toolGroupId: string): SegmentationConfig { ***************************/ /** - * Get the tool group IDs that have a segmentation with the given UID - * @param segmentationUID - The UID of the segmentation to get the tool + * Get the tool group IDs that have a segmentation with the given Id + * @param segmentationId - The id of the segmentation to get the tool * groups for. * @returns An array of tool group IDs. */ -function getToolGroupsWithSegmentation(segmentationUID: string): string[] { +function getToolGroupsWithSegmentation(segmentationId: string): string[] { const segmentationStateManager = getDefaultSegmentationStateManager() - return segmentationStateManager.getToolGroupsWithSegmentation(segmentationUID) + return segmentationStateManager.getToolGroupsWithSegmentation(segmentationId) } /** @@ -302,7 +304,7 @@ function addColorLUT(colorLut: ColorLUT, index: number): void { * @triggers SEGMENTATION_STATE_MODIFIED * * @param toolGroupId - The Id of the tool group that owns the segmentation data. - * @param segmentationDataUID - The UID of the segmentation data to set as active. + * @param segmentationDataUID - The id of the segmentation data to set as active. * @param suppressEvents - If true, the segmentation state will be updated, but no events will be triggered. */ function setActiveSegmentationData( diff --git a/packages/tools/src/stateManagement/segmentation/segmentationVisibility.ts b/packages/tools/src/stateManagement/segmentation/segmentationVisibility.ts index 8f1eb301e..7fe2fbf5a 100644 --- a/packages/tools/src/stateManagement/segmentation/segmentationVisibility.ts +++ b/packages/tools/src/stateManagement/segmentation/segmentationVisibility.ts @@ -8,7 +8,7 @@ import { ToolGroupSpecificSegmentationData } from '../../types/SegmentationState * * @triggers SEGMENTATION_STATE_MODIFIED * @param toolGroupId - The Id of the tool group that contains the segmentation. - * @param segmentationDataUID - The UID of the segmentation data to modify its visibility. + * @param segmentationDataUID - The id of the segmentation data to modify its visibility. * @param visibility - boolean */ function setSegmentationVisibility( @@ -37,7 +37,7 @@ function setSegmentationVisibility( * * @param toolGroupId - The Id of the tool group that the segmentation * data belongs to. - * @param segmentationDataUID - The UID of the segmentation data to get + * @param segmentationDataUID - The id of the segmentation data to get * @returns A boolean value that indicates whether the segmentation data is visible or * not on the toolGroup */ diff --git a/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts b/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts index 7c1c97de6..b9d39f6c9 100644 --- a/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts +++ b/packages/tools/src/stateManagement/segmentation/triggerSegmentationEvents.ts @@ -33,14 +33,12 @@ function triggerSegmentationStateModified(toolGroupId: string): void { * * @param segmentationId - The id of the segmentation that has been updated */ -function triggerSegmentationGlobalStateModified( - segmentationUID?: string -): void { +function triggerSegmentationGlobalStateModified(segmentationId?: string): void { let toolGroupIds, segmentationUIDs - if (segmentationUID) { - toolGroupIds = getToolGroupsWithSegmentation(segmentationUID) - segmentationUIDs = [segmentationUID] + if (segmentationId) { + toolGroupIds = getToolGroupsWithSegmentation(segmentationId) + segmentationUIDs = [segmentationId] } else { // get all toolGroups toolGroupIds = getToolGroups() @@ -49,11 +47,11 @@ function triggerSegmentationGlobalStateModified( ) } - // 1. Trigger an event notifying all listeners about the segmentationUID + // 1. Trigger an event notifying all listeners about the segmentationId // that has been updated. - segmentationUIDs.forEach((segmentationUID) => { + segmentationUIDs.forEach((segmentationId) => { const eventDetail: SegmentationGlobalStateModifiedEventDetail = { - segmentationUID, + segmentationId, } triggerEvent( eventTarget, @@ -62,7 +60,7 @@ function triggerSegmentationGlobalStateModified( ) }) - // 2. Notify all viewports that render the segmentationUID in order to update the + // 2. Notify all viewports that render the segmentationId in order to update the // rendering based on the new global state. toolGroupIds.forEach((toolGroupId) => { triggerSegmentationStateModified(toolGroupId) @@ -72,7 +70,7 @@ function triggerSegmentationGlobalStateModified( /** * Trigger an event that a segmentation data has been modified * @param toolGroupId - The Id of the tool group that triggered the event. - * @param segmentationDataUID - The UID of the segmentation data that was modified. + * @param segmentationDataUID - The id of the segmentation data that was modified. */ function triggerSegmentationDataModified( toolGroupId: string, diff --git a/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts b/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts index 2c350e4d8..d4aa2643b 100644 --- a/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts +++ b/packages/tools/src/tools/displayTools/Labelmap/LabelmapDisplay.ts @@ -127,10 +127,10 @@ function removeSegmentationData( } /** - * It takes the enabled element, the segmentation UID, and the configuration, and + * It takes the enabled element, the segmentation Id, and the configuration, and * it sets the segmentation for the enabled element as a labelmap * @param enabledElement - The cornerstone enabled element - * @param segmentationUID - The UID of the segmentation to be rendered. + * @param segmentationId - The id of the segmentation to be rendered. * @param configuration - The configuration object for the labelmap. */ function render( diff --git a/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts b/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts index 16ff7b382..440334043 100644 --- a/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts +++ b/packages/tools/src/tools/displayTools/SegmentationDisplayTool.ts @@ -40,7 +40,7 @@ import { deepMerge } from '../../utilities' * * addSegmentationsForToolGroup('toolGroupId', [ * { - * volumeId: segmentationUID, + * volumeId: segmentationId, * }, * ]) * diff --git a/packages/tools/src/tools/segmentation/RectangleRoiThresholdTool.ts b/packages/tools/src/tools/segmentation/RectangleRoiThresholdTool.ts index ff6bb6d88..b5dd7ba02 100644 --- a/packages/tools/src/tools/segmentation/RectangleRoiThresholdTool.ts +++ b/packages/tools/src/tools/segmentation/RectangleRoiThresholdTool.ts @@ -44,7 +44,7 @@ export interface RectangleRoiThresholdAnnotation extends Annotation { points: Types.Point3[] activeHandleIndex: number | null } - // segmentationUID: string + // segmentationId: string } } @@ -152,7 +152,7 @@ export default class RectangleRoiThresholdTool extends RectangleRoiTool { ], activeHandleIndex: null, }, - segmentationUID: null, + segmentationId: null, }, } diff --git a/packages/tools/src/types/EventTypes.ts b/packages/tools/src/types/EventTypes.ts index 75de33a36..77384759c 100644 --- a/packages/tools/src/types/EventTypes.ts +++ b/packages/tools/src/types/EventTypes.ts @@ -126,7 +126,7 @@ type SegmentationStateModifiedEventDetail = { */ type SegmentationGlobalStateModifiedEventDetail = { /** unique id of segmentation (not segmentationData), for volumes (labelMaps) it is volumeId */ - segmentationUID: string + segmentationId: string } /** diff --git a/packages/tools/test/segmentationRectangleScissor_test.js b/packages/tools/test/segmentationRectangleScissor_test.js index f6ac0b9f1..633127665 100644 --- a/packages/tools/test/segmentationRectangleScissor_test.js +++ b/packages/tools/test/segmentationRectangleScissor_test.js @@ -128,8 +128,8 @@ describe('Segmentation Tools --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -151,9 +151,9 @@ describe('Segmentation Tools --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) @@ -258,8 +258,8 @@ describe('Segmentation Tools --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -276,9 +276,9 @@ describe('Segmentation Tools --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) @@ -425,8 +425,8 @@ describe('Segmentation Tools --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -445,9 +445,9 @@ describe('Segmentation Tools --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) diff --git a/packages/tools/test/segmentationSegmentIndexController_test.js b/packages/tools/test/segmentationSegmentIndexController_test.js index ed1b2ee29..462e7e104 100644 --- a/packages/tools/test/segmentationSegmentIndexController_test.js +++ b/packages/tools/test/segmentationSegmentIndexController_test.js @@ -211,8 +211,8 @@ describe('Segmentation Index Controller --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -229,9 +229,9 @@ describe('Segmentation Index Controller --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) @@ -357,8 +357,8 @@ describe('Segmentation Index Controller --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -375,9 +375,9 @@ describe('Segmentation Index Controller --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) @@ -531,8 +531,8 @@ describe('Segmentation Index Controller --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -549,9 +549,9 @@ describe('Segmentation Index Controller --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) diff --git a/packages/tools/test/segmentationSphereScissor_test.js b/packages/tools/test/segmentationSphereScissor_test.js index 6b77f7532..b7e4f85cb 100644 --- a/packages/tools/test/segmentationSphereScissor_test.js +++ b/packages/tools/test/segmentationSphereScissor_test.js @@ -264,8 +264,8 @@ describe('Segmentation Tools --', () => { eventTarget.addEventListener( Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, (evt) => { - const { segmentationUID } = evt.detail - expect(segmentationUID.includes(volumeId)).toBe(true) + const { segmentationId } = evt.detail + expect(segmentationId.includes(volumeId)).toBe(true) } ) @@ -286,9 +286,9 @@ describe('Segmentation Tools --', () => { segmentation .createNewSegmentationForToolGroup(this.segToolGroup.id) - .then((segmentationUID) => { + .then((segmentationId) => { addSegmentationsForToolGroup(this.segToolGroup.id, [ - { volumeId: segmentationUID }, + { volumeId: segmentationId }, ]) }) }) diff --git a/packages/tools/test/segmentationState_test.js b/packages/tools/test/segmentationState_test.js index 19d96df25..fa83461ba 100644 --- a/packages/tools/test/segmentationState_test.js +++ b/packages/tools/test/segmentationState_test.js @@ -117,7 +117,7 @@ describe('Segmentation State -- ', () => { (evt) => { const globalState = segmentation.state.getSegmentation(segVolumeId) - expect(evt.detail.segmentationUID.includes(segVolumeId)).toBe(true) + expect(evt.detail.segmentationId.includes(segVolumeId)).toBe(true) expect(globalState).toBeDefined() From 5b11cc1aeee0f18d3d2c83829ec0d3793b264846 Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 25 Mar 2022 11:54:34 -0400 Subject: [PATCH 06/20] add segmentation to state completed --- common/reviews/api/tools.api.md | 32 ++-- .../demo/src/ExampleSegmentationRender.tsx | 165 ++++++++++------- packages/demo/src/ExampleVTKMPR.tsx | 10 ++ packages/tools/src/enums/Events.ts | 20 +-- packages/tools/src/init.ts | 6 +- .../segmentation/SegmentationStateManager.ts | 152 ++++++++-------- .../src/stateManagement/segmentation/index.ts | 2 + .../segmentation/segmentIndex.ts | 10 +- .../segmentation/segmentLocking.ts | 6 +- .../segmentation/segmentationColor.ts | 4 +- .../segmentation/segmentationConfig.ts | 12 +- .../segmentation/segmentationState.ts | 168 ++++++++++++------ .../segmentation/segmentationVisibility.ts | 8 +- .../segmentation/triggerSegmentationEvents.ts | 45 ++--- .../displayTools/SegmentationDisplayTool.ts | 59 +++--- packages/tools/src/types/EventTypes.ts | 18 +- .../tools/src/types/SegmentationStateTypes.ts | 8 +- packages/tools/src/types/index.ts | 4 +- .../test/segmentationRectangleScissor_test.js | 33 ++-- .../tools/test/segmentationRender_test.js | 2 +- ...segmentationSegmentIndexController_test.js | 33 ++-- .../test/segmentationSphereScissor_test.js | 11 +- packages/tools/test/segmentationState_test.js | 56 +++--- 23 files changed, 483 insertions(+), 381 deletions(-) diff --git a/common/reviews/api/tools.api.md b/common/reviews/api/tools.api.md index 9066c1c6f..0574a1207 100644 --- a/common/reviews/api/tools.api.md +++ b/common/reviews/api/tools.api.md @@ -28,10 +28,10 @@ type ActorEntry = { function addAnnotation(element: HTMLElement, annotation: Annotation): void; // @public (undocumented) -function addColorLUT(colorLut: ColorLUT, index: number): void; +function addColorLUT(colorLut: ColorLut, index: number): void; // @public (undocumented) -function addColorLUT_2(colorLUT: ColorLUT, colorLUTIndex: number): void; +function addColorLUT_2(colorLUT: ColorLut, colorLUTIndex: number): void; // @public (undocumented) function addGlobalSegmentationData(segmentationData: GlobalSegmentationData, suppressEvents?: boolean): void; @@ -354,7 +354,7 @@ function clip(a: any, b: any, box: any, da?: any, db?: any): 0 | 1; type Color = [number, number, number, number]; // @public (undocumented) -type ColorLUT = Array; +type ColorLut = Array; declare namespace config { export { @@ -1035,13 +1035,13 @@ declare namespace EventTypes_2 { AnnotationLockChangeEventDetail, AnnotationLockChangeEventType, SegmentationDataModifiedEventType, - SegmentationStateModifiedEventDetail, + SegmentationRepresentationModifiedEventDetail, SegmentationStateModifiedEventType, SegmentationDataModifiedEventDetail, SegmentationRenderedEventType, SegmentationRenderedEventDetail, - SegmentationGlobalStateModifiedEventType, - SegmentationGlobalStateModifiedEventDetail, + SegmentationModifiedEventType, + SegmentationModifiedEventDetail, KeyDownEventDetail, KeyDownEventType, KeyUpEventDetail, @@ -1156,7 +1156,7 @@ function getCanvasEllipseCorners(ellipseCanvasPoints: canvasCoordinates): Array< function getColorForSegmentIndex(toolGroupId: string, segmentationDataUID: string, segmentIndex: number): Color; // @public (undocumented) -function getColorLut(index: number): ColorLUT | undefined; +function getColorLut(index: number): ColorLut | undefined; // @public (undocumented) function getDefaultAnnotationManager(): FrameOfReferenceSpecificAnnotationManager; @@ -2645,12 +2645,12 @@ export class SegmentationDisplayTool extends BaseTool { } // @public (undocumented) -type SegmentationGlobalStateModifiedEventDetail = { +type SegmentationModifiedEventDetail = { segmentationId: string; }; // @public (undocumented) -type SegmentationGlobalStateModifiedEventType = Types_2.CustomEventType; +type SegmentationModifiedEventType = Types_2.CustomEventType; // @public (undocumented) type SegmentationRenderedEventDetail = { @@ -2665,12 +2665,12 @@ type SegmentationRenderedEventType = Types_2.CustomEventType; +type SegmentationStateModifiedEventType = Types_2.CustomEventType; declare namespace segmentationVisibility { export { @@ -3082,17 +3082,17 @@ function triggerSegmentationDataModified(toolGroupId: string, segmentationDataUI declare namespace triggerSegmentationEvents { export { - triggerSegmentationStateModified, + triggerSegmentationRepresentationModified, triggerSegmentationDataModified, - triggerSegmentationGlobalStateModified + triggerSegmentationModified } } // @public (undocumented) -function triggerSegmentationGlobalStateModified(segmentationId?: string): void; +function triggerSegmentationModified(segmentationId?: string): void; // @public (undocumented) -function triggerSegmentationStateModified(toolGroupId: string): void; +function triggerSegmentationRepresentationModified(toolGroupId: string): void; declare namespace Types { export { @@ -3116,7 +3116,7 @@ declare namespace Types { SegmentationRepresentation, LabelmapRepresentation, Color, - ColorLUT, + ColorLut, RepresentationConfig, SegmentationConfig, GlobalSegmentationData, diff --git a/packages/demo/src/ExampleSegmentationRender.tsx b/packages/demo/src/ExampleSegmentationRender.tsx index 9422ee922..a021babc9 100644 --- a/packages/demo/src/ExampleSegmentationRender.tsx +++ b/packages/demo/src/ExampleSegmentationRender.tsx @@ -6,6 +6,7 @@ import { cache, RenderingEngine, volumeLoader, + imageLoader, init as cs3dInit, eventTarget, } from '@cornerstonejs/core' @@ -39,7 +40,9 @@ import { } from './constants' import LAYOUTS, { ptCtFusion } from './layouts' import config from './config/default' +import { sharedArrayBufferImageLoader } from '@cornerstonejs/streaming-image-volume-loader' +import { cornerstoneStreamingImageVolumeLoader } from '@cornerstonejs/streaming-image-volume-loader' import sortImageIdsByIPP from './helpers/sortImageIdsByIPP' import limitImageIds from './helpers/limitImageIds' @@ -57,6 +60,13 @@ let ctSceneToolGroup, ptCoronalSegmentationToolGroup, axialPTCTSegmentationToolGroup +volumeLoader.registerUnknownVolumeLoader(cornerstoneStreamingImageVolumeLoader) +volumeLoader.registerVolumeLoader( + 'cornerstoneStreamingImageVolume', + cornerstoneStreamingImageVolumeLoader +) +imageLoader.registerImageLoader('csiv', sharedArrayBufferImageLoader) + const { createCameraPositionSynchronizer, createVOISynchronizer } = synchronizers @@ -129,7 +139,7 @@ class SegmentationExample extends Component { // Segmentation segmentationStatus: '', segmentationToolActive: false, - selectedsegmentationUID: '', + selectedSegmentationUID: '', availableSegmentations: [], fillAlphaGlobal: 0.9, fillAlphaToolGroup: 0.9, @@ -302,13 +312,13 @@ class SegmentationExample extends Component { _removeEventListeners() { eventTarget.removeEventListener( - csToolsEnums.Events.SEGMENTATION_STATE_MODIFIED, - this.onSegmentationStateModified + csToolsEnums.Events.SEGMENTATION_REPRESENTATION_MODIFIED, + this.onSegmentationRepresentationModified ) eventTarget.removeEventListener( - csToolsEnums.Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, - this.onGlobalSegmentationStateUpdated + csToolsEnums.Events.SEGMENTATION_MODIFIED, + this.onGlobalSegmentationModified ) eventTarget.removeEventListener( @@ -319,13 +329,13 @@ class SegmentationExample extends Component { _addEventListeners() { eventTarget.addEventListener( - csToolsEnums.Events.SEGMENTATION_STATE_MODIFIED, - this.onSegmentationStateModified + csToolsEnums.Events.SEGMENTATION_REPRESENTATION_MODIFIED, + this.onSegmentationRepresentationModified ) eventTarget.addEventListener( - csToolsEnums.Events.SEGMENTATION_GLOBAL_STATE_MODIFIED, - this.onGlobalSegmentationStateUpdated + csToolsEnums.Events.SEGMENTATION_MODIFIED, + this.onGlobalSegmentationModified ) eventTarget.addEventListener( @@ -345,24 +355,24 @@ class SegmentationExample extends Component { this.renderingEngine.destroy() } - onGlobalSegmentationStateUpdated = (evt) => { + onGlobalSegmentationModified = (evt) => { const { segmentationId } = evt.detail - const allSegmentationUIDs = segmentation.state - .getGlobalSegmentationState() - .map(({ volumeId }) => volumeId) + const allSegmentationIds = segmentation.state + .getSegmentations() + .map(({ segmentationId }) => segmentationId) let newSelectedSegmentationUID = this.state.selectedSegmentationUIDFromAll if (newSelectedSegmentationUID === '') { - newSelectedSegmentationUID = allSegmentationUIDs[0] + newSelectedSegmentationUID = allSegmentationIds[0] } this.setState({ - allSegmentationUIDs: allSegmentationUIDs, + allSegmentationUIDs: allSegmentationIds, selectedSegmentationUIDFromAll: newSelectedSegmentationUID, }) } - onSegmentationStateModified = (evt) => { + onSegmentationRepresentationModified = (evt) => { const { toolGroupId } = evt.detail if (toolGroupId !== this.state.selectedToolGroupName) { @@ -372,11 +382,11 @@ class SegmentationExample extends Component { const activeSegmentationInfo = segmentation.activeSegmentation.getActiveSegmentationInfo(toolGroupId) - let selectedsegmentationUID, segmentLocked, activeSegmentIndex + let selectedSegmentationUID, segmentLocked, activeSegmentIndex if (activeSegmentationInfo) { activeSegmentIndex = activeSegmentationInfo.activeSegmentIndex - selectedsegmentationUID = activeSegmentationInfo.segmentationDataUID + selectedSegmentationUID = activeSegmentationInfo.segmentationDataUID segmentLocked = segmentation.segmentLocking.getSegmentIndexLockedForSegmentation( @@ -398,7 +408,7 @@ class SegmentationExample extends Component { this.setState({ selectedToolGroupSegmentationDataUIDs: segmentationDataUIDs, - selectedsegmentationUID: selectedsegmentationUID, + selectedSegmentationUID: selectedSegmentationUID, selectedViewportActiveSegmentIndex: activeSegmentIndex ?? 1, segmentLocked: segmentLocked ?? false, }) @@ -408,12 +418,12 @@ class SegmentationExample extends Component { const { element } = evt.detail const segmentationUIDs = - segmentation.state.getsegmentationUIDsForElement(element) - const activesegmentationUID = - segmentation.activeSegmentation.getActivesegmentationUID(element) + segmentation.state.getSegmentationUIDsForElement(element) + const activeSegmentationUID = + segmentation.activeSegmentation.getActiveSegmentationUID(element) this.setState({ availableSegmentations: segmentationUIDs, - selectedsegmentationUID: activesegmentationUID, + selectedSegmentationUID: activeSegmentationUID, }) } @@ -543,41 +553,62 @@ class SegmentationExample extends Component { 'fatTissue', ]) + segmentation.addSegmentations([ + { + segmentationId: labelmap1UID, + representation: { + type: csToolsEnums.SegmentationRepresentations.Labelmap, + data: { + volumeId: labelmap1UID, + }, + }, + }, + { + segmentationId: labelmap2UID, + representation: { + type: csToolsEnums.SegmentationRepresentations.Labelmap, + data: { + volumeId: labelmap2UID, + }, + }, + }, + ]) + this.setState({ segmentationStatus: 'done' }) } loadSegmentation = async (segmentationId, initialConfig) => { const toolGroupId = this.state.selectedToolGroupName - if (!initialConfig) { - await segmentation.addSegmentationsForToolGroup(toolGroupId, [ - { - volumeId: segmentationId, - active: true, - representation: { - type: csToolsEnums.SegmentationRepresentations.Labelmap, - }, - }, - ]) - } else { - await segmentation.addSegmentationsForToolGroup( - toolGroupId, - [ - { - type: csToolsEnums.SegmentationRepresentations.Labelmap, - representation: {}, - active: true, - }, - ], - { - representations: { - [csToolsEnums.SegmentationRepresentations.Labelmap]: { - renderOutline: false, - }, - }, - } - ) - } + // if (!initialConfig) { + // await segmentation.addSegmentationsForToolGroup(toolGroupId, [ + // { + // volumeId: segmentationId, + // active: true, + // representation: { + // type: csToolsEnums.SegmentationRepresentations.Labelmap, + // }, + // }, + // ]) + // } else { + // await segmentation.addSegmentationsForToolGroup( + // toolGroupId, + // [ + // { + // type: csToolsEnums.SegmentationRepresentations.Labelmap, + // representation: {}, + // active: true, + // }, + // ], + // { + // representations: { + // [csToolsEnums.SegmentationRepresentations.Labelmap]: { + // renderOutline: false, + // }, + // }, + // } + // ) + // } this.setState({ segmentationToolActive: true, @@ -587,12 +618,12 @@ class SegmentationExample extends Component { toggleLockedSegmentIndex = (evt) => { const checked = evt.target.checked - const activesegmentationInfo = + const activeSegmentationInfo = segmentation.activeSegmentation.getActiveSegmentationInfo( this.state.selectedToolGroupName ) - const { volumeId, activeSegmentIndex } = activesegmentationInfo + const { volumeId, activeSegmentIndex } = activeSegmentationInfo const activeSegmentLockedStatus = segmentation.segmentLocking.getSegmentIndexLockedForSegmentation( @@ -637,7 +668,7 @@ class SegmentationExample extends Component { calculateTMTV = () => { const viewportId = this.state.selectedToolGroupName const { element } = this.renderingEngine.getViewport(viewportId) - const segmentationUIDs = segmentation.getsegmentationUIDsForElement(element) + const segmentationUIDs = segmentation.getSegmentationUIDsForElement(element) const labelmaps = segmentationUIDs.map((uid) => cache.getVolume(uid)) const segmentationIndex = 1 @@ -658,7 +689,7 @@ class SegmentationExample extends Component { const { uid } = viewport.getDefaultActor() const referenceVolume = cache.getVolume(uid) - const segmentationUIDs = segmentation.getsegmentationUIDsForElement( + const segmentationUIDs = segmentation.getSegmentationUIDsForElement( viewport.element ) @@ -698,9 +729,9 @@ class SegmentationExample extends Component { // Todo: this only works for volumeViewport const { uid } = volumeActorInfo - const segmentationData = SegmentatoinState.getSegmentationDataByUID( + const segmentationData = SegmentationState.getSegmentationDataByUID( this.state.selectedToolGroupName, - this.state.selectedsegmentationUID + this.state.selectedSegmentationUID ) const globalState = segmentation.state.getSegmentation( segmentationData.volumeId @@ -794,9 +825,9 @@ class SegmentationExample extends Component { const { uid } = volumeActorInfo const referenceVolume = cache.getVolume(uid) - const segmentationData = SegmentatoinState.getSegmentationDataByUID( + const segmentationData = SegmentationState.getSegmentationDataByUID( this.state.selectedToolGroupName, - this.state.selectedsegmentationUID + this.state.selectedSegmentationUID ) const numSlices = this.state.numSlicesForThreshold @@ -951,7 +982,7 @@ class SegmentationExample extends Component { } deleteSegmentation = () => { - const segmentationDataUID = this.state.selectedsegmentationUID + const segmentationDataUID = this.state.selectedSegmentationUID segmentation.removeSegmentationsFromToolGroup( this.state.selectedToolGroupName, [segmentationDataUID] @@ -1072,7 +1103,7 @@ class SegmentationExample extends Component { selectedToolGroupSegmentationDataUIDs: toolGroupSegmentations.map( (segData) => segData.segmentationDataUID ), - selectedsegmentationUID: + selectedSegmentationUID: activeSegmentationData?.segmentationDataUID, renderOutlineToolGroup: toolGroupSegmentationConfig?.renderOutline || true, @@ -1207,18 +1238,18 @@ class SegmentationExample extends Component { ToolGroup Segmentations (selected is active Segmentation){' '} { this.setState({ - selectedSegmentationUIDFromAll: evt.target.value, + selectedSegmentationIdFromAll: evt.target.value, }) }} size={3} > - {this.state.allSegmentationUIDs.map((segmentationId) => ( + {this.state.allSegmentationIds.map((segmentationId) => ( @@ -1195,14 +1194,16 @@ class SegmentationExample extends Component {
- - {' '} - ToolGroup Segmentations (selected is active Segmentation){' '} - + ToolGroup Segmentation Representations { - const selectedSegmentationUID = evt.target.value + const selectedRepresentationUID = evt.target.value segmentation.activeSegmentation.setActiveSegmentation( this.state.selectedToolGroupName, - selectedSegmentationUID + selectedRepresentationUID ) this.setState({ - selectedSegmentationUID, + selectedRepresentationUID, }) }} size={3} > - {this.state.selectedToolGroupSegmentationDataUIDs.map( + {this.state.selectedToolGroupSegRepresentationsUIDs.map( (segmentationId) => (
-