@cornerstonejs/tools 1.63.5 → 1.64.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 (85) hide show
  1. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts +3 -0
  2. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +2 -0
  3. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
  4. package/dist/cjs/store/ToolGroupManager/ToolGroup.d.ts +3 -2
  5. package/dist/cjs/store/ToolGroupManager/ToolGroup.js +13 -5
  6. package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
  7. package/dist/cjs/tools/CrosshairsTool.d.ts +1 -1
  8. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +1 -1
  9. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  10. package/dist/cjs/tools/annotation/SplineROITool.js +6 -4
  11. package/dist/cjs/tools/annotation/SplineROITool.js.map +1 -1
  12. package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js +4 -6
  13. package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
  14. package/dist/cjs/types/IToolGroup.d.ts +2 -2
  15. package/dist/cjs/types/index.d.ts +1 -1
  16. package/dist/cjs/utilities/contourSegmentation/addContourSegmentationAnnotation.js +3 -0
  17. package/dist/cjs/utilities/contourSegmentation/addContourSegmentationAnnotation.js.map +1 -1
  18. package/dist/cjs/utilities/contours/interpolation/createPolylineToolData.js +2 -4
  19. package/dist/cjs/utilities/contours/interpolation/createPolylineToolData.js.map +1 -1
  20. package/dist/cjs/utilities/contours/interpolation/interpolate.js +27 -17
  21. package/dist/cjs/utilities/contours/interpolation/interpolate.js.map +1 -1
  22. package/dist/cjs/utilities/contours/interpolation/selectHandles.js +2 -2
  23. package/dist/cjs/utilities/contours/interpolation/selectHandles.js.map +1 -1
  24. package/dist/cjs/utilities/contours/interpolation/updateChildInterpolationUID.d.ts +2 -0
  25. package/dist/cjs/utilities/contours/interpolation/updateChildInterpolationUID.js +39 -0
  26. package/dist/cjs/utilities/contours/interpolation/updateChildInterpolationUID.js.map +1 -0
  27. package/dist/cjs/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
  28. package/dist/cjs/utilities/segmentation/InterpolationManager/InterpolationManager.js.map +1 -1
  29. package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +1 -1
  30. package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
  31. package/dist/esm/store/ToolGroupManager/ToolGroup.js +13 -5
  32. package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
  33. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +1 -1
  34. package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  35. package/dist/esm/tools/annotation/SplineROITool.js +6 -4
  36. package/dist/esm/tools/annotation/SplineROITool.js.map +1 -1
  37. package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js +4 -6
  38. package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
  39. package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js +3 -0
  40. package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js.map +1 -1
  41. package/dist/esm/utilities/contours/interpolation/createPolylineToolData.js +2 -1
  42. package/dist/esm/utilities/contours/interpolation/createPolylineToolData.js.map +1 -1
  43. package/dist/esm/utilities/contours/interpolation/interpolate.js +27 -17
  44. package/dist/esm/utilities/contours/interpolation/interpolate.js.map +1 -1
  45. package/dist/esm/utilities/contours/interpolation/selectHandles.js +2 -2
  46. package/dist/esm/utilities/contours/interpolation/selectHandles.js.map +1 -1
  47. package/dist/esm/utilities/contours/interpolation/updateChildInterpolationUID.js +13 -0
  48. package/dist/esm/utilities/contours/interpolation/updateChildInterpolationUID.js.map +1 -0
  49. package/dist/esm/utilities/segmentation/InterpolationManager/InterpolationManager.js.map +1 -1
  50. package/dist/types/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts +3 -0
  51. package/dist/types/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts.map +1 -1
  52. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts +3 -2
  53. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts.map +1 -1
  54. package/dist/types/tools/CrosshairsTool.d.ts +1 -1
  55. package/dist/types/tools/CrosshairsTool.d.ts.map +1 -1
  56. package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
  57. package/dist/types/tools/annotation/SplineROITool.d.ts.map +1 -1
  58. package/dist/types/tools/annotation/planarFreehandROITool/drawLoop.d.ts.map +1 -1
  59. package/dist/types/types/IToolGroup.d.ts +2 -2
  60. package/dist/types/types/IToolGroup.d.ts.map +1 -1
  61. package/dist/types/types/index.d.ts +1 -1
  62. package/dist/types/types/index.d.ts.map +1 -1
  63. package/dist/types/utilities/contourSegmentation/addContourSegmentationAnnotation.d.ts.map +1 -1
  64. package/dist/types/utilities/contours/interpolation/createPolylineToolData.d.ts.map +1 -1
  65. package/dist/types/utilities/contours/interpolation/interpolate.d.ts.map +1 -1
  66. package/dist/types/utilities/contours/interpolation/selectHandles.d.ts.map +1 -1
  67. package/dist/types/utilities/contours/interpolation/updateChildInterpolationUID.d.ts +3 -0
  68. package/dist/types/utilities/contours/interpolation/updateChildInterpolationUID.d.ts.map +1 -0
  69. package/dist/types/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
  70. package/dist/umd/index.js +1 -1
  71. package/dist/umd/index.js.map +1 -1
  72. package/package.json +3 -3
  73. package/src/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.ts +6 -1
  74. package/src/store/ToolGroupManager/ToolGroup.ts +28 -10
  75. package/src/tools/annotation/PlanarFreehandROITool.ts +3 -3
  76. package/src/tools/annotation/SplineROITool.ts +10 -5
  77. package/src/tools/annotation/planarFreehandROITool/drawLoop.ts +4 -7
  78. package/src/types/IToolGroup.ts +11 -2
  79. package/src/types/index.ts +1 -1
  80. package/src/utilities/contourSegmentation/addContourSegmentationAnnotation.ts +4 -0
  81. package/src/utilities/contours/interpolation/createPolylineToolData.ts +2 -1
  82. package/src/utilities/contours/interpolation/interpolate.ts +54 -44
  83. package/src/utilities/contours/interpolation/selectHandles.ts +3 -2
  84. package/src/utilities/contours/interpolation/updateChildInterpolationUID.ts +23 -0
  85. package/src/utilities/segmentation/InterpolationManager/InterpolationManager.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.63.5",
3
+ "version": "1.64.0",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "src/index.ts",
6
6
  "types": "dist/types/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
30
30
  },
31
31
  "dependencies": {
32
- "@cornerstonejs/core": "^1.63.5",
32
+ "@cornerstonejs/core": "^1.64.0",
33
33
  "@icr/polyseg-wasm": "0.4.0",
34
34
  "@types/offscreencanvas": "2019.7.3",
35
35
  "comlink": "^4.4.1",
@@ -59,5 +59,5 @@
59
59
  "type": "individual",
60
60
  "url": "https://ohif.org/donate"
61
61
  },
62
- "gitHead": "e2d969d1bf43e204ce5bed804ca3af01d2071a08"
62
+ "gitHead": "997836e0c4aa342a1af3bc436a6c06112b24cfbc"
63
63
  }
@@ -201,7 +201,12 @@ function findIntersectingContour(
201
201
  }
202
202
  }
203
203
 
204
- function createPolylineHole(
204
+ /**
205
+ * Modifies the holeAnnotation to work as a contour hole in the targetAnnotation,
206
+ * displayed on the given viewport.
207
+
208
+ */
209
+ export function createPolylineHole(
205
210
  viewport: Types.IViewport,
206
211
  targetAnnotation: ContourSegmentationAnnotation,
207
212
  holeAnnotation: ContourSegmentationAnnotation
@@ -30,6 +30,8 @@ import { initElementCursor } from '../../cursors/elementCursor';
30
30
 
31
31
  const { Active, Passive, Enabled, Disabled } = ToolModes;
32
32
 
33
+ const PRIMARY_BINDINGS = [{ mouseButton: MouseBindings.Primary }];
34
+
33
35
  /**
34
36
  * ToolGroup class which is a container for tools and their modes and states.
35
37
  * In Cornerstone3DTools, you need to create a tool group in order to use the
@@ -424,7 +426,7 @@ export default class ToolGroup implements IToolGroup {
424
426
  */
425
427
  public setToolPassive(
426
428
  toolName: string,
427
- options?: { removeAllBindings?: boolean }
429
+ options?: { removeAllBindings?: boolean | IToolBinding[] }
428
430
  ): void {
429
431
  const toolInstance = this._toolInstances[toolName];
430
432
 
@@ -449,13 +451,18 @@ export default class ToolGroup implements IToolGroup {
449
451
  }
450
452
  );
451
453
 
452
- const defaultMousePrimary = this.getDefaultMousePrimary();
454
+ const matchBindings = Array.isArray(options?.removeAllBindings)
455
+ ? options.removeAllBindings
456
+ : this.getDefaultPrimaryBindings();
453
457
 
454
458
  // Remove the primary button bindings without modifiers, if they exist
455
459
  toolOptions.bindings = toolOptions.bindings.filter(
456
460
  (binding) =>
457
461
  options?.removeAllBindings !== true &&
458
- (binding.mouseButton !== defaultMousePrimary || binding.modifierKey)
462
+ !matchBindings.some((matchBinding) =>
463
+ hasSameBinding(binding, matchBinding)
464
+ )
465
+ //(binding.mouseButton !== defaultMousePrimary || binding.modifierKey)
459
466
  );
460
467
  // If there are other bindings, set the tool to be active
461
468
  let mode = Passive;
@@ -681,12 +688,20 @@ export default class ToolGroup implements IToolGroup {
681
688
 
682
689
  /**
683
690
  * Returns the default mouse primary button.
684
- *
685
691
  */
686
692
  public getDefaultMousePrimary(): MouseBindings {
687
693
  return MouseBindings.Primary;
688
694
  }
689
695
 
696
+ /**
697
+ * Gets an array of bindings that is the full primary binding.
698
+ * Currently this is just the primary mouse button, but may be extended in the
699
+ * future to include touch or other binding types.
700
+ */
701
+ public getDefaultPrimaryBindings(): IToolBinding[] {
702
+ return PRIMARY_BINDINGS;
703
+ }
704
+
690
705
  /**
691
706
  * Get the configuration of tool. It returns only the config for the given path (in case exists).
692
707
  * ConfigurationPath is the the path of the property to get separated by '.'.
@@ -759,12 +774,9 @@ export default class ToolGroup implements IToolGroup {
759
774
  * @returns A boolean value.
760
775
  */
761
776
  private _hasMousePrimaryButtonBinding(toolOptions) {
762
- const defaultMousePrimary = this.getDefaultMousePrimary();
763
-
764
- return toolOptions?.bindings?.some(
765
- (binding) =>
766
- binding.mouseButton === defaultMousePrimary &&
767
- binding.modifierKey === undefined
777
+ const primaryBindings = this.getDefaultPrimaryBindings();
778
+ return toolOptions?.bindings?.some((binding) =>
779
+ primaryBindings.some((primary) => hasSameBinding(binding, primary))
768
780
  );
769
781
  }
770
782
 
@@ -799,6 +811,9 @@ export default class ToolGroup implements IToolGroup {
799
811
  }
800
812
  }
801
813
 
814
+ /**
815
+ * Figure out if the two bindings are the same
816
+ */
802
817
  function hasSameBinding(
803
818
  binding1: IToolBinding,
804
819
  binding2: IToolBinding
@@ -806,6 +821,9 @@ function hasSameBinding(
806
821
  if (binding1.mouseButton !== binding2.mouseButton) {
807
822
  return false;
808
823
  }
824
+ if (binding1.numTouchPoints !== binding2.numTouchPoints) {
825
+ return false;
826
+ }
809
827
 
810
828
  return binding1.modifierKey === binding2.modifierKey;
811
829
  }
@@ -372,7 +372,7 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
372
372
  const enabledElement = getEnabledElement(element);
373
373
  const { viewport } = enabledElement;
374
374
 
375
- const points = annotation.data.contour.polyline;
375
+ const { polyline: points } = annotation.data.contour;
376
376
 
377
377
  // NOTE: It is implemented this way so that we do not double calculate
378
378
  // points when number crunching adjacent line segments.
@@ -402,7 +402,7 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
402
402
  return pointCanProjectOnLine(canvasCoords, pStart, pEnd, proximity);
403
403
  };
404
404
 
405
- cancel = (element: HTMLDivElement): void => {
405
+ public cancel = (element: HTMLDivElement): void => {
406
406
  const isDrawing = this.isDrawing;
407
407
  const isEditingOpen = this.isEditingOpen;
408
408
  const isEditingClosed = this.isEditingClosed;
@@ -421,7 +421,7 @@ class PlanarFreehandROITool extends ContourSegmentationBaseTool {
421
421
  * `handles`, which means `filterAnnotationsForDisplay` fails inside
422
422
  * `filterAnnotationsWithinSlice`.
423
423
  */
424
- filterInteractableAnnotationsForElement(
424
+ public filterInteractableAnnotationsForElement(
425
425
  element: HTMLDivElement,
426
426
  annotations: Annotations
427
427
  ): Annotations | undefined {
@@ -691,12 +691,17 @@ class SplineROITool extends ContourSegmentationBaseTool {
691
691
  const splineConfig = this._getSplineConfig(splineType);
692
692
  const spline = annotation.data.spline.instance;
693
693
 
694
+ const childAnnotations = getChildAnnotations(annotation);
695
+ const missingAnnotation = childAnnotations.findIndex((it) => !it);
696
+ if (missingAnnotation !== -1) {
697
+ // Child annotations go AWOL for a variety of reasons, so report is specifically here
698
+ throw new Error(
699
+ `Can't find annotation for child ${annotation.childAnnotationUIDs.join()}`
700
+ );
701
+ }
694
702
  // Update current and all child annotations/splines
695
- const splineAnnotationsGroup = [
696
- annotation,
697
- ...getChildAnnotations(annotation),
698
- ].filter((annotation) =>
699
- this._isSplineROIAnnotation(annotation)
703
+ const splineAnnotationsGroup = [annotation, ...childAnnotations].filter(
704
+ (annotation) => this._isSplineROIAnnotation(annotation)
700
705
  ) as SplineROIAnnotation[];
701
706
 
702
707
  splineAnnotationsGroup.forEach((annotation) => {
@@ -18,7 +18,7 @@ import { PlanarFreehandROIAnnotation } from '../../../types/ToolSpecificAnnotati
18
18
  import findOpenUShapedContourVectorToPeak from './findOpenUShapedContourVectorToPeak';
19
19
  import { polyline } from '../../../utilities/math';
20
20
  import { removeAnnotation } from '../../../stateManagement/annotation/annotationState';
21
- import reverseIfAntiClockwise from '../../../utilities/contours/reverseIfAntiClockwise';
21
+ import { ContourWindingDirection } from '../../../types/ContourAnnotation';
22
22
 
23
23
  const {
24
24
  addCanvasPointsToArray,
@@ -234,19 +234,16 @@ function completeDrawClosedContour(
234
234
  // Remove last point which will be a duplicate now.
235
235
  canvasPoints.pop();
236
236
 
237
- const clockwise = this.configuration.makeClockWise
238
- ? reverseIfAntiClockwise(canvasPoints)
239
- : canvasPoints;
240
-
241
237
  const updatedPoints = shouldSmooth(this.configuration, annotation)
242
- ? getInterpolatedPoints(this.configuration, clockwise)
243
- : clockwise;
238
+ ? getInterpolatedPoints(this.configuration, canvasPoints)
239
+ : canvasPoints;
244
240
 
245
241
  this.updateContourPolyline(
246
242
  annotation,
247
243
  {
248
244
  points: updatedPoints,
249
245
  closed: true,
246
+ targetWindingDirection: ContourWindingDirection.Clockwise,
250
247
  },
251
248
  viewport
252
249
  );
@@ -1,9 +1,15 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- import { SetToolBindingsType, ToolOptionsType } from './ISetToolModeOptions';
2
+ import {
3
+ IToolBinding,
4
+ SetToolBindingsType,
5
+ ToolOptionsType,
6
+ } from './ISetToolModeOptions';
3
7
  import { MouseBindings } from '../enums';
4
8
  import { ToolConfiguration } from '../types';
5
9
  /**
6
10
  * ToolGroup interface
11
+ * @deprecated - this is going away in favour of using the type import from the
12
+ * tool group itself.
7
13
  */
8
14
  export default interface IToolGroup {
9
15
  /** Unserializable instantiated tool classes, keyed by name */
@@ -44,7 +50,10 @@ export default interface IToolGroup {
44
50
  };
45
51
  /** Setting the tool to be Passive by its name*/
46
52
  setToolPassive: {
47
- (toolName: string, options?: { removeAllBindings?: boolean }): void;
53
+ (
54
+ toolName: string,
55
+ options?: { removeAllBindings?: boolean | IToolBinding[] }
56
+ ): void;
48
57
  };
49
58
  /** Setting the tool to be Enabled by its name*/
50
59
  setToolEnabled: {
@@ -23,7 +23,7 @@ import type {
23
23
  IToolBinding,
24
24
  ToolOptionsType,
25
25
  } from './ISetToolModeOptions';
26
- import type IToolGroup from './IToolGroup';
26
+ import type IToolGroup from '../store/ToolGroupManager/ToolGroup';
27
27
  import type * as ToolSpecificAnnotationTypes from './ToolSpecificAnnotationTypes';
28
28
  import type * as AnnotationStyle from './AnnotationStyle';
29
29
  import type ToolHandle from './ToolHandle';
@@ -8,6 +8,10 @@ import { ContourSegmentationAnnotation } from '../../types';
8
8
  export function addContourSegmentationAnnotation(
9
9
  annotation: ContourSegmentationAnnotation
10
10
  ) {
11
+ if (annotation.parentAnnotationUID) {
12
+ // Don't add it for parent annotations - this happens during interpolation
13
+ return;
14
+ }
11
15
  if (!annotation.data.segmentation) {
12
16
  throw new Error(
13
17
  'addContourSegmentationAnnotation: annotation does not have a segmentation data'
@@ -31,6 +31,7 @@ export default function createPolylineToolData(
31
31
  annotationUID: undefined,
32
32
  cachedStats: {},
33
33
  childAnnotationUIDs: [],
34
+ parentAnnotationUID: undefined,
34
35
  });
35
36
  Object.assign(annotation.data, {
36
37
  handles: {
@@ -54,8 +55,8 @@ export default function createPolylineToolData(
54
55
  },
55
56
  },
56
57
  contour: {
58
+ ...referencedToolData.data.contour,
57
59
  polyline,
58
- closed: true,
59
60
  },
60
61
  });
61
62
 
@@ -10,6 +10,8 @@ import type { AnnotationInterpolationCompletedEventDetail } from '../../../types
10
10
  import EventTypes from '../../../enums/Events';
11
11
  import * as annotationState from '../../../stateManagement/annotation';
12
12
  import selectHandles from './selectHandles';
13
+ import updateChildInterpolationUID from './updateChildInterpolationUID';
14
+ import { createPolylineHole } from '../../../eventListeners/annotations/contourSegmentation/contourSegmentationCompleted';
13
15
 
14
16
  const { PointsManager } = utilities;
15
17
 
@@ -70,7 +72,8 @@ function interpolate(viewportData: InterpolationViewportData) {
70
72
  * @returns null
71
73
  */
72
74
  function startInterpolation(viewportData: InterpolationViewportData) {
73
- const toolData = viewportData.annotation;
75
+ const { annotation: toolData } = viewportData;
76
+ updateChildInterpolationUID(toolData);
74
77
  const { interpolationData, interpolationList } =
75
78
  findAnnotationsForInterpolation(toolData, viewportData) || {};
76
79
 
@@ -129,12 +132,10 @@ function _linearlyInterpolateBetween(
129
132
  interpolationData,
130
133
  eventData
131
134
  ) {
132
- const c1 = _generateClosedContour(
133
- interpolationData.get(annotationPair[0])[0].data.contour.polyline
134
- );
135
- const c2 = _generateClosedContour(
136
- interpolationData.get(annotationPair[1])[0].data.contour.polyline
137
- );
135
+ const annotation0 = interpolationData.get(annotationPair[0])[0];
136
+ const annotation1 = interpolationData.get(annotationPair[1])[0];
137
+ const c1 = _generateClosedContour(annotation0.data.contour.polyline);
138
+ const c2 = _generateClosedContour(annotation1.data.contour.polyline);
138
139
 
139
140
  const { c1Interp, c2Interp } = _generateInterpolationContourPair(c1, c2);
140
141
  c1Interp.kIndex = annotationPair[0];
@@ -189,6 +190,8 @@ function _linearlyInterpolateContour(
189
190
  ) {
190
191
  const [startIndex, endIndex] = annotationPair;
191
192
  const zInterp = (sliceIndex - startIndex) / (endIndex - startIndex);
193
+ const annotation0 = interpolationData.get(startIndex)[0];
194
+ const annotation1 = interpolationData.get(endIndex)[0];
192
195
  const interpolated3DPoints = _generateInterpolatedOpenContour(
193
196
  c1Interp,
194
197
  c2Interp,
@@ -196,9 +199,7 @@ function _linearlyInterpolateContour(
196
199
  c1HasMoreNodes
197
200
  );
198
201
 
199
- const nearestAnnotation = interpolationData.get(
200
- annotationPair[zInterp > 0.5 ? 1 : 0]
201
- )[0];
202
+ const nearestAnnotation = zInterp > 0.5 ? annotation1 : annotation0;
202
203
 
203
204
  const handlePoints = selectHandles(interpolated3DPoints);
204
205
 
@@ -255,8 +256,41 @@ function _addInterpolatedContour(
255
256
  interpolatedAnnotation,
256
257
  referencedToolData
257
258
  );
259
+
260
+ const { parentAnnotationUID } = referencedToolData;
261
+ if (parentAnnotationUID) {
262
+ const parentReferenced =
263
+ annotationState.state.getAnnotation(parentAnnotationUID);
264
+ const parentAnnotation = _findExistingAnnotation(
265
+ parentReferenced,
266
+ sliceIndex,
267
+ eventData
268
+ );
269
+ createPolylineHole(viewport, parentAnnotation, interpolatedAnnotation);
270
+ }
258
271
  }
259
272
 
273
+ /**
274
+ * Finds an existing annotation on the given slide, with the interpolation UID as
275
+ * specified in the referenced tool data.
276
+ */
277
+ function _findExistingAnnotation(referencedToolData, sliceIndex, eventData) {
278
+ const { viewport } = eventData;
279
+ const annotations = annotationState.state.getAnnotations(
280
+ referencedToolData.metadata.toolName,
281
+ viewport.element
282
+ );
283
+
284
+ for (let i = 0; i < annotations.length; i++) {
285
+ const annotation = annotations[i] as InterpolationROIAnnotation;
286
+ if (
287
+ annotation.interpolationUID === referencedToolData.interpolationUID &&
288
+ annotation.metadata.sliceIndex === sliceIndex
289
+ ) {
290
+ return annotation;
291
+ }
292
+ }
293
+ }
260
294
  /**
261
295
  * _editInterpolatedContour - Edits an interpolated polygon on the imageId
262
296
  * that corresponds to the specified ROIContour.
@@ -266,7 +300,6 @@ function _addInterpolatedContour(
266
300
  * @param referencedToolData - type, The toolData of another polygon in the
267
301
  * ROIContour, to assign appropriate metadata to the new polygon.
268
302
  * @param eventData - object
269
- * @returns null
270
303
  */
271
304
  function _editInterpolatedContour(
272
305
  interpolated3DPoints: PointsArray3,
@@ -275,46 +308,23 @@ function _editInterpolatedContour(
275
308
  referencedToolData,
276
309
  eventData
277
310
  ) {
278
- const { viewport } = eventData;
279
- const annotations = annotationState.state.getAnnotations(
280
- referencedToolData.metadata.toolName,
281
- viewport.element
311
+ const oldAnnotationData = _findExistingAnnotation(
312
+ referencedToolData,
313
+ sliceIndex,
314
+ eventData
282
315
  );
283
316
 
284
- // Find the index of the polygon on this slice corresponding to
285
- // The ROIContour.
286
- let toolDataIndex;
287
-
288
- for (let i = 0; i < annotations.length; i++) {
289
- const annotation = annotations[i] as InterpolationROIAnnotation;
290
- if (
291
- annotation.interpolationUID === referencedToolData.interpolationUID &&
292
- annotation.metadata.sliceIndex === sliceIndex
293
- ) {
294
- toolDataIndex = i;
295
- break;
296
- }
297
- }
298
- if (toolDataIndex === undefined) {
299
- console.warn(
300
- 'Unable to find referenced slice index in the tool data',
301
- sliceIndex,
302
- annotations
303
- );
304
- return;
305
- }
306
-
307
- const oldToolData = annotations[toolDataIndex] as InterpolationROIAnnotation;
308
317
  const points = interpolated3DPoints.points;
309
318
  const interpolatedAnnotation = createPolylineToolData(
310
319
  points,
311
320
  handlePoints,
312
- oldToolData
321
+ oldAnnotationData
313
322
  );
314
- // To update existing annotation, not intend to add or remove
315
- interpolatedAnnotation.annotationUID = oldToolData.annotationUID;
316
- annotationState.state.removeAnnotation(oldToolData.annotationUID);
317
- annotationState.state.addAnnotation(interpolatedAnnotation, viewport.element);
323
+ // Does a real update here instead of an add/remove, which caused delete issues in child annotations
324
+ Object.assign(oldAnnotationData, {
325
+ metadata: interpolatedAnnotation.metadata,
326
+ data: interpolatedAnnotation.data,
327
+ });
318
328
  }
319
329
 
320
330
  /**
@@ -21,7 +21,7 @@ export default function selectHandles(
21
21
  const { sources: destPoints } = handles;
22
22
  const { length, sources: sourcePoints = [] } = polyline;
23
23
  // The distance used for figuring out the local angle of a line
24
- const distance = 6;
24
+ const distance = 5;
25
25
  if (length < distance * 3) {
26
26
  return polyline.subselect(handleCount);
27
27
  }
@@ -29,8 +29,9 @@ export default function selectHandles(
29
29
  // variation between points in terms of the distance of a line angle, but
30
30
  // also not too many handles either.
31
31
  // On average, we get twice the interval between handles, so double the length here.
32
+ // Or, choose a longer interval if the handle count would have too many handles (too short an interval)
32
33
  const interval = Math.floor(
33
- Math.max((2 * length) / handleCount, distance * 5)
34
+ Math.max((2 * length) / handleCount, distance * 2)
34
35
  );
35
36
  sourcePoints.forEach(() =>
36
37
  destPoints.push(PointsManager.create3(handleCount))
@@ -0,0 +1,23 @@
1
+ import type { InterpolationROIAnnotation } from '../../../types/ToolSpecificAnnotationTypes';
2
+ import * as annotationState from '../../../stateManagement/annotation';
3
+
4
+ /**
5
+ * Updates child annotation interpolation UIDs to be the parent interpolationUID
6
+ * followed by `-{index}` where the index is the hole/child index. This causes
7
+ * child annotations to be matched positionally within the parent.
8
+ */
9
+ export default function updateChildInterpolationUID(
10
+ annotation: InterpolationROIAnnotation
11
+ ) {
12
+ const { parentAnnotationUID, annotationUID } = annotation;
13
+ if (!parentAnnotationUID) {
14
+ return annotation.interpolationUID;
15
+ }
16
+ const parentAnnotation = annotationState.state.getAnnotation(
17
+ parentAnnotationUID
18
+ ) as InterpolationROIAnnotation;
19
+ const { interpolationUID } = parentAnnotation;
20
+ const index = parentAnnotation.childAnnotationUIDs.indexOf(annotationUID);
21
+ annotation.interpolationUID = `${interpolationUID}-${index}`;
22
+ return annotation.interpolationUID;
23
+ }
@@ -209,7 +209,6 @@ export default class InterpolationManager {
209
209
  ) {
210
210
  return;
211
211
  }
212
-
213
212
  const viewport = getViewportForAnnotation(annotation);
214
213
  if (!viewport) {
215
214
  console.warn(
@@ -219,7 +218,8 @@ export default class InterpolationManager {
219
218
  return;
220
219
  }
221
220
  if (annotation.autoGenerated) {
222
- // Dont fire the annotation changed events here, as that leads to recursion.
221
+ // Dont fire the annotation changed events here, as that leads to recursion,
222
+ // although this is in fact completing the event, so trigger the segmentation add
223
223
  addContourSegmentationAnnotation(annotation);
224
224
  annotation.autoGenerated = false;
225
225
  }