@cornerstonejs/tools 4.22.13 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/config.d.ts +4 -0
- package/dist/esm/drawingSvg/drawPath.d.ts +3 -0
- package/dist/esm/drawingSvg/drawPath.js +4 -1
- package/dist/esm/eventListeners/keyboard/keyDownListener.js +2 -2
- package/dist/esm/eventListeners/mouse/getMouseEventPoints.d.ts +1 -1
- package/dist/esm/eventListeners/mouse/getMouseEventPoints.js +19 -1
- package/dist/esm/eventListeners/mouse/mouseDoubleClickListener.js +8 -1
- package/dist/esm/eventListeners/mouse/mouseDownListener.js +37 -5
- package/dist/esm/eventListeners/mouse/mouseMoveListener.js +3 -0
- package/dist/esm/eventListeners/segmentation/imageChangeEventListener.js +60 -92
- package/dist/esm/eventListeners/segmentation/labelmap/onLabelmapSegmentationDataModified.js +49 -21
- package/dist/esm/eventListeners/segmentation/labelmap/performStackLabelmapUpdate.js +7 -13
- package/dist/esm/eventListeners/segmentation/labelmap/performVolumeLabelmapUpdate.js +44 -18
- package/dist/esm/eventListeners/touch/getTouchEventPoints.js +27 -4
- package/dist/esm/eventListeners/touch/touchStartListener.js +27 -9
- package/dist/esm/eventListeners/wheel/wheelListener.js +5 -1
- package/dist/esm/init.js +2 -0
- package/dist/esm/stateManagement/annotation/FrameOfReferenceSpecificAnnotationManager.js +10 -4
- package/dist/esm/stateManagement/segmentation/SegmentationRenderingEngine.js +23 -20
- package/dist/esm/stateManagement/segmentation/SegmentationRepresentationDisplayRegistry.d.ts +12 -0
- package/dist/esm/stateManagement/segmentation/SegmentationRepresentationDisplayRegistry.js +7 -0
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +1 -11
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +28 -166
- package/dist/esm/stateManagement/segmentation/addColorLUT.js +7 -1
- package/dist/esm/stateManagement/segmentation/getCurrentLabelmapImageIdForViewport.js +16 -1
- package/dist/esm/stateManagement/segmentation/helpers/clearSegmentValue.js +9 -7
- package/dist/esm/stateManagement/segmentation/helpers/getSegmentationActor.d.ts +1 -1
- package/dist/esm/stateManagement/segmentation/helpers/getSegmentationActor.js +3 -2
- package/dist/esm/stateManagement/segmentation/helpers/getViewportLabelmapRenderMode.d.ts +5 -0
- package/dist/esm/stateManagement/segmentation/helpers/getViewportLabelmapRenderMode.js +58 -0
- package/dist/esm/stateManagement/segmentation/helpers/labelmapImageMapperSupport.d.ts +52 -0
- package/dist/esm/stateManagement/segmentation/helpers/labelmapImageMapperSupport.js +246 -0
- package/dist/esm/stateManagement/segmentation/helpers/labelmapSegmentationState.d.ts +1 -0
- package/dist/esm/stateManagement/segmentation/helpers/labelmapSegmentationState.js +1 -0
- package/dist/esm/stateManagement/segmentation/helpers/normalizeSegmentationInput.js +11 -1
- package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.js +3 -3
- package/dist/esm/stateManagement/segmentation/labelmapModel/index.d.ts +9 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/index.js +7 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapEditTransaction.d.ts +54 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapEditTransaction.js +224 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapImageIdMapping.d.ts +6 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapImageIdMapping.js +39 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapImageReferenceResolver.d.ts +23 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapImageReferenceResolver.js +269 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapLayerStore.d.ts +15 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapLayerStore.js +160 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapLegacyAdapter.d.ts +4 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapLegacyAdapter.js +42 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapSegmentBindings.d.ts +11 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/labelmapSegmentBindings.js +73 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/normalizeLabelmapSegmentationData.d.ts +17 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/normalizeLabelmapSegmentationData.js +75 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/privateLabelmap.d.ts +5 -0
- package/dist/esm/stateManagement/segmentation/labelmapModel/privateLabelmap.js +106 -0
- package/dist/esm/stateManagement/segmentation/models/SegmentModel.d.ts +11 -0
- package/dist/esm/stateManagement/segmentation/models/SegmentModel.js +19 -0
- package/dist/esm/stateManagement/segmentation/models/SegmentationModel.d.ts +12 -0
- package/dist/esm/stateManagement/segmentation/models/SegmentationModel.js +23 -0
- package/dist/esm/stateManagement/segmentation/removeSegmentationRepresentations.js +6 -10
- package/dist/esm/stateManagement/segmentation/segmentIndex.js +24 -0
- package/dist/esm/stateManagement/segmentation/segmentationEventManager.js +2 -9
- package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +2 -1
- package/dist/esm/stateManagement/segmentation/segmentationState.js +4 -1
- package/dist/esm/store/state.js +2 -1
- package/dist/esm/synchronizers/callbacks/imageSliceSyncCallback.js +12 -3
- package/dist/esm/synchronizers/callbacks/presentationViewSyncCallback.js +5 -2
- package/dist/esm/synchronizers/callbacks/zoomPanSyncCallback.js +51 -3
- package/dist/esm/tools/AdvancedMagnifyTool.js +1 -1
- package/dist/esm/tools/CrosshairsTool.js +5 -5
- package/dist/esm/tools/OrientationControllerTool.js +1 -1
- package/dist/esm/tools/OrientationMarkerTool.js +4 -4
- package/dist/esm/tools/PanTool.js +26 -3
- package/dist/esm/tools/PlanarRotateTool.js +19 -4
- package/dist/esm/tools/ReferenceCursors.js +7 -1
- package/dist/esm/tools/SculptorTool/CircleSculptCursor.js +1 -1
- package/dist/esm/tools/TrackballRotateTool.js +3 -2
- package/dist/esm/tools/VolumeCroppingTool.js +3 -2
- package/dist/esm/tools/WindowLevelTool.d.ts +2 -1
- package/dist/esm/tools/WindowLevelTool.js +48 -4
- package/dist/esm/tools/ZoomTool.d.ts +8 -0
- package/dist/esm/tools/ZoomTool.js +92 -11
- package/dist/esm/tools/annotation/AngleTool.js +33 -31
- package/dist/esm/tools/annotation/ArrowAnnotateTool.js +30 -28
- package/dist/esm/tools/annotation/BidirectionalTool.js +51 -49
- package/dist/esm/tools/annotation/CircleROITool.js +49 -44
- package/dist/esm/tools/annotation/CobbAngleTool.js +1 -1
- package/dist/esm/tools/annotation/DragProbeTool.js +1 -1
- package/dist/esm/tools/annotation/ETDRSGridTool.js +1 -1
- package/dist/esm/tools/annotation/EllipticalROITool.js +42 -37
- package/dist/esm/tools/annotation/HeightTool.js +1 -1
- package/dist/esm/tools/annotation/KeyImageTool.js +11 -11
- package/dist/esm/tools/annotation/LabelTool.js +37 -35
- package/dist/esm/tools/annotation/LengthTool.js +35 -33
- package/dist/esm/tools/annotation/LivewireContourSegmentationTool.js +6 -4
- package/dist/esm/tools/annotation/LivewireContourTool.js +1 -1
- package/dist/esm/tools/annotation/PlanarFreehandContourSegmentationTool.js +6 -4
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js +1 -1
- package/dist/esm/tools/annotation/ProbeTool.js +51 -46
- package/dist/esm/tools/annotation/RectangleROITool.js +42 -37
- package/dist/esm/tools/annotation/RegionSegmentPlusTool.js +1 -1
- package/dist/esm/tools/annotation/RegionSegmentTool.js +1 -1
- package/dist/esm/tools/annotation/SplineContourSegmentationTool.js +1 -1
- package/dist/esm/tools/annotation/SplineROITool.js +51 -49
- package/dist/esm/tools/annotation/UltrasoundDirectionalTool.js +1 -1
- package/dist/esm/tools/annotation/UltrasoundPleuraBLineTool/UltrasoundPleuraBLineTool.js +57 -55
- package/dist/esm/tools/annotation/VideoRedactionTool.js +1 -1
- package/dist/esm/tools/base/AnnotationDisplayTool.js +9 -6
- package/dist/esm/tools/base/AnnotationTool.js +2 -1
- package/dist/esm/tools/base/BaseTool.js +16 -10
- package/dist/esm/tools/base/ContourSegmentationBaseTool.js +1 -1
- package/dist/esm/tools/base/GrowCutBaseTool.js +2 -2
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.d.ts +2 -4
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js +15 -85
- package/dist/esm/tools/displayTools/Labelmap/labelmapActorStyle.d.ts +5 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapActorStyle.js +191 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.d.ts +4 -3
- package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js +48 -209
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/createLabelmapRenderPlan.d.ts +3 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/createLabelmapRenderPlan.js +51 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/index.d.ts +4 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/index.js +3 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/legacyVolumePlan.d.ts +14 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/legacyVolumePlan.js +143 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/planarGenericVolumeLabelmap.d.ts +40 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/planarGenericVolumeLabelmap.js +79 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/removeLabelmapRepresentationFromViewport.d.ts +3 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/removeLabelmapRepresentationFromViewport.js +18 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/resolveLabelmapRenderPlan.d.ts +9 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/resolveLabelmapRenderPlan.js +56 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/stackImagePlan.d.ts +11 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/stackImagePlan.js +35 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/types.d.ts +48 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/types.js +0 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/volumeSliceImageMapperPlan.d.ts +13 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan/volumeSliceImageMapperPlan.js +34 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan.d.ts +2 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRenderPlan.js +1 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRepresentationUID.d.ts +8 -0
- package/dist/esm/tools/displayTools/Labelmap/labelmapRepresentationUID.js +18 -0
- package/dist/esm/tools/displayTools/Labelmap/removeLabelmapFromElement.js +2 -5
- package/dist/esm/tools/displayTools/Labelmap/removeLabelmapRepresentationData.d.ts +3 -0
- package/dist/esm/tools/displayTools/Labelmap/removeLabelmapRepresentationData.js +16 -0
- package/dist/esm/tools/displayTools/Labelmap/syncStackLabelmapActors.d.ts +2 -0
- package/dist/esm/tools/displayTools/Labelmap/syncStackLabelmapActors.js +135 -0
- package/dist/esm/tools/displayTools/Labelmap/volumeLabelmapImageMapper.d.ts +16 -0
- package/dist/esm/tools/displayTools/Labelmap/volumeLabelmapImageMapper.js +267 -0
- package/dist/esm/tools/displayTools/Labelmap/volumeLabelmapSliceData.d.ts +27 -0
- package/dist/esm/tools/displayTools/Labelmap/volumeLabelmapSliceData.js +185 -0
- package/dist/esm/tools/displayTools/registerBuiltInSegmentationRepresentationDisplays.d.ts +1 -0
- package/dist/esm/tools/displayTools/registerBuiltInSegmentationRepresentationDisplays.js +16 -0
- package/dist/esm/tools/segmentation/BrushTool.d.ts +9 -2
- package/dist/esm/tools/segmentation/BrushTool.js +109 -25
- package/dist/esm/tools/segmentation/CircleScissorsTool.js +13 -6
- package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +2 -3
- package/dist/esm/tools/segmentation/LabelmapBaseTool.js +77 -38
- package/dist/esm/tools/segmentation/LabelmapEditWithContour.js +3 -3
- package/dist/esm/tools/segmentation/PaintFillTool.js +11 -4
- package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.d.ts +2 -0
- package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +16 -8
- package/dist/esm/tools/segmentation/RectangleScissorsTool.js +13 -6
- package/dist/esm/tools/segmentation/SegmentBidirectionalTool.js +63 -61
- package/dist/esm/tools/segmentation/SegmentSelectTool.js +4 -4
- package/dist/esm/tools/segmentation/SphereScissorsTool.js +5 -1
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.d.ts +7 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +47 -24
- package/dist/esm/tools/segmentation/strategies/compositions/circularCursor.js +49 -15
- package/dist/esm/tools/segmentation/strategies/compositions/determineSegmentIndex.js +2 -2
- package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js +5 -1
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemovalComposition.js +2 -2
- package/dist/esm/tools/segmentation/strategies/compositions/preview.js +2 -2
- package/dist/esm/tools/segmentation/strategies/compositions/setValue.js +14 -6
- package/dist/esm/tools/segmentation/strategies/utils/crossLayerErase.d.ts +4 -0
- package/dist/esm/tools/segmentation/strategies/utils/crossLayerErase.js +23 -0
- package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js +1 -1
- package/dist/esm/tools/segmentation/strategies/utils/handleUseSegmentCenterIndex.js +12 -11
- package/dist/esm/tools/segmentation/strategies/utils/labelmapOverlap.d.ts +4 -0
- package/dist/esm/tools/segmentation/strategies/utils/labelmapOverlap.js +41 -0
- package/dist/esm/tools/segmentation/strategies/utils/overwritePolicy.d.ts +3 -0
- package/dist/esm/tools/segmentation/strategies/utils/overwritePolicy.js +31 -0
- package/dist/esm/tools/segmentation/strategies/utils/segmentSeparation.d.ts +3 -0
- package/dist/esm/tools/segmentation/strategies/utils/segmentSeparation.js +38 -0
- package/dist/esm/tools/segmentation/utils/LazyBrushEditController.d.ts +19 -0
- package/dist/esm/tools/segmentation/utils/LazyBrushEditController.js +55 -0
- package/dist/esm/tools/segmentation/utils/lazyBrushPreview.d.ts +3 -0
- package/dist/esm/tools/segmentation/utils/lazyBrushPreview.js +34 -0
- package/dist/esm/tools/segmentation/utils/shouldUseLazyLabelmapEditing.d.ts +3 -0
- package/dist/esm/tools/segmentation/utils/shouldUseLazyLabelmapEditing.js +42 -0
- package/dist/esm/types/LabelmapToolOperationData.d.ts +5 -0
- package/dist/esm/types/LabelmapTypes.d.ts +29 -6
- package/dist/esm/types/SegmentationStateTypes.d.ts +4 -0
- package/dist/esm/utilities/calibrateImageSpacing.js +17 -2
- package/dist/esm/utilities/contours/AnnotationToPointData.js +1 -1
- package/dist/esm/utilities/getSphereBoundsInfo.js +5 -1
- package/dist/esm/utilities/getViewportICamera.d.ts +4 -0
- package/dist/esm/utilities/getViewportICamera.js +23 -0
- package/dist/esm/utilities/getViewportsForAnnotation.js +5 -1
- package/dist/esm/utilities/math/basic/BasicStatsCalculator.js +9 -7
- package/dist/esm/utilities/pointInSurroundingSphereCallback.js +8 -1
- package/dist/esm/utilities/segmentation/InterpolationManager/InterpolationManager.js +121 -118
- package/dist/esm/utilities/segmentation/SegmentStatsCalculator.js +5 -4
- package/dist/esm/utilities/segmentation/VolumetricCalculator.js +1 -1
- package/dist/esm/utilities/segmentation/createLabelmapVolumeForViewport.js +1 -1
- package/dist/esm/utilities/segmentation/getReferenceVolumeForSegmentation.js +1 -1
- package/dist/esm/utilities/segmentation/getReferenceVolumeForSegmentationVolume.js +11 -2
- package/dist/esm/utilities/segmentation/getSegmentIndexAtLabelmapBorder.js +36 -17
- package/dist/esm/utilities/segmentation/getSegmentIndexAtWorldPoint.js +42 -25
- package/dist/esm/utilities/segmentation/getUniqueSegmentIndices.js +3 -30
- package/dist/esm/utilities/segmentation/index.d.ts +2 -1
- package/dist/esm/utilities/segmentation/index.js +2 -1
- package/dist/esm/utilities/segmentation/utilsForWorker.js +2 -2
- package/dist/esm/utilities/segmentation/validateLabelmap.js +1 -1
- package/dist/esm/utilities/stackPrefetch/stackPrefetch.js +0 -1
- package/dist/esm/utilities/touch/index.js +3 -2
- package/dist/esm/utilities/viewportCapabilities.d.ts +16 -0
- package/dist/esm/utilities/viewportCapabilities.js +18 -0
- package/dist/esm/utilities/viewportFilters/filterViewportsWithParallelNormals.d.ts +1 -1
- package/dist/esm/utilities/viewportFilters/filterViewportsWithParallelNormals.js +12 -4
- package/dist/esm/utilities/viewportFilters/filterViewportsWithSameOrientation.d.ts +1 -1
- package/dist/esm/utilities/viewportFilters/filterViewportsWithSameOrientation.js +11 -4
- package/dist/esm/utilities/viewportFilters/getViewportIdsWithToolToRender.js +1 -1
- package/dist/esm/utilities/viewportPresentation.d.ts +3 -0
- package/dist/esm/utilities/viewportPresentation.js +26 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +10 -10
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { cache, imageLoader, volumeLoader } from '@cornerstonejs/core';
|
|
2
|
+
import { ensureLabelmapState } from './normalizeLabelmapSegmentationData';
|
|
3
|
+
import { forEachLabelmapImageReference, hasMultipleLabelmapImagesPerReferencedImageId, } from './labelmapImageIdMapping';
|
|
4
|
+
function getLabelmap(segmentation, labelmapId) {
|
|
5
|
+
return ensureLabelmapState(segmentation)?.labelmaps?.[labelmapId];
|
|
6
|
+
}
|
|
7
|
+
function getLabelmaps(segmentation) {
|
|
8
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
9
|
+
if (!labelmapState) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return Object.values(labelmapState.labelmaps);
|
|
13
|
+
}
|
|
14
|
+
function registerLabelmap(segmentation, layer) {
|
|
15
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
16
|
+
if (!labelmapState) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
labelmapState.labelmaps[layer.labelmapId] = layer;
|
|
20
|
+
}
|
|
21
|
+
function removeLabelmap(segmentation, labelmapId) {
|
|
22
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
23
|
+
if (!labelmapState) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const layer = labelmapState.labelmaps[labelmapId];
|
|
27
|
+
if (layer?.geometryVolumeId && cache.getVolume(layer.geometryVolumeId)) {
|
|
28
|
+
cache.removeVolumeLoadObject(layer.geometryVolumeId);
|
|
29
|
+
}
|
|
30
|
+
delete labelmapState.labelmaps[labelmapId];
|
|
31
|
+
}
|
|
32
|
+
function getOrCreateLabelmapVolume(layer) {
|
|
33
|
+
const mergedVolume = getOrCreateMergedStackLabelmapVolume(layer);
|
|
34
|
+
if (mergedVolume) {
|
|
35
|
+
return mergedVolume;
|
|
36
|
+
}
|
|
37
|
+
const existingVolumeId = layer.volumeId ?? layer.geometryVolumeId;
|
|
38
|
+
if (existingVolumeId) {
|
|
39
|
+
const cachedVolume = cache.getVolume(existingVolumeId);
|
|
40
|
+
if (cachedVolume) {
|
|
41
|
+
return cachedVolume;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const imageIds = layer.imageIds ?? [];
|
|
45
|
+
if (!imageIds.length) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const volumeId = layer.volumeId ?? layer.geometryVolumeId ?? `${layer.labelmapId}-geometry`;
|
|
49
|
+
if (!layer.volumeId) {
|
|
50
|
+
layer.geometryVolumeId = volumeId;
|
|
51
|
+
}
|
|
52
|
+
const cachedVolume = cache.getVolume(volumeId);
|
|
53
|
+
if (cachedVolume) {
|
|
54
|
+
return cachedVolume;
|
|
55
|
+
}
|
|
56
|
+
return volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, imageIds);
|
|
57
|
+
}
|
|
58
|
+
function getOrCreateMergedStackLabelmapVolume(layer) {
|
|
59
|
+
if (layer.volumeId || !hasDuplicateReferencedImageIds(layer)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const volumeId = layer.geometryVolumeId ?? `${layer.labelmapId}-geometry`;
|
|
63
|
+
const cachedVolume = cache.getVolume(volumeId);
|
|
64
|
+
if (cachedVolume) {
|
|
65
|
+
return cachedVolume;
|
|
66
|
+
}
|
|
67
|
+
const imageIdsByReferencedImageId = new Map();
|
|
68
|
+
forEachLabelmapImageReference(layer, (referencedImageId, imageId) => {
|
|
69
|
+
const imageIdsForReference = imageIdsByReferencedImageId.get(referencedImageId) ?? [];
|
|
70
|
+
imageIdsForReference.push(imageId);
|
|
71
|
+
imageIdsByReferencedImageId.set(referencedImageId, imageIdsForReference);
|
|
72
|
+
});
|
|
73
|
+
const mergedReferencedImageIds = Array.from(imageIdsByReferencedImageId.keys());
|
|
74
|
+
if (!mergedReferencedImageIds.length) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
let mergedImageIndex = 0;
|
|
78
|
+
const mergedImages = imageLoader.createAndCacheDerivedImages(mergedReferencedImageIds, {
|
|
79
|
+
getDerivedImageId: () => `${volumeId}-image-${mergedImageIndex++}`,
|
|
80
|
+
targetBuffer: { type: 'Uint8Array' },
|
|
81
|
+
});
|
|
82
|
+
mergedImages.forEach((mergedImage) => {
|
|
83
|
+
const sourceImageIds = imageIdsByReferencedImageId.get(mergedImage.referencedImageId);
|
|
84
|
+
if (!sourceImageIds?.length) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const targetVoxelManager = mergedImage.voxelManager;
|
|
88
|
+
const scalarDataLength = targetVoxelManager.getScalarDataLength();
|
|
89
|
+
sourceImageIds.forEach((sourceImageId) => {
|
|
90
|
+
const sourceImage = cache.getImage(sourceImageId);
|
|
91
|
+
const sourceVoxelManager = sourceImage?.voxelManager;
|
|
92
|
+
if (!sourceVoxelManager) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const sourceScalarDataLength = sourceVoxelManager.getScalarDataLength();
|
|
96
|
+
const length = Math.min(scalarDataLength, sourceScalarDataLength);
|
|
97
|
+
for (let index = 0; index < length; index++) {
|
|
98
|
+
const value = Number(sourceVoxelManager.getAtIndex(index));
|
|
99
|
+
if (value !== 0) {
|
|
100
|
+
targetVoxelManager.setAtIndex(index, value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
layer.geometryVolumeId = volumeId;
|
|
106
|
+
return volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, mergedImages.map((image) => image.imageId));
|
|
107
|
+
}
|
|
108
|
+
function hasDuplicateReferencedImageIds(layer) {
|
|
109
|
+
return hasMultipleLabelmapImagesPerReferencedImageId(layer);
|
|
110
|
+
}
|
|
111
|
+
function getLabelmapIds(segmentation) {
|
|
112
|
+
return getLabelmaps(segmentation).map((layer) => layer.labelmapId);
|
|
113
|
+
}
|
|
114
|
+
function getLabelmapDataById(segmentation, labelmapId) {
|
|
115
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
116
|
+
const layer = labelmapState?.labelmaps?.[labelmapId];
|
|
117
|
+
if (!labelmapState || !layer) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
volumeId: layer.volumeId,
|
|
122
|
+
referencedVolumeId: layer.referencedVolumeId,
|
|
123
|
+
imageIds: layer.imageIds,
|
|
124
|
+
referencedImageIds: layer.referencedImageIds,
|
|
125
|
+
sourceRepresentationName: labelmapState.sourceRepresentationName,
|
|
126
|
+
primaryLabelmapId: labelmapId,
|
|
127
|
+
labelmaps: {
|
|
128
|
+
[labelmapId]: layer,
|
|
129
|
+
},
|
|
130
|
+
segmentBindings: Object.fromEntries(Object.entries(labelmapState.segmentBindings).filter(([, binding]) => binding.labelmapId === labelmapId)),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function getScalarArrayLengthFromLabelmap(layer) {
|
|
134
|
+
if (layer.volumeId) {
|
|
135
|
+
return cache.getVolume(layer.volumeId)?.voxelManager?.getScalarDataLength();
|
|
136
|
+
}
|
|
137
|
+
const firstImageId = layer.imageIds?.[0];
|
|
138
|
+
const firstImage = firstImageId ? cache.getImage(firstImageId) : null;
|
|
139
|
+
if (!firstImage || !layer.imageIds?.length) {
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
return firstImage.voxelManager.getScalarDataLength() * layer.imageIds.length;
|
|
143
|
+
}
|
|
144
|
+
function getConstructorNameForLabelmap(layer) {
|
|
145
|
+
if (layer.volumeId) {
|
|
146
|
+
return cache.getVolume(layer.volumeId)?.voxelManager?.getConstructor()
|
|
147
|
+
?.name;
|
|
148
|
+
}
|
|
149
|
+
const imageId = layer.imageIds?.[0];
|
|
150
|
+
return imageId
|
|
151
|
+
? cache.getImage(imageId)?.voxelManager?.getConstructor()?.name
|
|
152
|
+
: undefined;
|
|
153
|
+
}
|
|
154
|
+
function getLabelmapForImageId(segmentation, imageId) {
|
|
155
|
+
return getLabelmaps(segmentation).find((layer) => layer.imageIds?.includes(imageId));
|
|
156
|
+
}
|
|
157
|
+
function getLabelmapForVolumeId(segmentation, volumeId) {
|
|
158
|
+
return getLabelmaps(segmentation).find((layer) => layer.volumeId === volumeId || layer.geometryVolumeId === volumeId);
|
|
159
|
+
}
|
|
160
|
+
export { getConstructorNameForLabelmap, getLabelmap, getLabelmapDataById, getLabelmapForImageId, getLabelmapForVolumeId, getLabelmapIds, getLabelmaps, getOrCreateLabelmapVolume, getScalarArrayLengthFromLabelmap, registerLabelmap, removeLabelmap, };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
declare function syncLegacyLabelmapData(segmentation: Segmentation): void;
|
|
3
|
+
declare function getReferencedImageIdToCurrentImageIdMap(segmentation: Segmentation): Map<string, string[]>;
|
|
4
|
+
export { getReferencedImageIdToCurrentImageIdMap, syncLegacyLabelmapData };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ensureLabelmapState, getSegmentOrder, } from './normalizeLabelmapSegmentationData';
|
|
2
|
+
import { getLabelmaps } from './labelmapLayerStore';
|
|
3
|
+
import { forEachLabelmapImageReference } from './labelmapImageIdMapping';
|
|
4
|
+
function syncOptionalLegacyProperty(target, key, value) {
|
|
5
|
+
if (value == null) {
|
|
6
|
+
delete target[key];
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
target[key] = value;
|
|
10
|
+
}
|
|
11
|
+
function syncLegacyLabelmapData(segmentation) {
|
|
12
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
13
|
+
if (!labelmapState) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const firstSegmentIndex = getSegmentOrder(segmentation)[0] ?? 1;
|
|
17
|
+
const primaryLabelmapId = labelmapState.primaryLabelmapId ??
|
|
18
|
+
labelmapState.segmentBindings[firstSegmentIndex]?.labelmapId ??
|
|
19
|
+
Object.keys(labelmapState.labelmaps)[0];
|
|
20
|
+
const primaryLayer = labelmapState.labelmaps[primaryLabelmapId];
|
|
21
|
+
if (!primaryLayer) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
syncOptionalLegacyProperty(labelmapState, 'volumeId', primaryLayer.volumeId);
|
|
25
|
+
syncOptionalLegacyProperty(labelmapState, 'referencedVolumeId', primaryLayer.referencedVolumeId);
|
|
26
|
+
syncOptionalLegacyProperty(labelmapState, 'imageIds', primaryLayer.imageIds);
|
|
27
|
+
syncOptionalLegacyProperty(labelmapState, 'referencedImageIds', primaryLayer.referencedImageIds);
|
|
28
|
+
}
|
|
29
|
+
function getReferencedImageIdToCurrentImageIdMap(segmentation) {
|
|
30
|
+
const map = new Map();
|
|
31
|
+
getLabelmaps(segmentation).forEach((layer) => {
|
|
32
|
+
forEachLabelmapImageReference(layer, (referenceImageId, labelmapImageId) => {
|
|
33
|
+
const values = map.get(referenceImageId) ?? [];
|
|
34
|
+
if (!values.includes(labelmapImageId)) {
|
|
35
|
+
values.push(labelmapImageId);
|
|
36
|
+
}
|
|
37
|
+
map.set(referenceImageId, values);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
return map;
|
|
41
|
+
}
|
|
42
|
+
export { getReferencedImageIdToCurrentImageIdMap, syncLegacyLabelmapData };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
import type { LabelmapLayer, SegmentLabelmapBindingState } from '../../../types/LabelmapTypes';
|
|
3
|
+
declare function getSegmentBinding(segmentation: Segmentation, segmentIndex: number): SegmentLabelmapBindingState | undefined;
|
|
4
|
+
declare function setSegmentBinding(segmentation: Segmentation, segmentIndex: number, binding: SegmentLabelmapBindingState): void;
|
|
5
|
+
declare function getSegmentsOnLabelmap(segmentation: Segmentation, labelmapId: string): number[];
|
|
6
|
+
declare function getSegmentIndexForLabelValue(segmentation: Segmentation, labelmapId: string, labelValue: number): number | undefined;
|
|
7
|
+
declare function getLabelValueForSegment(segmentation: Segmentation, segmentIndex: number): number;
|
|
8
|
+
declare function getLabelmapForSegment(segmentation: Segmentation, segmentIndex: number): LabelmapLayer | undefined;
|
|
9
|
+
declare function resolveLabelmapForSegment(segmentation: Segmentation, segmentIndex: number): LabelmapLayer | undefined;
|
|
10
|
+
declare function removeSegmentBinding(segmentation: Segmentation, segmentIndex: number): void;
|
|
11
|
+
export { getLabelmapForSegment, getLabelValueForSegment, getSegmentBinding, getSegmentIndexForLabelValue, getSegmentsOnLabelmap, removeSegmentBinding, resolveLabelmapForSegment, setSegmentBinding, };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ensureLabelmapState } from './normalizeLabelmapSegmentationData';
|
|
2
|
+
import { getLabelmap, getLabelmaps, removeLabelmap, } from './labelmapLayerStore';
|
|
3
|
+
import { syncLegacyLabelmapData } from './labelmapLegacyAdapter';
|
|
4
|
+
function getSegmentBinding(segmentation, segmentIndex) {
|
|
5
|
+
return ensureLabelmapState(segmentation)?.segmentBindings?.[segmentIndex];
|
|
6
|
+
}
|
|
7
|
+
function setSegmentBinding(segmentation, segmentIndex, binding) {
|
|
8
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
9
|
+
if (!labelmapState) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const previousBinding = labelmapState.segmentBindings[segmentIndex];
|
|
13
|
+
if (previousBinding) {
|
|
14
|
+
const previousLayer = labelmapState.labelmaps[previousBinding.labelmapId];
|
|
15
|
+
if (previousLayer?.labelToSegmentIndex) {
|
|
16
|
+
delete previousLayer.labelToSegmentIndex[previousBinding.labelValue];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
labelmapState.segmentBindings[segmentIndex] = binding;
|
|
20
|
+
const layer = labelmapState.labelmaps[binding.labelmapId];
|
|
21
|
+
if (layer) {
|
|
22
|
+
layer.labelToSegmentIndex ||= {};
|
|
23
|
+
layer.labelToSegmentIndex[binding.labelValue] = segmentIndex;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getSegmentsOnLabelmap(segmentation, labelmapId) {
|
|
27
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
28
|
+
if (!labelmapState) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return Object.entries(labelmapState.segmentBindings)
|
|
32
|
+
.filter(([, binding]) => binding.labelmapId === labelmapId)
|
|
33
|
+
.map(([segmentIndex]) => Number(segmentIndex))
|
|
34
|
+
.sort((a, b) => a - b);
|
|
35
|
+
}
|
|
36
|
+
function getSegmentIndexForLabelValue(segmentation, labelmapId, labelValue) {
|
|
37
|
+
const layer = getLabelmap(segmentation, labelmapId);
|
|
38
|
+
if (!layer || labelValue == null) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
return layer.labelToSegmentIndex?.[labelValue] ?? labelValue;
|
|
42
|
+
}
|
|
43
|
+
function getLabelValueForSegment(segmentation, segmentIndex) {
|
|
44
|
+
return (getSegmentBinding(segmentation, segmentIndex)?.labelValue ?? segmentIndex);
|
|
45
|
+
}
|
|
46
|
+
function getLabelmapForSegment(segmentation, segmentIndex) {
|
|
47
|
+
const binding = getSegmentBinding(segmentation, segmentIndex);
|
|
48
|
+
if (!binding) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
return getLabelmap(segmentation, binding.labelmapId);
|
|
52
|
+
}
|
|
53
|
+
function resolveLabelmapForSegment(segmentation, segmentIndex) {
|
|
54
|
+
return (getLabelmapForSegment(segmentation, segmentIndex) ??
|
|
55
|
+
getLabelmaps(segmentation)[0]);
|
|
56
|
+
}
|
|
57
|
+
function removeSegmentBinding(segmentation, segmentIndex) {
|
|
58
|
+
const labelmapState = ensureLabelmapState(segmentation);
|
|
59
|
+
const binding = labelmapState?.segmentBindings?.[segmentIndex];
|
|
60
|
+
if (!labelmapState || !binding) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const layer = labelmapState.labelmaps[binding.labelmapId];
|
|
64
|
+
if (layer?.labelToSegmentIndex) {
|
|
65
|
+
delete layer.labelToSegmentIndex[binding.labelValue];
|
|
66
|
+
}
|
|
67
|
+
delete labelmapState.segmentBindings[segmentIndex];
|
|
68
|
+
if (getSegmentsOnLabelmap(segmentation, binding.labelmapId).length === 0) {
|
|
69
|
+
removeLabelmap(segmentation, binding.labelmapId);
|
|
70
|
+
}
|
|
71
|
+
syncLegacyLabelmapData(segmentation);
|
|
72
|
+
}
|
|
73
|
+
export { getLabelmapForSegment, getLabelValueForSegment, getSegmentBinding, getSegmentIndexForLabelValue, getSegmentsOnLabelmap, removeSegmentBinding, resolveLabelmapForSegment, setSegmentBinding, };
|
package/dist/esm/stateManagement/segmentation/labelmapModel/normalizeLabelmapSegmentationData.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
import type { LabelmapSegmentationData, LabelmapLayer, SegmentLabelmapBindingState } from '../../../types/LabelmapTypes';
|
|
3
|
+
declare const SOURCE_REPRESENTATION_NAME = "binaryLabelmap";
|
|
4
|
+
type LabelmapSegmentationWithState = LabelmapSegmentationData & {
|
|
5
|
+
labelmaps: {
|
|
6
|
+
[labelmapId: string]: LabelmapLayer;
|
|
7
|
+
};
|
|
8
|
+
segmentBindings: {
|
|
9
|
+
[segmentIndex: number]: SegmentLabelmapBindingState;
|
|
10
|
+
};
|
|
11
|
+
primaryLabelmapId: string;
|
|
12
|
+
};
|
|
13
|
+
declare function getSegmentOrder(segmentation: Segmentation): number[];
|
|
14
|
+
declare function getPrimaryLabelmapId(segmentationId: string): string;
|
|
15
|
+
declare function ensureLabelmapState(segmentation: Segmentation): LabelmapSegmentationWithState | undefined;
|
|
16
|
+
export { SOURCE_REPRESENTATION_NAME, ensureLabelmapState, getPrimaryLabelmapId, getSegmentOrder, };
|
|
17
|
+
export type { LabelmapSegmentationWithState };
|
package/dist/esm/stateManagement/segmentation/labelmapModel/normalizeLabelmapSegmentationData.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const SOURCE_REPRESENTATION_NAME = 'binaryLabelmap';
|
|
2
|
+
function getSegmentOrder(segmentation) {
|
|
3
|
+
if (segmentation.segmentOrder?.length) {
|
|
4
|
+
return [...segmentation.segmentOrder];
|
|
5
|
+
}
|
|
6
|
+
return Object.keys(segmentation.segments)
|
|
7
|
+
.map(Number)
|
|
8
|
+
.sort((a, b) => a - b);
|
|
9
|
+
}
|
|
10
|
+
function getPrimaryLabelmapId(segmentationId) {
|
|
11
|
+
return `${segmentationId}-storage-0`;
|
|
12
|
+
}
|
|
13
|
+
function getPrimaryLabelmapType(labelmapData) {
|
|
14
|
+
return labelmapData.volumeId ? 'volume' : 'stack';
|
|
15
|
+
}
|
|
16
|
+
function createPrimaryLabelmapLayer(segmentation, labelmapData, labelmapId = getPrimaryLabelmapId(segmentation.segmentationId)) {
|
|
17
|
+
const layer = {
|
|
18
|
+
labelmapId,
|
|
19
|
+
type: getPrimaryLabelmapType(labelmapData),
|
|
20
|
+
labelToSegmentIndex: {},
|
|
21
|
+
};
|
|
22
|
+
if (labelmapData.volumeId != null) {
|
|
23
|
+
layer.volumeId = labelmapData.volumeId;
|
|
24
|
+
}
|
|
25
|
+
if (labelmapData.referencedVolumeId != null) {
|
|
26
|
+
layer.referencedVolumeId = labelmapData.referencedVolumeId;
|
|
27
|
+
}
|
|
28
|
+
if (labelmapData.referencedImageIds != null) {
|
|
29
|
+
layer.referencedImageIds = labelmapData.referencedImageIds;
|
|
30
|
+
}
|
|
31
|
+
if (labelmapData.imageIds != null) {
|
|
32
|
+
layer.imageIds = labelmapData.imageIds;
|
|
33
|
+
}
|
|
34
|
+
return layer;
|
|
35
|
+
}
|
|
36
|
+
function resolvePrimaryLabelmapId(segmentation, labelmapData) {
|
|
37
|
+
const storedLabelmapId = labelmapData.primaryLabelmapId;
|
|
38
|
+
if (storedLabelmapId && labelmapData.labelmaps?.[storedLabelmapId]) {
|
|
39
|
+
return storedLabelmapId;
|
|
40
|
+
}
|
|
41
|
+
const fallbackLabelmapId = Object.keys(labelmapData.labelmaps ?? {})[0] ??
|
|
42
|
+
getPrimaryLabelmapId(segmentation.segmentationId);
|
|
43
|
+
labelmapData.primaryLabelmapId = fallbackLabelmapId;
|
|
44
|
+
return fallbackLabelmapId;
|
|
45
|
+
}
|
|
46
|
+
function ensureLabelmapState(segmentation) {
|
|
47
|
+
const labelmapData = segmentation.representationData.Labelmap;
|
|
48
|
+
if (!labelmapData) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
labelmapData.labelmaps ||= {};
|
|
52
|
+
const primaryLabelmapId = resolvePrimaryLabelmapId(segmentation, labelmapData);
|
|
53
|
+
labelmapData.labelmaps[primaryLabelmapId] ||= createPrimaryLabelmapLayer(segmentation, labelmapData, primaryLabelmapId);
|
|
54
|
+
labelmapData.segmentBindings ||= {};
|
|
55
|
+
labelmapData.sourceRepresentationName ||= SOURCE_REPRESENTATION_NAME;
|
|
56
|
+
getSegmentOrder(segmentation).forEach((segmentIndex) => {
|
|
57
|
+
labelmapData.segmentBindings[segmentIndex] ||= {
|
|
58
|
+
labelmapId: primaryLabelmapId,
|
|
59
|
+
labelValue: segmentIndex,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
Object.values(labelmapData.labelmaps).forEach((layer) => {
|
|
63
|
+
layer.labelToSegmentIndex = {};
|
|
64
|
+
});
|
|
65
|
+
Object.entries(labelmapData.segmentBindings).forEach(([segmentIndex, binding]) => {
|
|
66
|
+
const layer = labelmapData.labelmaps[binding.labelmapId];
|
|
67
|
+
if (!layer) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
layer.labelToSegmentIndex ||= {};
|
|
71
|
+
layer.labelToSegmentIndex[binding.labelValue] = Number(segmentIndex);
|
|
72
|
+
});
|
|
73
|
+
return labelmapData;
|
|
74
|
+
}
|
|
75
|
+
export { SOURCE_REPRESENTATION_NAME, ensureLabelmapState, getPrimaryLabelmapId, getSegmentOrder, };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
import type { LabelmapLayer } from '../../../types/LabelmapTypes';
|
|
3
|
+
declare function createPrivateLabelmap(segmentation: Segmentation, sourceLabelmap: LabelmapLayer): LabelmapLayer;
|
|
4
|
+
declare function moveSegmentToPrivateLabelmap(segmentation: Segmentation, segmentIndex: number): LabelmapLayer | undefined;
|
|
5
|
+
export { createPrivateLabelmap, moveSegmentToPrivateLabelmap };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { cache, imageLoader, utilities as csUtils, volumeLoader, } from '@cornerstonejs/core';
|
|
2
|
+
import { getLabelmap, registerLabelmap } from './labelmapLayerStore';
|
|
3
|
+
import { getSegmentBinding, getSegmentsOnLabelmap, setSegmentBinding, } from './labelmapSegmentBindings';
|
|
4
|
+
import { syncLegacyLabelmapData } from './labelmapLegacyAdapter';
|
|
5
|
+
function createPrivateVolumeLabelmap(segmentation, sourceLabelmap) {
|
|
6
|
+
const sourceVolume = cache.getVolume(sourceLabelmap.volumeId);
|
|
7
|
+
const volumeId = `${segmentation.segmentationId}-storage-${csUtils.uuidv4()}`;
|
|
8
|
+
const referencedVolumeId = sourceLabelmap.referencedVolumeId ??
|
|
9
|
+
sourceVolume?.referencedVolumeId ??
|
|
10
|
+
sourceLabelmap.volumeId;
|
|
11
|
+
const volume = volumeLoader.createAndCacheDerivedLabelmapVolume(referencedVolumeId, {
|
|
12
|
+
volumeId,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
labelmapId: volumeId,
|
|
16
|
+
type: 'volume',
|
|
17
|
+
volumeId,
|
|
18
|
+
imageIds: volume.imageIds,
|
|
19
|
+
referencedVolumeId,
|
|
20
|
+
referencedImageIds: sourceLabelmap.referencedImageIds ?? sourceVolume?.referencedImageIds,
|
|
21
|
+
labelToSegmentIndex: {},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createPrivateStackLabelmap(segmentation, sourceLabelmap) {
|
|
25
|
+
const referencedImageIds = sourceLabelmap.referencedImageIds ?? sourceLabelmap.imageIds ?? [];
|
|
26
|
+
const sourceImageIds = sourceLabelmap.imageIds ?? [];
|
|
27
|
+
const sourceImage = sourceImageIds[0]
|
|
28
|
+
? cache.getImage(sourceImageIds[0])
|
|
29
|
+
: null;
|
|
30
|
+
const targetType = sourceImage?.voxelManager?.getConstructor?.().name ?? 'Uint8Array';
|
|
31
|
+
const images = imageLoader.createAndCacheDerivedImages(referencedImageIds, {
|
|
32
|
+
getDerivedImageId: (referencedImageId) => `${segmentation.segmentationId}-storage-${csUtils.uuidv4()}-${referencedImageId.slice(-12)}`,
|
|
33
|
+
targetBuffer: {
|
|
34
|
+
type: targetType,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
labelmapId: `${segmentation.segmentationId}-storage-${csUtils.uuidv4()}`,
|
|
39
|
+
type: 'stack',
|
|
40
|
+
imageIds: images.map((image) => image.imageId),
|
|
41
|
+
referencedVolumeId: sourceLabelmap.referencedVolumeId,
|
|
42
|
+
referencedImageIds,
|
|
43
|
+
labelToSegmentIndex: {},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function createPrivateLabelmap(segmentation, sourceLabelmap) {
|
|
47
|
+
if (sourceLabelmap.imageIds?.length ||
|
|
48
|
+
sourceLabelmap.referencedImageIds?.length) {
|
|
49
|
+
return createPrivateStackLabelmap(segmentation, sourceLabelmap);
|
|
50
|
+
}
|
|
51
|
+
if (sourceLabelmap.volumeId) {
|
|
52
|
+
return createPrivateVolumeLabelmap(segmentation, sourceLabelmap);
|
|
53
|
+
}
|
|
54
|
+
return createPrivateStackLabelmap(segmentation, sourceLabelmap);
|
|
55
|
+
}
|
|
56
|
+
function moveSegmentToPrivateLabelmap(segmentation, segmentIndex) {
|
|
57
|
+
const binding = getSegmentBinding(segmentation, segmentIndex);
|
|
58
|
+
if (!binding) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const sourceLabelmap = getLabelmap(segmentation, binding.labelmapId);
|
|
62
|
+
if (!sourceLabelmap) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (getSegmentsOnLabelmap(segmentation, sourceLabelmap.labelmapId).length <= 1) {
|
|
66
|
+
return sourceLabelmap;
|
|
67
|
+
}
|
|
68
|
+
const privateLabelmap = createPrivateLabelmap(segmentation, sourceLabelmap);
|
|
69
|
+
registerLabelmap(segmentation, privateLabelmap);
|
|
70
|
+
if (sourceLabelmap.volumeId && privateLabelmap.volumeId) {
|
|
71
|
+
const sourceVolume = cache.getVolume(sourceLabelmap.volumeId);
|
|
72
|
+
const targetVolume = cache.getVolume(privateLabelmap.volumeId);
|
|
73
|
+
sourceVolume.voxelManager.forEach(({ value, index }) => {
|
|
74
|
+
if (value !== binding.labelValue) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
targetVolume.voxelManager.setAtIndex(index, 1);
|
|
78
|
+
sourceVolume.voxelManager.setAtIndex(index, 0);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const sourceImageIds = sourceLabelmap.imageIds ?? [];
|
|
83
|
+
const targetImageIds = privateLabelmap.imageIds ?? [];
|
|
84
|
+
sourceImageIds.forEach((imageId, imageIndex) => {
|
|
85
|
+
const sourceImage = cache.getImage(imageId);
|
|
86
|
+
const targetImage = cache.getImage(targetImageIds[imageIndex]);
|
|
87
|
+
if (!sourceImage || !targetImage) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
sourceImage.voxelManager.forEach(({ value, index }) => {
|
|
91
|
+
if (value !== binding.labelValue) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
targetImage.voxelManager.setAtIndex(index, 1);
|
|
95
|
+
sourceImage.voxelManager.setAtIndex(index, 0);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
setSegmentBinding(segmentation, segmentIndex, {
|
|
100
|
+
labelmapId: privateLabelmap.labelmapId,
|
|
101
|
+
labelValue: 1,
|
|
102
|
+
});
|
|
103
|
+
syncLegacyLabelmapData(segmentation);
|
|
104
|
+
return privateLabelmap;
|
|
105
|
+
}
|
|
106
|
+
export { createPrivateLabelmap, moveSegmentToPrivateLabelmap };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Segment, Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
import type { SegmentLabelmapBindingState } from '../../../types/LabelmapTypes';
|
|
3
|
+
export default class SegmentModel {
|
|
4
|
+
private readonly segmentation;
|
|
5
|
+
private readonly state;
|
|
6
|
+
constructor(segmentation: Segmentation, state: Segment);
|
|
7
|
+
get segmentIndex(): number;
|
|
8
|
+
get label(): string;
|
|
9
|
+
get binding(): SegmentLabelmapBindingState | undefined;
|
|
10
|
+
toState(): Segment;
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getSegmentBinding } from '../helpers/labelmapSegmentationState';
|
|
2
|
+
export default class SegmentModel {
|
|
3
|
+
constructor(segmentation, state) {
|
|
4
|
+
this.segmentation = segmentation;
|
|
5
|
+
this.state = state;
|
|
6
|
+
}
|
|
7
|
+
get segmentIndex() {
|
|
8
|
+
return this.state.segmentIndex;
|
|
9
|
+
}
|
|
10
|
+
get label() {
|
|
11
|
+
return this.state.label;
|
|
12
|
+
}
|
|
13
|
+
get binding() {
|
|
14
|
+
return getSegmentBinding(this.segmentation, this.state.segmentIndex);
|
|
15
|
+
}
|
|
16
|
+
toState() {
|
|
17
|
+
return this.state;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Segmentation } from '../../../types/SegmentationStateTypes';
|
|
2
|
+
import type { LabelmapLayer } from '../../../types/LabelmapTypes';
|
|
3
|
+
import SegmentModel from './SegmentModel';
|
|
4
|
+
export default class SegmentationModel {
|
|
5
|
+
private readonly state;
|
|
6
|
+
constructor(state: Segmentation);
|
|
7
|
+
get segmentationId(): string;
|
|
8
|
+
get segments(): SegmentModel[];
|
|
9
|
+
getLabelmaps(): LabelmapLayer[];
|
|
10
|
+
getBinding(segmentIndex: number): import("../../../types/LabelmapTypes").SegmentLabelmapBindingState;
|
|
11
|
+
toState(): Segmentation;
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import SegmentModel from './SegmentModel';
|
|
2
|
+
import { ensureLabelmapState, getLabelmaps, getSegmentBinding, } from '../helpers/labelmapSegmentationState';
|
|
3
|
+
export default class SegmentationModel {
|
|
4
|
+
constructor(state) {
|
|
5
|
+
this.state = state;
|
|
6
|
+
ensureLabelmapState(state);
|
|
7
|
+
}
|
|
8
|
+
get segmentationId() {
|
|
9
|
+
return this.state.segmentationId;
|
|
10
|
+
}
|
|
11
|
+
get segments() {
|
|
12
|
+
return Object.values(this.state.segments).map((segment) => new SegmentModel(this.state, segment));
|
|
13
|
+
}
|
|
14
|
+
getLabelmaps() {
|
|
15
|
+
return getLabelmaps(this.state);
|
|
16
|
+
}
|
|
17
|
+
getBinding(segmentIndex) {
|
|
18
|
+
return getSegmentBinding(this.state, segmentIndex);
|
|
19
|
+
}
|
|
20
|
+
toState() {
|
|
21
|
+
return this.state;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import SegmentationRepresentations from '../../enums/SegmentationRepresentations';
|
|
2
|
-
import labelmapDisplay from '../../tools/displayTools/Labelmap/labelmapDisplay';
|
|
3
|
-
import contourDisplay from '../../tools/displayTools/Contour/contourDisplay';
|
|
4
2
|
import { getSegmentationRepresentations } from './getSegmentationRepresentation';
|
|
5
3
|
import { getEnabledElementByViewportId } from '@cornerstonejs/core';
|
|
6
4
|
import { defaultSegmentationStateManager } from './SegmentationStateManager';
|
|
7
|
-
import { surfaceDisplay } from '../../tools/displayTools/Surface';
|
|
8
5
|
import { removeSegmentationListener } from './segmentationEventManager';
|
|
6
|
+
import { getSegmentationRepresentationDisplay } from './SegmentationRepresentationDisplayRegistry';
|
|
9
7
|
function removeSegmentationRepresentation(viewportId, specifier, immediate) {
|
|
10
8
|
return _removeSegmentationRepresentations(viewportId, specifier, immediate);
|
|
11
9
|
}
|
|
@@ -56,14 +54,12 @@ function _removeRepresentationObject(viewportId, segmentationId, type, immediate
|
|
|
56
54
|
type,
|
|
57
55
|
});
|
|
58
56
|
representations.forEach((representation) => {
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
const display = getSegmentationRepresentationDisplay(representation.type);
|
|
58
|
+
if (display) {
|
|
59
|
+
display.removeRepresentation(viewportId, representation.segmentationId, immediate);
|
|
61
60
|
}
|
|
62
|
-
else
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
else if (representation.type === SegmentationRepresentations.Surface) {
|
|
66
|
-
surfaceDisplay.removeRepresentation(viewportId, representation.segmentationId, immediate);
|
|
61
|
+
else {
|
|
62
|
+
console.warn(`No display registered for segmentation representation type ${representation.type}.`);
|
|
67
63
|
}
|
|
68
64
|
removeSegmentationListener(representation.segmentationId, representation.type);
|
|
69
65
|
});
|
|
@@ -5,6 +5,7 @@ import { getViewportIdsWithSegmentation } from './getViewportIdsWithSegmentation
|
|
|
5
5
|
import { triggerSegmentationModified } from './triggerSegmentationEvents';
|
|
6
6
|
import { getActiveSegmentIndex } from './getActiveSegmentIndex';
|
|
7
7
|
import { getSegmentationRepresentations } from './getSegmentationRepresentation';
|
|
8
|
+
import { ensureLabelmapState, getSegmentBinding, getLabelmaps, setSegmentBinding, syncLegacyLabelmapData, } from './helpers/labelmapSegmentationState';
|
|
8
9
|
function setActiveSegmentIndex(segmentationId, segmentIndex) {
|
|
9
10
|
const segmentation = getSegmentation(segmentationId);
|
|
10
11
|
if (typeof segmentIndex === 'string') {
|
|
@@ -22,6 +23,29 @@ function setActiveSegmentIndex(segmentationId, segmentIndex) {
|
|
|
22
23
|
cachedStats: {},
|
|
23
24
|
active: false,
|
|
24
25
|
};
|
|
26
|
+
if (segmentation.representationData?.Labelmap) {
|
|
27
|
+
ensureLabelmapState(segmentation);
|
|
28
|
+
const primaryLayer = getLabelmaps(segmentation)[0];
|
|
29
|
+
if (primaryLayer) {
|
|
30
|
+
setSegmentBinding(segmentation, segmentIndex, {
|
|
31
|
+
labelmapId: primaryLayer.labelmapId,
|
|
32
|
+
labelValue: segmentIndex,
|
|
33
|
+
});
|
|
34
|
+
syncLegacyLabelmapData(segmentation);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (segmentation.representationData?.Labelmap &&
|
|
39
|
+
!getSegmentBinding(segmentation, segmentIndex)) {
|
|
40
|
+
ensureLabelmapState(segmentation);
|
|
41
|
+
const primaryLayer = getLabelmaps(segmentation)[0];
|
|
42
|
+
if (primaryLayer) {
|
|
43
|
+
setSegmentBinding(segmentation, segmentIndex, {
|
|
44
|
+
labelmapId: primaryLayer.labelmapId,
|
|
45
|
+
labelValue: segmentIndex,
|
|
46
|
+
});
|
|
47
|
+
syncLegacyLabelmapData(segmentation);
|
|
48
|
+
}
|
|
25
49
|
}
|
|
26
50
|
if (segmentation.segments[segmentIndex].active !== true) {
|
|
27
51
|
segmentation.segments[segmentIndex].active = true;
|
|
@@ -2,18 +2,11 @@ import { eventTarget } from '@cornerstonejs/core';
|
|
|
2
2
|
import { Events, SegmentationRepresentations } from '../../enums';
|
|
3
3
|
import { triggerSegmentationModified } from './triggerSegmentationEvents';
|
|
4
4
|
import debounce from '../../utilities/debounce';
|
|
5
|
-
import surfaceDisplay from '../../tools/displayTools/Surface/surfaceDisplay';
|
|
6
|
-
import contourDisplay from '../../tools/displayTools/Contour/contourDisplay';
|
|
7
|
-
import labelmapDisplay from '../../tools/displayTools/Labelmap/labelmapDisplay';
|
|
8
5
|
import { getSegmentation } from './getSegmentation';
|
|
9
|
-
|
|
10
|
-
[SegmentationRepresentations.Labelmap]: labelmapDisplay,
|
|
11
|
-
[SegmentationRepresentations.Contour]: contourDisplay,
|
|
12
|
-
[SegmentationRepresentations.Surface]: surfaceDisplay,
|
|
13
|
-
};
|
|
6
|
+
import { getSegmentationRepresentationDisplay } from './SegmentationRepresentationDisplayRegistry';
|
|
14
7
|
const segmentationListeners = new Map();
|
|
15
8
|
export function addDefaultSegmentationListener(viewport, segmentationId, representationType) {
|
|
16
|
-
const updateFunction =
|
|
9
|
+
const updateFunction = getSegmentationRepresentationDisplay(representationType)?.getUpdateFunction(viewport);
|
|
17
10
|
if (updateFunction) {
|
|
18
11
|
addSegmentationListener(segmentationId, representationType, updateFunction);
|
|
19
12
|
}
|