@cornerstonejs/tools 2.7.4 → 2.8.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.
Files changed (59) hide show
  1. package/dist/esm/enums/ChangeTypes.d.ts +2 -1
  2. package/dist/esm/enums/ChangeTypes.js +1 -0
  3. package/dist/esm/store/filterToolsWithAnnotationsForElement.js +1 -1
  4. package/dist/esm/tools/AnnotationEraserTool.js +8 -4
  5. package/dist/esm/tools/CrosshairsTool.js +1 -1
  6. package/dist/esm/tools/PanTool.d.ts +0 -1
  7. package/dist/esm/tools/PanTool.js +0 -5
  8. package/dist/esm/tools/ZoomTool.js +0 -2
  9. package/dist/esm/tools/annotation/ArrowAnnotateTool.js +4 -1
  10. package/dist/esm/tools/annotation/BidirectionalTool.js +6 -5
  11. package/dist/esm/tools/annotation/CircleROITool.js +6 -3
  12. package/dist/esm/tools/annotation/CobbAngleTool.d.ts +2 -2
  13. package/dist/esm/tools/annotation/CobbAngleTool.js +19 -19
  14. package/dist/esm/tools/annotation/EllipticalROITool.js +6 -6
  15. package/dist/esm/tools/annotation/KeyImageTool.d.ts +1 -2
  16. package/dist/esm/tools/annotation/KeyImageTool.js +5 -1
  17. package/dist/esm/tools/annotation/LengthTool.js +4 -1
  18. package/dist/esm/tools/annotation/LivewireContourTool.js +9 -5
  19. package/dist/esm/tools/annotation/ProbeTool.js +6 -5
  20. package/dist/esm/tools/annotation/RectangleROITool.js +3 -2
  21. package/dist/esm/tools/annotation/SplineROITool.js +4 -4
  22. package/dist/esm/tools/annotation/VideoRedactionTool.d.ts +2 -2
  23. package/dist/esm/tools/annotation/VideoRedactionTool.js +27 -29
  24. package/dist/esm/tools/annotation/planarFreehandROITool/closedContourEditLoop.js +7 -3
  25. package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js +6 -2
  26. package/dist/esm/tools/annotation/planarFreehandROITool/openContourEditLoop.js +6 -2
  27. package/dist/esm/tools/base/AnnotationDisplayTool.d.ts +1 -1
  28. package/dist/esm/tools/base/AnnotationDisplayTool.js +2 -2
  29. package/dist/esm/tools/base/AnnotationTool.d.ts +30 -0
  30. package/dist/esm/tools/base/AnnotationTool.js +85 -1
  31. package/dist/esm/tools/base/BaseTool.d.ts +1 -0
  32. package/dist/esm/tools/base/BaseTool.js +7 -1
  33. package/dist/esm/tools/base/ContourSegmentationBaseTool.js +0 -4
  34. package/dist/esm/tools/segmentation/BrushTool.js +1 -0
  35. package/dist/esm/tools/segmentation/CircleScissorsTool.d.ts +4 -2
  36. package/dist/esm/tools/segmentation/CircleScissorsTool.js +4 -1
  37. package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +6 -1
  38. package/dist/esm/tools/segmentation/LabelmapBaseTool.js +6 -1
  39. package/dist/esm/tools/segmentation/PaintFillTool.js +1 -1
  40. package/dist/esm/tools/segmentation/RectangleScissorsTool.d.ts +2 -2
  41. package/dist/esm/tools/segmentation/RectangleScissorsTool.js +6 -2
  42. package/dist/esm/tools/segmentation/SphereScissorsTool.d.ts +2 -2
  43. package/dist/esm/tools/segmentation/SphereScissorsTool.js +5 -1
  44. package/dist/esm/tools/segmentation/strategies/BrushStrategy.d.ts +2 -0
  45. package/dist/esm/tools/segmentation/strategies/compositions/preview.js +15 -13
  46. package/dist/esm/tools/segmentation/strategies/compositions/setValue.js +2 -1
  47. package/dist/esm/tools/segmentation/strategies/fillRectangle.d.ts +6 -8
  48. package/dist/esm/tools/segmentation/strategies/fillRectangle.js +29 -30
  49. package/dist/esm/tools/segmentation/strategies/index.d.ts +2 -2
  50. package/dist/esm/tools/segmentation/strategies/index.js +2 -2
  51. package/dist/esm/types/ContourAnnotation.d.ts +2 -0
  52. package/dist/esm/types/LabelmapToolOperationData.d.ts +2 -0
  53. package/dist/esm/utilities/math/polyline/planarFreehandROIInternalTypes.d.ts +1 -0
  54. package/dist/esm/utilities/planar/filterAnnotationsWithinSlice.js +4 -0
  55. package/dist/esm/utilities/segmentation/createLabelmapMemo.d.ts +44 -0
  56. package/dist/esm/utilities/segmentation/createLabelmapMemo.js +68 -0
  57. package/dist/esm/utilities/segmentation/index.d.ts +2 -1
  58. package/dist/esm/utilities/segmentation/index.js +2 -1
  59. package/package.json +3 -3
@@ -138,7 +138,7 @@ class VideoRedactionTool extends AnnotationTool {
138
138
  triggerAnnotationRenderForViewportIds(viewportUIDsToRender);
139
139
  evt.preventDefault();
140
140
  };
141
- this._mouseUpCallback = (evt) => {
141
+ this._endCallback = (evt) => {
142
142
  const eventData = evt.detail;
143
143
  const { element } = eventData;
144
144
  const { annotation, viewportUIDsToRender, newAnnotation, hasMoved } = this.editData;
@@ -146,12 +146,12 @@ class VideoRedactionTool extends AnnotationTool {
146
146
  if (newAnnotation && !hasMoved) {
147
147
  return;
148
148
  }
149
+ this.doneEditMemo();
149
150
  data.active = false;
150
151
  data.handles.activeHandleIndex = null;
151
152
  this._deactivateModify(element);
152
153
  this._deactivateDraw(element);
153
154
  resetElementCursor(element);
154
- const enabledElement = getEnabledElement(element);
155
155
  this.editData = null;
156
156
  this.isDrawing = false;
157
157
  if (this.isHandleOutsideImage &&
@@ -160,11 +160,12 @@ class VideoRedactionTool extends AnnotationTool {
160
160
  }
161
161
  triggerAnnotationRenderForViewportIds(viewportUIDsToRender);
162
162
  };
163
- this._mouseDragCallback = (evt) => {
163
+ this._dragCallback = (evt) => {
164
164
  this.isDrawing = true;
165
165
  const eventData = evt.detail;
166
166
  const { element } = eventData;
167
- const { annotation, viewportUIDsToRender, handleIndex } = this.editData;
167
+ const { annotation, viewportUIDsToRender, handleIndex, newAnnotation } = this.editData;
168
+ this.createMemo(element, annotation, { newAnnotation });
168
169
  const { data } = annotation;
169
170
  if (handleIndex === undefined) {
170
171
  const { deltaPoints } = eventData;
@@ -230,37 +231,37 @@ class VideoRedactionTool extends AnnotationTool {
230
231
  };
231
232
  this._activateDraw = (element) => {
232
233
  state.isInteractingWithTool = true;
233
- element.addEventListener(Events.MOUSE_UP, this._mouseUpCallback);
234
- element.addEventListener(Events.MOUSE_DRAG, this._mouseDragCallback);
235
- element.addEventListener(Events.MOUSE_MOVE, this._mouseDragCallback);
236
- element.addEventListener(Events.MOUSE_CLICK, this._mouseUpCallback);
237
- element.addEventListener(Events.TOUCH_END, this._mouseUpCallback);
238
- element.addEventListener(Events.TOUCH_DRAG, this._mouseDragCallback);
234
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
235
+ element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
236
+ element.addEventListener(Events.MOUSE_MOVE, this._dragCallback);
237
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
238
+ element.addEventListener(Events.TOUCH_END, this._endCallback);
239
+ element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
239
240
  };
240
241
  this._deactivateDraw = (element) => {
241
242
  state.isInteractingWithTool = false;
242
- element.removeEventListener(Events.MOUSE_UP, this._mouseUpCallback);
243
- element.removeEventListener(Events.MOUSE_DRAG, this._mouseDragCallback);
244
- element.removeEventListener(Events.MOUSE_MOVE, this._mouseDragCallback);
245
- element.removeEventListener(Events.MOUSE_CLICK, this._mouseUpCallback);
246
- element.removeEventListener(Events.TOUCH_END, this._mouseUpCallback);
247
- element.removeEventListener(Events.TOUCH_DRAG, this._mouseDragCallback);
243
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
244
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
245
+ element.removeEventListener(Events.MOUSE_MOVE, this._dragCallback);
246
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
247
+ element.removeEventListener(Events.TOUCH_END, this._endCallback);
248
+ element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
248
249
  };
249
250
  this._activateModify = (element) => {
250
251
  state.isInteractingWithTool = true;
251
- element.addEventListener(Events.MOUSE_UP, this._mouseUpCallback);
252
- element.addEventListener(Events.MOUSE_DRAG, this._mouseDragCallback);
253
- element.addEventListener(Events.MOUSE_CLICK, this._mouseUpCallback);
254
- element.addEventListener(Events.TOUCH_END, this._mouseUpCallback);
255
- element.addEventListener(Events.TOUCH_DRAG, this._mouseDragCallback);
252
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
253
+ element.addEventListener(Events.MOUSE_DRAG, this._dragCallback);
254
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
255
+ element.addEventListener(Events.TOUCH_END, this._endCallback);
256
+ element.addEventListener(Events.TOUCH_DRAG, this._dragCallback);
256
257
  };
257
258
  this._deactivateModify = (element) => {
258
259
  state.isInteractingWithTool = false;
259
- element.removeEventListener(Events.MOUSE_UP, this._mouseUpCallback);
260
- element.removeEventListener(Events.MOUSE_DRAG, this._mouseDragCallback);
261
- element.removeEventListener(Events.MOUSE_CLICK, this._mouseUpCallback);
262
- element.removeEventListener(Events.TOUCH_END, this._mouseUpCallback);
263
- element.removeEventListener(Events.TOUCH_DRAG, this._mouseDragCallback);
260
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
261
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragCallback);
262
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
263
+ element.removeEventListener(Events.TOUCH_END, this._endCallback);
264
+ element.removeEventListener(Events.TOUCH_DRAG, this._dragCallback);
264
265
  };
265
266
  this.renderAnnotation = (enabledElement, svgDrawingHelper) => {
266
267
  const renderStatus = false;
@@ -274,8 +275,6 @@ class VideoRedactionTool extends AnnotationTool {
274
275
  if (!annotations?.length) {
275
276
  return renderStatus;
276
277
  }
277
- const targetId = this.getTargetId(viewport);
278
- const renderingEngine = viewport.getRenderingEngine();
279
278
  const styleSpecifier = {
280
279
  toolGroupId: this.toolGroupId,
281
280
  toolName: this.getToolName(),
@@ -284,7 +283,6 @@ class VideoRedactionTool extends AnnotationTool {
284
283
  for (let i = 0; i < annotations.length; i++) {
285
284
  const annotation = annotations[i];
286
285
  const { annotationUID } = annotation;
287
- const toolMetadata = annotation.metadata;
288
286
  const data = annotation.data;
289
287
  const { points, activeHandleIndex } = data.handles;
290
288
  const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
@@ -27,6 +27,7 @@ function activateClosedContourEdit(evt, annotation, viewportIdsToRender) {
27
27
  editCanvasPoints: [canvasPos],
28
28
  startCrossingIndex: undefined,
29
29
  editIndex: 0,
30
+ annotation,
30
31
  };
31
32
  this.commonData = {
32
33
  annotation,
@@ -61,9 +62,10 @@ function mouseDragClosedContourEditCallback(evt) {
61
62
  const worldPos = currentPoints.world;
62
63
  const canvasPos = currentPoints.canvas;
63
64
  const enabledElement = getEnabledElement(element);
64
- const { renderingEngine, viewport } = enabledElement;
65
+ const { viewport } = enabledElement;
65
66
  const { viewportIdsToRender, xDir, yDir, spacing } = this.commonData;
66
- const { editIndex, editCanvasPoints, startCrossingIndex } = this.editData;
67
+ const { editIndex, editCanvasPoints, startCrossingIndex, annotation } = this.editData;
68
+ this.createMemo(element, annotation);
67
69
  const lastCanvasPoint = editCanvasPoints[editCanvasPoints.length - 1];
68
70
  const lastWorldPoint = viewport.canvasToWorld(lastCanvasPoint);
69
71
  const worldPosDiff = vec3.create();
@@ -118,6 +120,7 @@ function finishEditAndStartNewEdit(evt) {
118
120
  startCrossingIndex: undefined,
119
121
  editIndex: 0,
120
122
  snapIndex: undefined,
123
+ annotation,
121
124
  };
122
125
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
123
126
  }
@@ -203,8 +206,9 @@ function mouseUpClosedContourEditCallback(evt) {
203
206
  }
204
207
  function completeClosedContourEdit(element) {
205
208
  const enabledElement = getEnabledElement(element);
206
- const { viewport, renderingEngine } = enabledElement;
209
+ const { viewport } = enabledElement;
207
210
  const { annotation, viewportIdsToRender } = this.commonData;
211
+ this.doneEditMemo();
208
212
  const { fusedCanvasPoints, prevCanvasPoints } = this.editData;
209
213
  if (fusedCanvasPoints) {
210
214
  const updatedPoints = shouldSmooth(this.configuration, annotation)
@@ -26,6 +26,7 @@ function activateDraw(evt, annotation, viewportIdsToRender) {
26
26
  canvasPoints: [canvasPos],
27
27
  polylineIndex: 0,
28
28
  contourHoleProcessingEnabled,
29
+ newAnnotation: true,
29
30
  };
30
31
  this.commonData = {
31
32
  annotation,
@@ -60,9 +61,10 @@ function mouseDragDrawCallback(evt) {
60
61
  const worldPos = currentPoints.world;
61
62
  const canvasPos = currentPoints.canvas;
62
63
  const enabledElement = getEnabledElement(element);
63
- const { renderingEngine, viewport } = enabledElement;
64
+ const { viewport } = enabledElement;
64
65
  const { annotation, viewportIdsToRender, xDir, yDir, spacing, movingTextBox, } = this.commonData;
65
- const { polylineIndex, canvasPoints } = this.drawData;
66
+ const { polylineIndex, canvasPoints, newAnnotation } = this.drawData;
67
+ this.createMemo(element, annotation, { newAnnotation });
66
68
  const lastCanvasPoint = canvasPoints[canvasPoints.length - 1];
67
69
  const lastWorldPoint = viewport.canvasToWorld(lastCanvasPoint);
68
70
  const worldPosDiff = vec3.create();
@@ -102,6 +104,8 @@ function mouseUpDrawCallback(evt) {
102
104
  const lastPoint = canvasPoints[canvasPoints.length - 1];
103
105
  const eventDetail = evt.detail;
104
106
  const { element } = eventDetail;
107
+ this.doneEditMemo();
108
+ this.drawData.newAnnotation = false;
105
109
  if (allowOpenContours &&
106
110
  !pointsAreWithinCloseContourProximity(firstPoint, lastPoint, this.configuration.closeContourProximity)) {
107
111
  this.completeDrawOpenContour(element, { contourHoleProcessingEnabled });
@@ -17,6 +17,7 @@ function activateOpenContourEdit(evt, annotation, viewportIdsToRender) {
17
17
  const canvasPos = currentPoints.canvas;
18
18
  const enabledElement = getEnabledElement(element);
19
19
  const { viewport } = enabledElement;
20
+ this.doneEditMemo();
20
21
  const prevCanvasPoints = annotation.data.contour.polyline.map(viewport.worldToCanvas);
21
22
  const { spacing, xDir, yDir } = getSubPixelSpacingAndXYDirections(viewport, this.configuration.subPixelResolution);
22
23
  this.editData = {
@@ -58,12 +59,13 @@ function mouseDragOpenContourEditCallback(evt) {
58
59
  const worldPos = currentPoints.world;
59
60
  const canvasPos = currentPoints.canvas;
60
61
  const enabledElement = getEnabledElement(element);
61
- const { renderingEngine, viewport } = enabledElement;
62
+ const { viewport } = enabledElement;
62
63
  const { viewportIdsToRender, xDir, yDir, spacing } = this.commonData;
63
64
  const { editIndex, editCanvasPoints, startCrossingIndex } = this.editData;
64
65
  const lastCanvasPoint = editCanvasPoints[editCanvasPoints.length - 1];
65
66
  const lastWorldPoint = viewport.canvasToWorld(lastCanvasPoint);
66
67
  const worldPosDiff = vec3.create();
68
+ this.createMemo(element, this.commonData.annotation);
67
69
  vec3.subtract(worldPosDiff, worldPos, lastWorldPoint);
68
70
  const xDist = Math.abs(vec3.dot(worldPosDiff, xDir));
69
71
  const yDist = Math.abs(vec3.dot(worldPosDiff, yDir));
@@ -112,6 +114,7 @@ function openContourEditOverwriteEnd(evt) {
112
114
  this.isEditingOpen = false;
113
115
  this.editData = undefined;
114
116
  this.commonData = undefined;
117
+ this.doneEditMemo();
115
118
  this.deactivateOpenContourEdit(element);
116
119
  this.activateOpenContourEndEdit(evt, annotation, viewportIdsToRender, null);
117
120
  }
@@ -262,8 +265,9 @@ function mouseUpOpenContourEditCallback(evt) {
262
265
  }
263
266
  function completeOpenContourEdit(element) {
264
267
  const enabledElement = getEnabledElement(element);
265
- const { viewport, renderingEngine } = enabledElement;
268
+ const { viewport } = enabledElement;
266
269
  const { annotation, viewportIdsToRender } = this.commonData;
270
+ this.doneEditMemo();
267
271
  const { fusedCanvasPoints, prevCanvasPoints } = this.editData;
268
272
  if (fusedCanvasPoints) {
269
273
  const updatedPoints = shouldSmooth(this.configuration)
@@ -5,7 +5,7 @@ import type { StyleSpecifier } from '../../types/AnnotationStyle';
5
5
  declare abstract class AnnotationDisplayTool extends BaseTool {
6
6
  static toolName: any;
7
7
  abstract renderAnnotation(enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper): any;
8
- filterInteractableAnnotationsForElement(element: HTMLDivElement, annotations: Annotations): Annotations | undefined;
8
+ filterInteractableAnnotationsForElement(element: HTMLDivElement, annotations: Annotations): Annotations;
9
9
  onImageSpacingCalibrated: (evt: Types.EventTypes.ImageSpacingCalibratedEvent) => void;
10
10
  protected createAnnotation(evt: EventTypes.InteractionEventType): Annotation;
11
11
  protected getReferencedImageId(viewport: Types.IViewport, worldPos: Types.Point3, viewPlaneNormal: Types.Point3, viewUp?: Types.Point3): string;
@@ -34,8 +34,8 @@ class AnnotationDisplayTool extends BaseTool {
34
34
  };
35
35
  }
36
36
  filterInteractableAnnotationsForElement(element, annotations) {
37
- if (!annotations || !annotations.length) {
38
- return;
37
+ if (!annotations?.length) {
38
+ return [];
39
39
  }
40
40
  const enabledElement = getEnabledElement(element);
41
41
  const { viewport } = enabledElement;
@@ -22,5 +22,35 @@ declare abstract class AnnotationTool extends AnnotationDisplayTool {
22
22
  styleSpecifier: StyleSpecifier;
23
23
  }): AnnotationStyle;
24
24
  private _imagePointNearToolOrHandle;
25
+ protected static createAnnotationState(annotation: Annotation, deleting?: boolean): {
26
+ annotationUID: string;
27
+ data: {
28
+ [key: string]: unknown;
29
+ handles?: {
30
+ points?: Types.Point3[];
31
+ activeHandleIndex?: number | null;
32
+ textBox?: {
33
+ hasMoved?: boolean;
34
+ worldPosition?: Types.Point3;
35
+ worldBoundingBox?: {
36
+ topLeft: Types.Point3;
37
+ topRight: Types.Point3;
38
+ bottomLeft: Types.Point3;
39
+ bottomRight: Types.Point3;
40
+ };
41
+ };
42
+ [key: string]: unknown;
43
+ };
44
+ cachedStats?: Record<string, unknown>;
45
+ };
46
+ deleting: boolean;
47
+ };
48
+ static createAnnotationMemo(element: any, annotation: Annotation, options?: {
49
+ newAnnotation?: boolean;
50
+ deleting?: boolean;
51
+ }): {
52
+ restoreMemo: () => void;
53
+ };
54
+ protected createMemo(element: any, annotation: any, options?: any): void;
25
55
  }
26
56
  export default AnnotationTool;
@@ -3,8 +3,13 @@ import { vec2 } from 'gl-matrix';
3
3
  import AnnotationDisplayTool from './AnnotationDisplayTool';
4
4
  import { isAnnotationLocked } from '../../stateManagement/annotation/annotationLocking';
5
5
  import { isAnnotationVisible } from '../../stateManagement/annotation/annotationVisibility';
6
- import { addAnnotation } from '../../stateManagement/annotation/annotationState';
6
+ import { addAnnotation, removeAnnotation, getAnnotation, } from '../../stateManagement/annotation/annotationState';
7
7
  import { triggerAnnotationModified } from '../../stateManagement/annotation/helpers/state';
8
+ import ChangeTypes from '../../enums/ChangeTypes';
9
+ import { setAnnotationSelected } from '../../stateManagement/annotation/annotationSelection';
10
+ import { addContourSegmentationAnnotation } from '../../utilities/contourSegmentation';
11
+ const { DefaultHistoryMemo } = csUtils.HistoryMemo;
12
+ const { PointsManager } = csUtils;
8
13
  class AnnotationTool extends AnnotationDisplayTool {
9
14
  static createAnnotation(...annotationBaseData) {
10
15
  let annotation = {
@@ -177,6 +182,85 @@ class AnnotationTool extends AnnotationDisplayTool {
177
182
  return true;
178
183
  }
179
184
  }
185
+ static createAnnotationState(annotation, deleting) {
186
+ const { data, annotationUID } = annotation;
187
+ const cloneData = {
188
+ ...data,
189
+ cachedStats: {},
190
+ };
191
+ delete cloneData.contour;
192
+ delete cloneData.spline;
193
+ const state = {
194
+ annotationUID,
195
+ data: structuredClone(cloneData),
196
+ deleting,
197
+ };
198
+ const contour = data.contour;
199
+ if (contour) {
200
+ state.data.contour = {
201
+ ...contour,
202
+ polyline: null,
203
+ pointsManager: PointsManager.create3(contour.polyline.length, contour.polyline),
204
+ };
205
+ }
206
+ return state;
207
+ }
208
+ static createAnnotationMemo(element, annotation, options) {
209
+ if (!annotation) {
210
+ return;
211
+ }
212
+ const { newAnnotation, deleting = newAnnotation ? false : undefined } = options || {};
213
+ const { annotationUID } = annotation;
214
+ const state = AnnotationTool.createAnnotationState(annotation, deleting);
215
+ const annotationMemo = {
216
+ restoreMemo: () => {
217
+ const newState = AnnotationTool.createAnnotationState(annotation, deleting);
218
+ if (state.deleting === true) {
219
+ state.deleting = false;
220
+ Object.assign(annotation.data, state.data);
221
+ if (annotation.data.contour) {
222
+ const annotationData = annotation.data;
223
+ annotationData.contour.polyline = state.data.contour.pointsManager.points;
224
+ delete state.data.contour.pointsManager;
225
+ if (annotationData.segmentation) {
226
+ addContourSegmentationAnnotation(annotation);
227
+ }
228
+ }
229
+ state.data = newState.data;
230
+ addAnnotation(annotation, element);
231
+ setAnnotationSelected(annotation.annotationUID, true);
232
+ getEnabledElement(element)?.viewport.render();
233
+ return;
234
+ }
235
+ if (state.deleting === false) {
236
+ state.deleting = true;
237
+ state.data = newState.data;
238
+ setAnnotationSelected(annotation.annotationUID);
239
+ removeAnnotation(annotation.annotationUID);
240
+ getEnabledElement(element)?.viewport.render();
241
+ return;
242
+ }
243
+ const currentAnnotation = getAnnotation(annotationUID);
244
+ if (!currentAnnotation) {
245
+ console.warn('No current annotation');
246
+ return;
247
+ }
248
+ Object.assign(currentAnnotation.data, state.data);
249
+ if (currentAnnotation.data.contour) {
250
+ currentAnnotation.data
251
+ .contour.polyline = state.data.contour.pointsManager.points;
252
+ }
253
+ state.data = newState.data;
254
+ currentAnnotation.invalidated = true;
255
+ triggerAnnotationModified(currentAnnotation, element, ChangeTypes.History);
256
+ },
257
+ };
258
+ DefaultHistoryMemo.push(annotationMemo);
259
+ return annotationMemo;
260
+ }
261
+ createMemo(element, annotation, options) {
262
+ this.memo ||= AnnotationTool.createAnnotationMemo(element, annotation, options);
263
+ }
180
264
  }
181
265
  AnnotationTool.toolName = 'AnnotationTool';
182
266
  export default AnnotationTool;
@@ -33,5 +33,6 @@ declare abstract class BaseTool {
33
33
  static createZoomPanMemo(viewport: any): {
34
34
  restoreMemo: () => void;
35
35
  };
36
+ doneEditMemo(): void;
36
37
  }
37
38
  export default BaseTool;
@@ -92,8 +92,8 @@ class BaseTool {
92
92
  throw new Error('getTargetId: viewport must have a getViewReferenceId method');
93
93
  }
94
94
  undo() {
95
+ this.doneEditMemo();
95
96
  DefaultHistoryMemo.undo();
96
- this.memo = null;
97
97
  }
98
98
  redo() {
99
99
  DefaultHistoryMemo.redo();
@@ -117,6 +117,12 @@ class BaseTool {
117
117
  DefaultHistoryMemo.push(zoomPanMemo);
118
118
  return zoomPanMemo;
119
119
  }
120
+ doneEditMemo() {
121
+ if (this.memo?.commitMemo?.()) {
122
+ DefaultHistoryMemo.push(this.memo);
123
+ }
124
+ this.memo = null;
125
+ }
120
126
  }
121
127
  BaseTool.toolName = 'BaseTool';
122
128
  export default BaseTool;
@@ -6,15 +6,11 @@ import InterpolationManager from '../../utilities/segmentation/InterpolationMana
6
6
  import { addContourSegmentationAnnotation, removeContourSegmentationAnnotation, } from '../../utilities/contourSegmentation';
7
7
  import { triggerAnnotationRenderForToolGroupIds } from '../../utilities/triggerAnnotationRenderForToolGroupIds';
8
8
  import { getToolGroupForViewport } from '../../store/ToolGroupManager';
9
- import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
10
9
  import { getSegmentationRepresentations } from '../../stateManagement/segmentation/getSegmentationRepresentation';
11
10
  import { getActiveSegmentation } from '../../stateManagement/segmentation/getActiveSegmentation';
12
- import { getSegmentationRepresentationVisibility } from '../../stateManagement/segmentation/getSegmentationRepresentationVisibility';
13
11
  import { getViewportIdsWithSegmentation } from '../../stateManagement/segmentation/getViewportIdsWithSegmentation';
14
12
  import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
15
13
  import { getLockedSegmentIndices } from '../../stateManagement/segmentation/segmentLocking';
16
- import { segmentationStyle } from '../../stateManagement/segmentation/SegmentationStyle';
17
- import { internalGetHiddenSegmentIndices } from '../../stateManagement/segmentation/helpers/internalGetHiddenSegmentIndices';
18
14
  import { getSVGStyleForSegment } from '../../utilities/segmentation/getSVGStyleForSegment';
19
15
  class ContourSegmentationBaseTool extends ContourBaseTool {
20
16
  constructor(toolProps, defaultToolProps) {
@@ -146,6 +146,7 @@ class BrushTool extends LabelmapBaseTool {
146
146
  if (!this._previewData.preview && !this._previewData.isDrag) {
147
147
  this.applyActiveStrategy(enabledElement, operationData);
148
148
  }
149
+ this.doneEditMemo();
149
150
  this._deactivateDraw(element);
150
151
  resetElementCursor(element);
151
152
  this.updateCursor(evt);
@@ -1,7 +1,8 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- import { BaseTool } from '../base';
3
2
  import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper, Annotation } from '../../types';
4
- declare class CircleScissorsTool extends BaseTool {
3
+ import LabelmapBaseTool from './LabelmapBaseTool';
4
+ import type { LabelmapMemo } from '../../utilities/segmentation/createLabelmapMemo';
5
+ declare class CircleScissorsTool extends LabelmapBaseTool {
5
6
  static toolName: any;
6
7
  editData: {
7
8
  annotation: Annotation;
@@ -18,6 +19,7 @@ declare class CircleScissorsTool extends BaseTool {
18
19
  hasMoved?: boolean;
19
20
  imageId: string;
20
21
  centerCanvas?: Array<number>;
22
+ memo?: LabelmapMemo;
21
23
  } | null;
22
24
  isDrawing: boolean;
23
25
  isHandleOutsideImage: boolean;
@@ -8,7 +8,8 @@ import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCur
8
8
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
9
9
  import { segmentLocking, activeSegmentation, segmentIndex as segmentIndexController, config as segmentationConfig, } from '../../stateManagement/segmentation';
10
10
  import { getCurrentLabelmapImageIdForViewport, getSegmentation, } from '../../stateManagement/segmentation/segmentationState';
11
- class CircleScissorsTool extends BaseTool {
11
+ import LabelmapBaseTool from './LabelmapBaseTool';
12
+ class CircleScissorsTool extends LabelmapBaseTool {
12
13
  constructor(toolProps = {}, defaultToolProps = {
13
14
  supportedInteractionTypes: ['Mouse', 'Touch'],
14
15
  configuration: {
@@ -167,10 +168,12 @@ class CircleScissorsTool extends BaseTool {
167
168
  viewPlaneNormal,
168
169
  viewUp,
169
170
  strategySpecificConfiguration: {},
171
+ createMemo: this.createMemo.bind(this),
170
172
  };
171
173
  this.editData = null;
172
174
  this.isDrawing = false;
173
175
  this.applyActiveStrategy(enabledElement, operationData);
176
+ this.doneEditMemo();
174
177
  };
175
178
  this._activateDraw = (element) => {
176
179
  element.addEventListener(Events.MOUSE_UP, this._endCallback);
@@ -1,6 +1,7 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import { BaseTool } from '../base';
3
3
  import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
4
+ import * as LabelmapMemo from '../../utilities/segmentation/createLabelmapMemo';
4
5
  export type PreviewData = {
5
6
  preview: unknown;
6
7
  timer?: number;
@@ -32,7 +33,7 @@ export default class LabelmapBaseTool extends BaseTool {
32
33
  };
33
34
  protected _previewData?: PreviewData;
34
35
  constructor(toolProps: any, defaultToolProps: any);
35
- createMemo(segmentId: string, segmentationVoxelManager: any, preview: any): void;
36
+ createMemo(segmentId: string, segmentationVoxelManager: any, preview: any): LabelmapMemo.LabelmapMemo;
36
37
  createEditData(element: any): {
37
38
  volumeId: string;
38
39
  referencedVolumeId: any;
@@ -89,6 +90,7 @@ export default class LabelmapBaseTool extends BaseTool {
89
90
  viewUp: any;
90
91
  strategySpecificConfiguration: any;
91
92
  preview: unknown;
93
+ createMemo: (segmentId: string, segmentationVoxelManager: any, preview: any) => LabelmapMemo.LabelmapMemo;
92
94
  override: {
93
95
  voxelManager: Types.IVoxelManager<number>;
94
96
  imageData: vtkImageData;
@@ -108,6 +110,7 @@ export default class LabelmapBaseTool extends BaseTool {
108
110
  viewUp: any;
109
111
  strategySpecificConfiguration: any;
110
112
  preview: unknown;
113
+ createMemo: (segmentId: string, segmentationVoxelManager: any, preview: any) => LabelmapMemo.LabelmapMemo;
111
114
  volumeId: string;
112
115
  referencedVolumeId: any;
113
116
  segmentsLocked: number[] | [];
@@ -123,6 +126,7 @@ export default class LabelmapBaseTool extends BaseTool {
123
126
  viewUp: any;
124
127
  strategySpecificConfiguration: any;
125
128
  preview: unknown;
129
+ createMemo: (segmentId: string, segmentationVoxelManager: any, preview: any) => LabelmapMemo.LabelmapMemo;
126
130
  imageId: string;
127
131
  segmentsLocked: number[] | [];
128
132
  override: {
@@ -141,6 +145,7 @@ export default class LabelmapBaseTool extends BaseTool {
141
145
  viewUp: any;
142
146
  strategySpecificConfiguration: any;
143
147
  preview: unknown;
148
+ createMemo: (segmentId: string, segmentationVoxelManager: any, preview: any) => LabelmapMemo.LabelmapMemo;
144
149
  imageId: string;
145
150
  segmentsLocked: number[] | [];
146
151
  volumeId?: undefined;
@@ -10,6 +10,7 @@ import { getStackSegmentationImageIdsForViewport } from '../../stateManagement/s
10
10
  import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
11
11
  import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
12
12
  import { StrategyCallbacks } from '../../enums';
13
+ import * as LabelmapMemo from '../../utilities/segmentation/createLabelmapMemo';
13
14
  export default class LabelmapBaseTool extends BaseTool {
14
15
  constructor(toolProps, defaultToolProps) {
15
16
  super(toolProps, defaultToolProps);
@@ -23,7 +24,8 @@ export default class LabelmapBaseTool extends BaseTool {
23
24
  };
24
25
  }
25
26
  createMemo(segmentId, segmentationVoxelManager, preview) {
26
- console.warn('LabelmapBaseTool.createMemo not implemented yet');
27
+ this.memo ||= LabelmapMemo.createLabelmapMemo(segmentId, segmentationVoxelManager, preview);
28
+ return this.memo;
27
29
  }
28
30
  createEditData(element) {
29
31
  const enabledElement = getEnabledElement(element);
@@ -181,6 +183,7 @@ export default class LabelmapBaseTool extends BaseTool {
181
183
  viewUp,
182
184
  strategySpecificConfiguration: this.configuration.strategySpecificConfiguration,
183
185
  preview: this._previewData?.preview,
186
+ createMemo: this.createMemo.bind(this),
184
187
  };
185
188
  return operationData;
186
189
  }
@@ -210,9 +213,11 @@ export default class LabelmapBaseTool extends BaseTool {
210
213
  if (!element) {
211
214
  return;
212
215
  }
216
+ this.doneEditMemo();
213
217
  const enabledElement = getEnabledElement(element);
214
218
  this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.AcceptPreview);
215
219
  this._previewData.isDrag = false;
216
220
  this._previewData.preview = null;
221
+ this.doneEditMemo();
217
222
  }
218
223
  }
@@ -29,9 +29,9 @@ class PaintFillTool extends BaseTool {
29
29
  const { representationData } = getSegmentation(segmentationId);
30
30
  let dimensions;
31
31
  let direction;
32
- let scalarData;
33
32
  let index;
34
33
  let voxelManager;
34
+ this.doneEditMemo();
35
35
  if (viewport instanceof BaseVolumeViewport) {
36
36
  const { volumeId } = representationData[SegmentationRepresentations.Labelmap];
37
37
  const segmentation = cache.getVolume(volumeId);
@@ -1,7 +1,7 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- import { BaseTool } from '../base';
3
2
  import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper, Annotation } from '../../types';
4
- declare class RectangleScissorsTool extends BaseTool {
3
+ import LabelmapBaseTool from './LabelmapBaseTool';
4
+ declare class RectangleScissorsTool extends LabelmapBaseTool {
5
5
  static toolName: any;
6
6
  _throttledCalculateCachedStats: Function;
7
7
  editData: {
@@ -8,8 +8,9 @@ import { drawRect as drawRectSvg } from '../../drawingSvg';
8
8
  import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
9
9
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
10
10
  import { config as segmentationConfig, segmentLocking, segmentIndex as segmentIndexController, activeSegmentation, } from '../../stateManagement/segmentation';
11
- import { getCurrentLabelmapImageIdForViewport, getSegmentation, getStackSegmentationImageIdsForViewport, } from '../../stateManagement/segmentation/segmentationState';
12
- class RectangleScissorsTool extends BaseTool {
11
+ import { getCurrentLabelmapImageIdForViewport, getSegmentation, } from '../../stateManagement/segmentation/segmentationState';
12
+ import LabelmapBaseTool from './LabelmapBaseTool';
13
+ class RectangleScissorsTool extends LabelmapBaseTool {
13
14
  constructor(toolProps = {}, defaultToolProps = {
14
15
  supportedInteractionTypes: ['Mouse', 'Touch'],
15
16
  configuration: {
@@ -171,10 +172,13 @@ class RectangleScissorsTool extends BaseTool {
171
172
  const operationData = {
172
173
  ...this.editData,
173
174
  points: data.handles.points,
175
+ strategySpecificConfiguration: {},
176
+ createMemo: this.createMemo.bind(this),
174
177
  };
175
178
  this.editData = null;
176
179
  this.isDrawing = false;
177
180
  this.applyActiveStrategy(enabledElement, operationData);
181
+ this.doneEditMemo();
178
182
  };
179
183
  this._activateDraw = (element) => {
180
184
  element.addEventListener(Events.MOUSE_UP, this._endCallback);
@@ -1,7 +1,7 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- import { BaseTool } from '../base';
3
2
  import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper, Annotation } from '../../types';
4
- declare class SphereScissorsTool extends BaseTool {
3
+ import LabelmapBaseTool from './LabelmapBaseTool';
4
+ declare class SphereScissorsTool extends LabelmapBaseTool {
5
5
  static toolName: any;
6
6
  editData: {
7
7
  annotation: Annotation;