@cornerstonejs/tools 2.0.0-beta.23 → 2.0.0-beta.25
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/enums/SegmentationRepresentations.d.ts +3 -3
- package/dist/esm/enums/SegmentationRepresentations.js +3 -3
- package/dist/esm/eventDispatchers/mouseEventHandlers/mouseMove.js +4 -0
- package/dist/esm/eventListeners/segmentation/labelmap/onLabelmapSegmentationDataModified.js +27 -23
- package/dist/esm/eventListeners/segmentation/segmentationDataModifiedEventListener.js +2 -2
- package/dist/esm/stateManagement/index.d.ts +3 -2
- package/dist/esm/stateManagement/index.js +2 -2
- package/dist/esm/stateManagement/segmentation/SegmentationRenderingEngine.d.ts +1 -2
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +9 -6
- package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +72 -24
- package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.d.ts +8 -3
- package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.js +14 -4
- package/dist/esm/stateManagement/segmentation/config/segmentationConfig.d.ts +8 -7
- package/dist/esm/stateManagement/segmentation/convertVolumeToStackSegmentation.js +1 -1
- package/dist/esm/stateManagement/segmentation/getGlobalConfig.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/getPerSegmentConfig.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/getStackSegmentationImageIdsForViewport.d.ts +1 -0
- package/dist/esm/stateManagement/segmentation/getStackSegmentationImageIdsForViewport.js +5 -0
- package/dist/esm/stateManagement/segmentation/helpers/updateStackSegmentationState.js +5 -5
- package/dist/esm/stateManagement/segmentation/index.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/index.js +2 -2
- package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.d.ts +3 -0
- package/dist/esm/stateManagement/segmentation/{addSegmentationRepresentation.js → internalAddSegmentationRepresentation.js} +4 -3
- package/dist/esm/stateManagement/segmentation/polySeg/Contour/contourComputationStrategies.js +4 -4
- package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +4 -4
- package/dist/esm/stateManagement/segmentation/polySeg/Surface/createAndCacheSurfacesFromRaw.js +1 -1
- package/dist/esm/stateManagement/segmentation/polySeg/Surface/surfaceComputationStrategies.js +6 -6
- package/dist/esm/stateManagement/segmentation/polySeg/Surface/updateSurfaceData.js +2 -2
- package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/segmentationState.js +2 -2
- package/dist/esm/stateManagement/segmentation/setGlobalConfig.d.ts +2 -2
- package/dist/esm/stateManagement/segmentation/setPerSegmentConfig.d.ts +2 -2
- package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +1 -1
- package/dist/esm/tools/AdvancedMagnifyTool.js +2 -2
- package/dist/esm/tools/ScaleOverlayTool.js +23 -20
- package/dist/esm/tools/annotation/LivewireContourTool.d.ts +5 -0
- package/dist/esm/tools/annotation/LivewireContourTool.js +156 -8
- package/dist/esm/tools/base/BaseTool.d.ts +1 -13
- package/dist/esm/tools/base/ContourSegmentationBaseTool.js +1 -1
- package/dist/esm/tools/displayTools/Contour/contourHandler/handleContourSegmentation.js +4 -4
- package/dist/esm/tools/displayTools/Contour/contourHandler/utils.js +1 -1
- package/dist/esm/tools/displayTools/Contour/removeContourFromElement.js +1 -1
- package/dist/esm/tools/segmentation/BrushTool.d.ts +38 -0
- package/dist/esm/tools/segmentation/BrushTool.js +40 -7
- package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +23 -15
- package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +6 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +10 -5
- package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.js +1 -1
- package/dist/esm/tools/segmentation/strategies/compositions/preview.js +2 -2
- package/dist/esm/tools/segmentation/strategies/compositions/setValue.js +6 -4
- package/dist/esm/tools/segmentation/strategies/fillSphere.js +5 -14
- package/dist/esm/types/EventTypes.d.ts +1 -2
- package/dist/esm/types/IBaseTool.d.ts +2 -0
- package/dist/esm/types/IBaseTool.js +1 -0
- package/dist/esm/types/IToolGroup.d.ts +3 -63
- package/dist/esm/types/LabelmapToolOperationData.d.ts +5 -0
- package/dist/esm/types/SegmentationStateTypes.d.ts +22 -22
- package/dist/esm/types/index.d.ts +3 -2
- package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js +3 -3
- package/dist/esm/utilities/contourSegmentation/removeContourSegmentationAnnotation.js +1 -1
- package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.js +7 -7
- package/dist/esm/utilities/segmentation/getHoveredContourSegmentationAnnotation.js +1 -1
- package/dist/esm/utilities/segmentation/getSegmentIndexAtLabelmapBorder.js +8 -4
- package/dist/esm/utilities/segmentation/getSegmentIndexAtWorldPoint.js +2 -2
- package/dist/esm/utilities/segmentation/getUniqueSegmentIndices.js +2 -2
- package/dist/esm/utilities/segmentation/isLineInSegment.js +3 -3
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +16 -7
- package/dist/esm/stateManagement/segmentation/addSegmentationRepresentation.d.ts +0 -3
|
@@ -10,10 +10,11 @@ import { drawCircle as drawCircleSvg } from '../../drawingSvg';
|
|
|
10
10
|
import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
|
|
11
11
|
import triggerAnnotationRenderForViewportUIDs from '../../utilities/triggerAnnotationRenderForViewportIds';
|
|
12
12
|
import { isVolumeSegmentation } from './strategies/utils/stackVolumeCheck';
|
|
13
|
-
import { getActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, getSegmentation, } from '../../stateManagement/segmentation/segmentationState';
|
|
13
|
+
import { getActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, getSegmentation, getStackSegmentationImageIdsForViewport, } from '../../stateManagement/segmentation/segmentationState';
|
|
14
14
|
import { getLockedSegmentIndices } from '../../stateManagement/segmentation/segmentLocking';
|
|
15
15
|
import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
|
|
16
16
|
import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
|
|
17
|
+
import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
17
18
|
class BrushTool extends BaseTool {
|
|
18
19
|
constructor(toolProps = {}, defaultToolProps = {
|
|
19
20
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
@@ -141,7 +142,6 @@ class BrushTool extends BaseTool {
|
|
|
141
142
|
const eventData = evt.detail;
|
|
142
143
|
const { element, currentPoints } = eventData;
|
|
143
144
|
const enabledElement = getEnabledElement(element);
|
|
144
|
-
const { renderingEngine } = enabledElement;
|
|
145
145
|
this.updateCursor(evt);
|
|
146
146
|
const { viewportIdsToRender } = this._hoverData;
|
|
147
147
|
triggerAnnotationRenderForViewportUIDs(viewportIdsToRender);
|
|
@@ -235,12 +235,45 @@ class BrushTool extends BaseTool {
|
|
|
235
235
|
return;
|
|
236
236
|
}
|
|
237
237
|
if (this.configuration.activeStrategy.includes('SPHERE')) {
|
|
238
|
-
|
|
238
|
+
const referencedImageIds = viewport.getImageIds();
|
|
239
|
+
const isValidVolumeForSphere = csUtils.isValidVolume(referencedImageIds);
|
|
240
|
+
if (!isValidVolumeForSphere) {
|
|
241
|
+
throw new Error('Volume is not reconstructable for sphere manipulation');
|
|
242
|
+
}
|
|
243
|
+
const labelmapImageIds = getStackSegmentationImageIdsForViewport(viewport.id, segmentationId);
|
|
244
|
+
if (!labelmapImageIds || labelmapImageIds.length === 1) {
|
|
245
|
+
return {
|
|
246
|
+
imageId: segmentationImageId,
|
|
247
|
+
segmentsLocked,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const tempVolumeId = 'tempVolumeId';
|
|
251
|
+
const { dimensions, direction, origin, spacing, numberOfComponents, imageIds: sortedLabelmapImageIds, } = csUtils.generateVolumePropsFromImageIds(labelmapImageIds, tempVolumeId);
|
|
252
|
+
const newVoxelManager = csUtils.VoxelManager.createImageVolumeVoxelManager({
|
|
253
|
+
dimensions,
|
|
254
|
+
imageIds: sortedLabelmapImageIds,
|
|
255
|
+
numberOfComponents,
|
|
256
|
+
});
|
|
257
|
+
const newImageData = vtkImageData.newInstance();
|
|
258
|
+
newImageData.setDimensions(dimensions);
|
|
259
|
+
newImageData.setSpacing(spacing);
|
|
260
|
+
newImageData.setDirection(direction);
|
|
261
|
+
newImageData.setOrigin(origin);
|
|
262
|
+
return {
|
|
263
|
+
imageId: segmentationImageId,
|
|
264
|
+
segmentsLocked,
|
|
265
|
+
override: {
|
|
266
|
+
voxelManager: newVoxelManager,
|
|
267
|
+
imageData: newImageData,
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
return {
|
|
273
|
+
imageId: segmentationImageId,
|
|
274
|
+
segmentsLocked,
|
|
275
|
+
};
|
|
239
276
|
}
|
|
240
|
-
return {
|
|
241
|
-
imageId: segmentationImageId,
|
|
242
|
-
segmentsLocked,
|
|
243
|
-
};
|
|
244
277
|
}
|
|
245
278
|
}
|
|
246
279
|
createHoverData(element, centerCanvas) {
|
|
@@ -171,30 +171,35 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
171
171
|
const canvasCorners = getCanvasCircleCorners(canvasCoordinates);
|
|
172
172
|
const focalPoint = viewport.getCamera().focalPoint;
|
|
173
173
|
const viewplaneNormal = viewport.getCamera().viewPlaneNormal;
|
|
174
|
-
let
|
|
175
|
-
let
|
|
174
|
+
let tempStartCoordinate = startCoordinate;
|
|
175
|
+
let tempEndCoordinate = endCoordinate;
|
|
176
176
|
if (Array.isArray(startCoordinate)) {
|
|
177
|
-
|
|
177
|
+
tempStartCoordinate = this._getCoordinateForViewplaneNormal(tempStartCoordinate, viewplaneNormal);
|
|
178
|
+
data.startCoordinate = tempStartCoordinate;
|
|
178
179
|
}
|
|
179
180
|
if (Array.isArray(endCoordinate)) {
|
|
180
|
-
|
|
181
|
+
tempEndCoordinate = this._getCoordinateForViewplaneNormal(tempEndCoordinate, viewplaneNormal);
|
|
182
|
+
data.endCoordinate = tempEndCoordinate;
|
|
181
183
|
}
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
187
|
-
|
|
184
|
+
const roundedStartCoordinate = coreUtils.roundToPrecision(data.startCoordinate);
|
|
185
|
+
const roundedEndCoordinate = coreUtils.roundToPrecision(data.endCoordinate);
|
|
186
|
+
const cameraCoordinate = this._getCoordinateForViewplaneNormal(focalPoint, viewplaneNormal);
|
|
187
|
+
const roundedCameraCoordinate = coreUtils.roundToPrecision(cameraCoordinate);
|
|
188
|
+
if (roundedCameraCoordinate <
|
|
189
|
+
Math.min(roundedStartCoordinate, roundedEndCoordinate) ||
|
|
190
|
+
roundedCameraCoordinate >
|
|
191
|
+
Math.max(roundedStartCoordinate, roundedEndCoordinate)) {
|
|
188
192
|
continue;
|
|
189
193
|
}
|
|
190
|
-
|
|
191
|
-
this._throttledCalculateCachedStats(annotation, enabledElement);
|
|
192
|
-
}
|
|
193
|
-
const middleCoord = coreUtils.roundToPrecision((startCoord + endCoord) / 2);
|
|
194
|
+
const middleCoordinate = coreUtils.roundToPrecision((data.startCoordinate + data.endCoordinate) / 2);
|
|
194
195
|
let isMiddleSlice = false;
|
|
195
|
-
if (
|
|
196
|
+
if (roundedCameraCoordinate === middleCoordinate) {
|
|
196
197
|
isMiddleSlice = true;
|
|
197
198
|
}
|
|
199
|
+
data.handles.points[0][this._getIndexOfCoordinatesForViewplaneNormal(viewplaneNormal)] = middleCoordinate;
|
|
200
|
+
if (annotation.invalidated) {
|
|
201
|
+
this._throttledCalculateCachedStats(annotation, enabledElement);
|
|
202
|
+
}
|
|
198
203
|
if (!viewport.getRenderingEngine()) {
|
|
199
204
|
console.warn('Rendering Engine has been destroyed');
|
|
200
205
|
return renderStatus;
|
|
@@ -420,6 +425,9 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
|
|
|
420
425
|
const targetId = this.getTargetId(viewport);
|
|
421
426
|
const imageVolume = cache.getVolume(targetId.split(/volumeId:|\?/)[1]);
|
|
422
427
|
this._computeProjectionPoints(annotation, imageVolume);
|
|
428
|
+
if (this.configuration.calculatePointsInsideVolume) {
|
|
429
|
+
this._computePointsInsideVolume(annotation, imageVolume, targetId, enabledElement);
|
|
430
|
+
}
|
|
423
431
|
annotation.invalidated = false;
|
|
424
432
|
triggerAnnotationModified(annotation, viewport.element);
|
|
425
433
|
return cachedStats;
|
|
@@ -172,9 +172,12 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
|
|
|
172
172
|
let endCoord = endCoordinate;
|
|
173
173
|
if (Array.isArray(startCoordinate)) {
|
|
174
174
|
startCoord = this._getCoordinateForViewplaneNormal(startCoord, viewplaneNormal);
|
|
175
|
+
data.startCoordinate = startCoord;
|
|
176
|
+
data.handles.points[0][this._getIndexOfCoordinatesForViewplaneNormal(viewplaneNormal)] = startCoord;
|
|
175
177
|
}
|
|
176
178
|
if (Array.isArray(endCoordinate)) {
|
|
177
179
|
endCoord = this._getCoordinateForViewplaneNormal(endCoord, viewplaneNormal);
|
|
180
|
+
data.endCoordinate = endCoord;
|
|
178
181
|
}
|
|
179
182
|
const roundedStartCoord = csUtils.roundToPrecision(startCoord);
|
|
180
183
|
const roundedEndCoord = csUtils.roundToPrecision(endCoord);
|
|
@@ -378,6 +381,9 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
|
|
|
378
381
|
const targetId = this.getTargetId(viewport);
|
|
379
382
|
const imageVolume = cache.getVolume(targetId.split(/volumeId:|\?/)[1]);
|
|
380
383
|
this._computeProjectionPoints(annotation, imageVolume);
|
|
384
|
+
if (this.configuration.calculatePointsInsideVolume) {
|
|
385
|
+
this._computePointsInsideVolume(annotation, targetId, imageVolume, enabledElement);
|
|
386
|
+
}
|
|
381
387
|
annotation.invalidated = false;
|
|
382
388
|
triggerAnnotationModified(annotation, viewport.element);
|
|
383
389
|
return cachedStats;
|
|
@@ -37,7 +37,8 @@ export default class BrushStrategy {
|
|
|
37
37
|
}
|
|
38
38
|
this._fill.forEach((func) => func(initializedData));
|
|
39
39
|
const { segmentationVoxelManager, previewVoxelManager, previewSegmentIndex, } = initializedData;
|
|
40
|
-
triggerSegmentationDataModified(initializedData.segmentationId, segmentationVoxelManager.
|
|
40
|
+
triggerSegmentationDataModified(initializedData.segmentationId, segmentationVoxelManager.getArrayOfModifiedSlices());
|
|
41
|
+
segmentationVoxelManager.resetModifiedSlices();
|
|
41
42
|
if (!previewSegmentIndex || !previewVoxelManager.modifiedSlices.size) {
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
@@ -69,7 +70,9 @@ export default class BrushStrategy {
|
|
|
69
70
|
BrushStrategy.childFunctions[key](this, result[key]);
|
|
70
71
|
}
|
|
71
72
|
});
|
|
72
|
-
this.strategyFunction = (enabledElement, operationData) =>
|
|
73
|
+
this.strategyFunction = (enabledElement, operationData) => {
|
|
74
|
+
return this.fill(enabledElement, operationData);
|
|
75
|
+
};
|
|
73
76
|
for (const key of Object.keys(BrushStrategy.childFunctions)) {
|
|
74
77
|
this.strategyFunction[key] = this[key];
|
|
75
78
|
}
|
|
@@ -82,9 +85,11 @@ export default class BrushStrategy {
|
|
|
82
85
|
return operationData.preview;
|
|
83
86
|
}
|
|
84
87
|
const { imageVoxelManager, segmentationVoxelManager, segmentationImageData, } = data;
|
|
88
|
+
const segmentationVoxelManagerToUse = operationData.override?.voxelManager || segmentationVoxelManager;
|
|
89
|
+
const segmentationImageDataToUse = operationData.override?.imageData || segmentationImageData;
|
|
85
90
|
const previewVoxelManager = operationData.preview?.previewVoxelManager ||
|
|
86
91
|
VoxelManager.createHistoryVoxelManager({
|
|
87
|
-
sourceVoxelManager:
|
|
92
|
+
sourceVoxelManager: segmentationVoxelManagerToUse,
|
|
88
93
|
});
|
|
89
94
|
const previewEnabled = !!operationData.previewColors;
|
|
90
95
|
const previewSegmentIndex = previewEnabled ? 255 : undefined;
|
|
@@ -94,8 +99,8 @@ export default class BrushStrategy {
|
|
|
94
99
|
...operationData,
|
|
95
100
|
enabledElement,
|
|
96
101
|
imageVoxelManager,
|
|
97
|
-
segmentationVoxelManager,
|
|
98
|
-
segmentationImageData,
|
|
102
|
+
segmentationVoxelManager: segmentationVoxelManagerToUse,
|
|
103
|
+
segmentationImageData: segmentationImageDataToUse,
|
|
99
104
|
previewVoxelManager,
|
|
100
105
|
viewport,
|
|
101
106
|
centerWorld: null,
|
|
@@ -118,6 +118,6 @@ export default {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
triggerSegmentationDataModified(operationData.segmentationId, previewVoxelManager.
|
|
121
|
+
triggerSegmentationDataModified(operationData.segmentationId, previewVoxelManager.getArrayOfModifiedSlices());
|
|
122
122
|
},
|
|
123
123
|
};
|
|
@@ -66,7 +66,7 @@ export default {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
tracking.forEach(callback, {});
|
|
69
|
-
triggerSegmentationDataModified(operationData.segmentationId, tracking.
|
|
69
|
+
triggerSegmentationDataModified(operationData.segmentationId, tracking.getArrayOfModifiedSlices());
|
|
70
70
|
tracking.clear();
|
|
71
71
|
},
|
|
72
72
|
[StrategyCallbacks.RejectPreview]: (operationData) => {
|
|
@@ -78,7 +78,7 @@ export default {
|
|
|
78
78
|
segmentationVoxelManager.setAtIndex(index, value);
|
|
79
79
|
};
|
|
80
80
|
previewVoxelManager.forEach(callback);
|
|
81
|
-
triggerSegmentationDataModified(operationData.segmentationId, previewVoxelManager.
|
|
81
|
+
triggerSegmentationDataModified(operationData.segmentationId, previewVoxelManager.getArrayOfModifiedSlices());
|
|
82
82
|
previewVoxelManager.clear();
|
|
83
83
|
},
|
|
84
84
|
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
|
|
2
|
+
import { triggerEvent, eventTarget } from '@cornerstonejs/core';
|
|
2
3
|
export default {
|
|
3
4
|
[StrategyCallbacks.INTERNAL_setValue]: (operationData, { value, index }) => {
|
|
4
|
-
const { segmentsLocked, segmentIndex, previewVoxelManager, previewSegmentIndex, segmentationVoxelManager, } = operationData;
|
|
5
|
+
const { segmentsLocked, segmentIndex, previewVoxelManager, previewSegmentIndex, segmentationVoxelManager, segmentationId, } = operationData;
|
|
5
6
|
const existingValue = segmentationVoxelManager.getAtIndex(index);
|
|
7
|
+
let changed = false;
|
|
6
8
|
if (segmentIndex === null) {
|
|
7
9
|
const oldValue = previewVoxelManager.getAtIndex(index);
|
|
8
10
|
if (oldValue !== undefined) {
|
|
9
|
-
previewVoxelManager.setAtIndex(index, oldValue);
|
|
11
|
+
changed = previewVoxelManager.setAtIndex(index, oldValue);
|
|
10
12
|
}
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
@@ -15,13 +17,13 @@ export default {
|
|
|
15
17
|
}
|
|
16
18
|
if (existingValue === previewSegmentIndex) {
|
|
17
19
|
if (previewVoxelManager.getAtIndex(index) === undefined) {
|
|
18
|
-
segmentationVoxelManager.setAtIndex(index, segmentIndex);
|
|
20
|
+
changed = segmentationVoxelManager.setAtIndex(index, segmentIndex);
|
|
19
21
|
}
|
|
20
22
|
else {
|
|
21
23
|
return;
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
const useSegmentIndex = previewSegmentIndex ?? segmentIndex;
|
|
25
|
-
previewVoxelManager.setAtIndex(index, useSegmentIndex);
|
|
27
|
+
changed = previewVoxelManager.setAtIndex(index, useSegmentIndex);
|
|
26
28
|
},
|
|
27
29
|
};
|
|
@@ -21,20 +21,11 @@ const sphereComposition = {
|
|
|
21
21
|
operationData.centerIJK = transformWorldToIndex(segmentationImageData, center);
|
|
22
22
|
const { boundsIJK: newBoundsIJK, topLeftWorld, bottomRightWorld, } = getSphereBoundsInfo(points.slice(0, 2), segmentationImageData, viewport);
|
|
23
23
|
segmentationVoxelManager.boundsIJK = newBoundsIJK;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
segmentationVoxelManager.isInObject = createEllipseInPoint({
|
|
33
|
-
topLeftWorld,
|
|
34
|
-
bottomRightWorld,
|
|
35
|
-
center,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
24
|
+
segmentationVoxelManager.isInObject = createEllipseInPoint({
|
|
25
|
+
topLeftWorld,
|
|
26
|
+
bottomRightWorld,
|
|
27
|
+
center,
|
|
28
|
+
});
|
|
38
29
|
},
|
|
39
30
|
};
|
|
40
31
|
const SPHERE_STRATEGY = new BrushStrategy('Sphere', compositions.regionFill, compositions.setValue, sphereComposition, compositions.determineSegmentIndex, compositions.preview);
|
|
@@ -5,9 +5,8 @@ import type ITouchPoints from './ITouchPoints';
|
|
|
5
5
|
import type IDistance from './IDistance';
|
|
6
6
|
import type { SetToolBindingsType } from './ISetToolModeOptions';
|
|
7
7
|
import type { Swipe } from '../enums/Touch';
|
|
8
|
-
import type { ToolModes } from '../enums';
|
|
8
|
+
import type { ToolModes, ChangeTypes } from '../enums';
|
|
9
9
|
import type { InterpolationROIAnnotation } from './ToolSpecificAnnotationTypes';
|
|
10
|
-
import type { ChangeTypes } from '../enums';
|
|
11
10
|
type NormalizedInteractionEventDetail = {
|
|
12
11
|
eventName: string;
|
|
13
12
|
renderingEngineId: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,63 +1,3 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import type { ToolConfiguration } from '../types';
|
|
5
|
-
export default interface IToolGroup {
|
|
6
|
-
_toolInstances: Record<string, unknown>;
|
|
7
|
-
id: string;
|
|
8
|
-
viewportsInfo: Array<Types.IViewportId>;
|
|
9
|
-
toolOptions: Record<string, unknown>;
|
|
10
|
-
getViewportIds: () => string[];
|
|
11
|
-
getViewportsInfo: () => Array<Types.IViewportId>;
|
|
12
|
-
getToolInstance: {
|
|
13
|
-
(toolName: string): unknown;
|
|
14
|
-
};
|
|
15
|
-
hasTool(toolName: string): boolean;
|
|
16
|
-
addTool: {
|
|
17
|
-
(toolName: string, toolConfiguration?: ToolConfiguration): void;
|
|
18
|
-
};
|
|
19
|
-
addToolInstance: {
|
|
20
|
-
(toolName: string, parentClassName: string, configuration?: unknown): void;
|
|
21
|
-
};
|
|
22
|
-
addViewport: {
|
|
23
|
-
(viewportId: string, renderingEngineId?: string): void;
|
|
24
|
-
};
|
|
25
|
-
removeViewports: {
|
|
26
|
-
(renderingEngineId: string, viewportId?: string): void;
|
|
27
|
-
};
|
|
28
|
-
setToolActive: {
|
|
29
|
-
(toolName: string, toolBindingsOption?: SetToolBindingsType): void;
|
|
30
|
-
};
|
|
31
|
-
setToolPassive: {
|
|
32
|
-
(toolName: string, options?: {
|
|
33
|
-
removeAllBindings?: boolean | IToolBinding[];
|
|
34
|
-
}): void;
|
|
35
|
-
};
|
|
36
|
-
setToolEnabled: {
|
|
37
|
-
(toolName: string): void;
|
|
38
|
-
};
|
|
39
|
-
setToolDisabled: {
|
|
40
|
-
(toolName: string): void;
|
|
41
|
-
};
|
|
42
|
-
getToolOptions: {
|
|
43
|
-
(toolName: string): ToolOptionsType;
|
|
44
|
-
};
|
|
45
|
-
getActivePrimaryMouseButtonTool: {
|
|
46
|
-
(): undefined | string;
|
|
47
|
-
};
|
|
48
|
-
setViewportsCursorByToolName: {
|
|
49
|
-
(toolName: string, strategyName?: string): void;
|
|
50
|
-
};
|
|
51
|
-
setToolConfiguration: {
|
|
52
|
-
(toolName: string, configuration: ToolConfiguration, overwrite?: boolean): void;
|
|
53
|
-
};
|
|
54
|
-
getToolConfiguration: {
|
|
55
|
-
(toolName: string, configurationPath?: string): unknown;
|
|
56
|
-
};
|
|
57
|
-
getDefaultMousePrimary: {
|
|
58
|
-
(): MouseBindings;
|
|
59
|
-
};
|
|
60
|
-
clone: {
|
|
61
|
-
(newToolGroupId: string, fnToolFilter: (toolName: string) => boolean): IToolGroup;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
1
|
+
import type ToolGroup from '../store/ToolGroupManager/ToolGroup';
|
|
2
|
+
type IToolGroup = ToolGroup;
|
|
3
|
+
export type { IToolGroup as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import type { LabelmapSegmentationDataStack, LabelmapSegmentationDataVolume } from './LabelmapTypes';
|
|
3
|
+
import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
3
4
|
type LabelmapToolOperationData = {
|
|
4
5
|
segmentationId: string;
|
|
5
6
|
segmentIndex: number;
|
|
@@ -11,6 +12,10 @@ type LabelmapToolOperationData = {
|
|
|
11
12
|
segmentationRepresentationUID: string;
|
|
12
13
|
points: Types.Point3[];
|
|
13
14
|
voxelManager: any;
|
|
15
|
+
override: {
|
|
16
|
+
voxelManager: Types.IVoxelManager<number>;
|
|
17
|
+
imageData: vtkImageData;
|
|
18
|
+
};
|
|
14
19
|
preview: any;
|
|
15
20
|
toolGroupId: string;
|
|
16
21
|
};
|
|
@@ -3,24 +3,23 @@ import type * as Enums from '../enums';
|
|
|
3
3
|
import type { ContourConfig, ContourRenderingConfig, ContourSegmentationData } from './ContourTypes';
|
|
4
4
|
import type { LabelmapConfig, LabelmapRenderingConfig, LabelmapSegmentationData } from './LabelmapTypes';
|
|
5
5
|
import type { SurfaceSegmentationData, SurfaceRenderingConfig } from './SurfaceTypes';
|
|
6
|
-
export type SegmentRepresentationConfig = {
|
|
7
|
-
[key: number | string]: RepresentationConfig;
|
|
8
|
-
};
|
|
9
6
|
export type SurfaceConfig = {};
|
|
10
|
-
export type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
export type RepresentationsConfig = {
|
|
8
|
+
[Enums.SegmentationRepresentations.Labelmap]?: LabelmapConfig;
|
|
9
|
+
[Enums.SegmentationRepresentations.Contour]?: ContourConfig;
|
|
10
|
+
[Enums.SegmentationRepresentations.Surface]?: SurfaceConfig;
|
|
14
11
|
};
|
|
15
|
-
export type
|
|
12
|
+
export type RepresentationConfig = LabelmapConfig | ContourConfig | SurfaceConfig;
|
|
13
|
+
export type GlobalConfig = {
|
|
16
14
|
renderInactiveRepresentations: boolean;
|
|
17
|
-
representations:
|
|
15
|
+
representations: RepresentationsConfig;
|
|
18
16
|
};
|
|
19
|
-
export type
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export type RepresentationsData = {
|
|
18
|
+
[Enums.SegmentationRepresentations.Labelmap]?: LabelmapSegmentationData;
|
|
19
|
+
[Enums.SegmentationRepresentations.Contour]?: ContourSegmentationData;
|
|
20
|
+
[Enums.SegmentationRepresentations.Surface]?: SurfaceSegmentationData;
|
|
23
21
|
};
|
|
22
|
+
export type RepresentationData = LabelmapSegmentationData | ContourSegmentationData | SurfaceSegmentationData;
|
|
24
23
|
export type Segmentation = {
|
|
25
24
|
segmentationId: string;
|
|
26
25
|
type: Enums.SegmentationRepresentations;
|
|
@@ -33,7 +32,7 @@ export type Segmentation = {
|
|
|
33
32
|
segmentLabels: {
|
|
34
33
|
[key: string]: string;
|
|
35
34
|
};
|
|
36
|
-
representationData:
|
|
35
|
+
representationData: RepresentationsData;
|
|
37
36
|
};
|
|
38
37
|
export type BaseSegmentationRepresentation = {
|
|
39
38
|
segmentationRepresentationUID: string;
|
|
@@ -46,7 +45,7 @@ export type BaseSegmentationRepresentation = {
|
|
|
46
45
|
};
|
|
47
46
|
config: {
|
|
48
47
|
allSegments?: RepresentationConfig;
|
|
49
|
-
perSegment?:
|
|
48
|
+
perSegment?: RepresentationConfig;
|
|
50
49
|
};
|
|
51
50
|
};
|
|
52
51
|
export type LabelmapRepresentation = BaseSegmentationRepresentation & {
|
|
@@ -62,7 +61,7 @@ export type SegmentationRepresentation = LabelmapRepresentation | ContourReprese
|
|
|
62
61
|
export type SegmentationState = {
|
|
63
62
|
colorLUT: Types.ColorLUT[];
|
|
64
63
|
segmentations: Segmentation[];
|
|
65
|
-
globalConfig:
|
|
64
|
+
globalConfig: GlobalConfig;
|
|
66
65
|
representations: {
|
|
67
66
|
[key: string]: SegmentationRepresentation;
|
|
68
67
|
};
|
|
@@ -80,14 +79,9 @@ export type SegmentationPublicInput = {
|
|
|
80
79
|
segmentationId: string;
|
|
81
80
|
representation: {
|
|
82
81
|
type: Enums.SegmentationRepresentations;
|
|
83
|
-
data?:
|
|
82
|
+
data?: RepresentationData;
|
|
84
83
|
};
|
|
85
84
|
};
|
|
86
|
-
export type RepresentationPublicInput = {
|
|
87
|
-
segmentationId: string;
|
|
88
|
-
type: Enums.SegmentationRepresentations;
|
|
89
|
-
options?: RepresentationPublicInputOptions;
|
|
90
|
-
};
|
|
91
85
|
export type RepresentationPublicInputOptions = {
|
|
92
86
|
segmentationRepresentationUID?: string;
|
|
93
87
|
colorLUTOrIndex?: Types.ColorLUT | number;
|
|
@@ -96,3 +90,9 @@ export type RepresentationPublicInputOptions = {
|
|
|
96
90
|
options?: unknown;
|
|
97
91
|
};
|
|
98
92
|
};
|
|
93
|
+
export type RepresentationPublicInput = {
|
|
94
|
+
segmentationId: string;
|
|
95
|
+
type: Enums.SegmentationRepresentations;
|
|
96
|
+
options?: RepresentationPublicInputOptions;
|
|
97
|
+
config?: RepresentationConfig;
|
|
98
|
+
};
|
|
@@ -22,7 +22,7 @@ import type ScrollOptions from './ScrollOptions';
|
|
|
22
22
|
import type BoundsIJK from './BoundsIJK';
|
|
23
23
|
import type SVGDrawingHelper from './SVGDrawingHelper';
|
|
24
24
|
import type * as CINETypes from './CINETypes';
|
|
25
|
-
import type { RepresentationConfig,
|
|
25
|
+
import type { RepresentationConfig, RepresentationData, RepresentationsData, GlobalConfig, Segmentation, SegmentationState, RepresentationPublicInput } from './SegmentationStateTypes';
|
|
26
26
|
import type { ISculptToolShape } from './ISculptToolShape';
|
|
27
27
|
import type ISynchronizerEventHandler from './ISynchronizerEventHandler';
|
|
28
28
|
import type { FloodFillGetter, FloodFillOptions, FloodFillResult } from './FloodFillTypes';
|
|
@@ -46,4 +46,5 @@ import type { SplineLineSegment } from './SplineLineSegment';
|
|
|
46
46
|
import type { SplineProps } from './SplineProps';
|
|
47
47
|
import type { BidirectionalData } from '../utilities/segmentation/createBidirectionalToolData';
|
|
48
48
|
import type { PolySegConversionOptions } from './PolySeg';
|
|
49
|
-
|
|
49
|
+
import type { IBaseTool } from './IBaseTool';
|
|
50
|
+
export type { Annotation, Annotations, ContourAnnotationData, ContourAnnotation, ContourSegmentationAnnotationData, ContourSegmentationAnnotation, BidirectionalData, CanvasCoordinates, IAnnotationManager, InterpolationViewportData, ImageInterpolationData, GroupSpecificAnnotations, AnnotationState, AnnotationStyle, ToolSpecificAnnotationTypes, JumpToSliceOptions, AnnotationGroupSelector, AnnotationRenderContext, PlanarBoundingBox, ToolProps, PublicToolProps, ToolConfiguration, EventTypes, IPoints, ITouchPoints, IDistance, IToolBinding, SetToolBindingsType, ToolOptionsType, InteractionTypes, ToolAction, IToolGroup, IToolClassReference, ISynchronizerEventHandler, ToolHandle, AnnotationHandle, TextBoxHandle, Segmentation, SegmentationState, RepresentationData, RepresentationsData, RepresentationConfig, RepresentationPublicInput, LabelmapTypes, SVGCursorDescriptor, SVGPoint, ScrollOptions, CINETypes, BoundsIJK, SVGDrawingHelper, FloodFillResult, FloodFillGetter, FloodFillOptions, ContourSegmentationData, ISculptToolShape, Statistics, NamedStatistics, LabelmapToolOperationData, LabelmapToolOperationDataStack, LabelmapToolOperationDataVolume, CardinalSplineProps, ClosestControlPoint, ClosestPoint, ClosestSplinePoint, ControlPointInfo, ISpline, SplineCurveSegment, SplineLineSegment, SplineProps, PolySegConversionOptions, IBaseTool, GlobalConfig, };
|
|
@@ -8,10 +8,10 @@ export function addContourSegmentationAnnotation(annotation) {
|
|
|
8
8
|
}
|
|
9
9
|
const { segmentationId, segmentIndex } = annotation.data.segmentation;
|
|
10
10
|
const segmentation = getSegmentation(segmentationId);
|
|
11
|
-
if (!segmentation.representationData.
|
|
12
|
-
segmentation.representationData.
|
|
11
|
+
if (!segmentation.representationData.Contour) {
|
|
12
|
+
segmentation.representationData.Contour = { annotationUIDsMap: new Map() };
|
|
13
13
|
}
|
|
14
|
-
const { annotationUIDsMap } = segmentation.representationData.
|
|
14
|
+
const { annotationUIDsMap } = segmentation.representationData.Contour;
|
|
15
15
|
let annotationsUIDsSet = annotationUIDsMap.get(segmentIndex);
|
|
16
16
|
if (!annotationsUIDsSet) {
|
|
17
17
|
annotationsUIDsSet = new Set();
|
|
@@ -5,7 +5,7 @@ export function removeContourSegmentationAnnotation(annotation) {
|
|
|
5
5
|
}
|
|
6
6
|
const { segmentationId, segmentIndex } = annotation.data.segmentation;
|
|
7
7
|
const segmentation = getSegmentation(segmentationId);
|
|
8
|
-
const { annotationUIDsMap } = segmentation?.representationData.
|
|
8
|
+
const { annotationUIDsMap } = segmentation?.representationData.Contour || {};
|
|
9
9
|
const annotationsUIDsSet = annotationUIDsMap?.get(segmentIndex);
|
|
10
10
|
if (!annotationsUIDsSet) {
|
|
11
11
|
return;
|
|
@@ -15,13 +15,13 @@ function generateContourSetsFromLabelmap({ segmentations }) {
|
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
const numSlices = vol.dimensions[2];
|
|
18
|
-
const
|
|
18
|
+
const voxelManager = vol.voxelManager;
|
|
19
19
|
const pixelsPerSlice = vol.dimensions[0] * vol.dimensions[1];
|
|
20
20
|
for (let z = 0; z < numSlices; z++) {
|
|
21
21
|
for (let y = 0; y < vol.dimensions[1]; y++) {
|
|
22
22
|
const index = y * vol.dimensions[0] + z * pixelsPerSlice;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
voxelManager.setAtIndex(index, 0);
|
|
24
|
+
voxelManager.setAtIndex(index + vol.dimensions[0] - 1, 0);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
const ContourSets = [];
|
|
@@ -41,13 +41,13 @@ function generateContourSetsFromLabelmap({ segmentations }) {
|
|
|
41
41
|
});
|
|
42
42
|
const { containedSegmentIndices } = segment;
|
|
43
43
|
for (let sliceIndex = 0; sliceIndex < numSlices; sliceIndex++) {
|
|
44
|
-
if (isSliceEmptyForSegment(sliceIndex,
|
|
44
|
+
if (isSliceEmptyForSegment(sliceIndex, voxelManager, pixelsPerSlice, segIndex)) {
|
|
45
45
|
continue;
|
|
46
46
|
}
|
|
47
47
|
const frameStart = sliceIndex * pixelsPerSlice;
|
|
48
48
|
try {
|
|
49
49
|
for (let i = 0; i < pixelsPerSlice; i++) {
|
|
50
|
-
const value =
|
|
50
|
+
const value = voxelManager.getAtIndex(i + frameStart);
|
|
51
51
|
if (value === segIndex || containedSegmentIndices?.has(value)) {
|
|
52
52
|
scalars.setValue(i + frameStart, 1);
|
|
53
53
|
}
|
|
@@ -96,11 +96,11 @@ function generateContourSetsFromLabelmap({ segmentations }) {
|
|
|
96
96
|
}
|
|
97
97
|
return ContourSets;
|
|
98
98
|
}
|
|
99
|
-
function isSliceEmptyForSegment(sliceIndex,
|
|
99
|
+
function isSliceEmptyForSegment(sliceIndex, voxelManager, pixelsPerSlice, segIndex) {
|
|
100
100
|
const startIdx = sliceIndex * pixelsPerSlice;
|
|
101
101
|
const endIdx = startIdx + pixelsPerSlice;
|
|
102
102
|
for (let i = startIdx; i < endIdx; i++) {
|
|
103
|
-
if (
|
|
103
|
+
if (voxelManager.getAtIndex(i) === segIndex) {
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -2,7 +2,7 @@ import { getAnnotation } from '../../stateManagement';
|
|
|
2
2
|
import { getSegmentation } from '../../stateManagement/segmentation/segmentationState';
|
|
3
3
|
export function getHoveredContourSegmentationAnnotation(segmentationId) {
|
|
4
4
|
const segmentation = getSegmentation(segmentationId);
|
|
5
|
-
const { annotationUIDsMap } = segmentation.representationData.
|
|
5
|
+
const { annotationUIDsMap } = segmentation.representationData.Contour;
|
|
6
6
|
for (const [segmentIndex, annotationUIDs] of annotationUIDsMap.entries()) {
|
|
7
7
|
const highlightedAnnotationUID = Array.from(annotationUIDs).find((annotationUID) => getAnnotation(annotationUID).highlighted);
|
|
8
8
|
if (highlightedAnnotationUID) {
|
|
@@ -3,15 +3,17 @@ import { getSegmentation, getSegmentationRepresentationsForSegmentation, getCurr
|
|
|
3
3
|
import { isVolumeSegmentation } from '../../tools/segmentation/strategies/utils/stackVolumeCheck';
|
|
4
4
|
export function getSegmentIndexAtLabelmapBorder(segmentationId, worldPoint, { viewport, searchRadius }) {
|
|
5
5
|
const segmentation = getSegmentation(segmentationId);
|
|
6
|
-
const labelmapData = segmentation.representationData.
|
|
7
|
-
if (isVolumeSegmentation(labelmapData)) {
|
|
6
|
+
const labelmapData = segmentation.representationData.Labelmap;
|
|
7
|
+
if (isVolumeSegmentation(labelmapData, viewport)) {
|
|
8
8
|
const { volumeId } = labelmapData;
|
|
9
9
|
const segmentationVolume = cache.getVolume(volumeId);
|
|
10
10
|
if (!segmentationVolume) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
+
const voxelManager = segmentationVolume.voxelManager;
|
|
13
14
|
const imageData = segmentationVolume.imageData;
|
|
14
|
-
const
|
|
15
|
+
const indexIJK = utilities.transformWorldToIndex(imageData, worldPoint);
|
|
16
|
+
const segmentIndex = voxelManager.getAtIJK(indexIJK[0], indexIJK[1], indexIJK[2]);
|
|
15
17
|
const canvasPoint = viewport.worldToCanvas(worldPoint);
|
|
16
18
|
const onEdge = isSegmentOnEdgeCanvas(canvasPoint, segmentIndex, viewport, imageData, searchRadius);
|
|
17
19
|
return onEdge ? segmentIndex : undefined;
|
|
@@ -69,7 +71,9 @@ function isSegmentOnEdgeCanvas(canvasPoint, segmentIndex, viewport, imageData, s
|
|
|
69
71
|
const getNeighborIndex = (deltaI, deltaJ) => {
|
|
70
72
|
const neighborCanvas = [canvasPoint[0] + deltaI, canvasPoint[1] + deltaJ];
|
|
71
73
|
const worldPoint = viewport.canvasToWorld(neighborCanvas);
|
|
72
|
-
|
|
74
|
+
const voxelManager = imageData.get('voxelManager').voxelManager;
|
|
75
|
+
const indexIJK = utilities.transformWorldToIndex(imageData, worldPoint);
|
|
76
|
+
return voxelManager.getAtIJK(indexIJK[0], indexIJK[1], indexIJK[2]);
|
|
73
77
|
};
|
|
74
78
|
return isSegmentOnEdge(getNeighborIndex, segmentIndex, searchRadius);
|
|
75
79
|
}
|
|
@@ -21,7 +21,7 @@ export function getSegmentIndexAtWorldPoint(segmentationId, worldPoint, options
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
export function getSegmentIndexAtWorldForLabelmap(segmentation, worldPoint, { viewport }) {
|
|
24
|
-
const labelmapData = segmentation.representationData.
|
|
24
|
+
const labelmapData = segmentation.representationData.Labelmap;
|
|
25
25
|
if (isVolumeSegmentation(labelmapData)) {
|
|
26
26
|
const { volumeId } = labelmapData;
|
|
27
27
|
const segmentationVolume = cache.getVolume(volumeId);
|
|
@@ -51,7 +51,7 @@ export function getSegmentIndexAtWorldForLabelmap(segmentation, worldPoint, { vi
|
|
|
51
51
|
return segmentIndex;
|
|
52
52
|
}
|
|
53
53
|
export function getSegmentIndexAtWorldForContour(segmentation, worldPoint, { viewport }) {
|
|
54
|
-
const contourData = segmentation.representationData.
|
|
54
|
+
const contourData = segmentation.representationData.Contour;
|
|
55
55
|
const segmentIndices = Array.from(contourData.annotationUIDsMap.keys());
|
|
56
56
|
const { viewPlaneNormal } = viewport.getCamera();
|
|
57
57
|
for (const segmentIndex of segmentIndices) {
|