@cornerstonejs/tools 1.51.4 → 1.52.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 (128) hide show
  1. package/dist/cjs/drawingSvg/drawPolyline.js +1 -1
  2. package/dist/cjs/drawingSvg/drawPolyline.js.map +1 -1
  3. package/dist/cjs/enums/ChangeTypes.d.ts +2 -1
  4. package/dist/cjs/enums/ChangeTypes.js +1 -0
  5. package/dist/cjs/enums/ChangeTypes.js.map +1 -1
  6. package/dist/cjs/eventDispatchers/keyboardEventHandlers/keyDown.js +1 -1
  7. package/dist/cjs/eventDispatchers/keyboardEventHandlers/keyDown.js.map +1 -1
  8. package/dist/cjs/stateManagement/annotation/helpers/state.d.ts +2 -1
  9. package/dist/cjs/stateManagement/annotation/helpers/state.js +2 -1
  10. package/dist/cjs/stateManagement/annotation/helpers/state.js.map +1 -1
  11. package/dist/cjs/tools/annotation/LivewireContourSegmentationTool.d.ts +4 -0
  12. package/dist/cjs/tools/annotation/LivewireContourSegmentationTool.js +82 -0
  13. package/dist/cjs/tools/annotation/LivewireContourSegmentationTool.js.map +1 -1
  14. package/dist/cjs/tools/annotation/LivewireContourTool.d.ts +10 -9
  15. package/dist/cjs/tools/annotation/LivewireContourTool.js +56 -43
  16. package/dist/cjs/tools/annotation/LivewireContourTool.js.map +1 -1
  17. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +2 -1
  18. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  19. package/dist/cjs/tools/annotation/SplineROITool.js +3 -3
  20. package/dist/cjs/tools/annotation/SplineROITool.js.map +1 -1
  21. package/dist/cjs/types/ContourSegmentationAnnotation.d.ts +8 -0
  22. package/dist/cjs/types/InterpolationTypes.d.ts +2 -0
  23. package/dist/cjs/types/ToolSpecificAnnotationTypes.d.ts +2 -5
  24. package/dist/cjs/utilities/contours/interpolation/acceptAutogeneratedInterpolations.js.map +1 -1
  25. package/dist/cjs/utilities/contours/interpolation/createPolylineToolData.js +2 -1
  26. package/dist/cjs/utilities/contours/interpolation/createPolylineToolData.js.map +1 -1
  27. package/dist/cjs/utilities/contours/interpolation/findAnnotationForInterpolation.js +2 -1
  28. package/dist/cjs/utilities/contours/interpolation/findAnnotationForInterpolation.js.map +1 -1
  29. package/dist/cjs/utilities/contours/interpolation/getInterpolationData.js +3 -1
  30. package/dist/cjs/utilities/contours/interpolation/getInterpolationData.js.map +1 -1
  31. package/dist/cjs/utilities/contours/interpolation/interpolate.d.ts +8 -0
  32. package/dist/cjs/utilities/contours/interpolation/interpolate.js +56 -42
  33. package/dist/cjs/utilities/contours/interpolation/interpolate.js.map +1 -1
  34. package/dist/cjs/utilities/contours/interpolation/selectHandles.d.ts +4 -0
  35. package/dist/cjs/utilities/contours/interpolation/selectHandles.js +170 -0
  36. package/dist/cjs/utilities/contours/interpolation/selectHandles.js.map +1 -0
  37. package/dist/cjs/utilities/livewire/LivewireScissors.d.ts +2 -1
  38. package/dist/cjs/utilities/livewire/LivewireScissors.js +46 -24
  39. package/dist/cjs/utilities/livewire/LivewireScissors.js.map +1 -1
  40. package/dist/cjs/utilities/segmentation/InterpolationManager/InterpolationManager.js +13 -3
  41. package/dist/cjs/utilities/segmentation/InterpolationManager/InterpolationManager.js.map +1 -1
  42. package/dist/esm/drawingSvg/drawPolyline.js +1 -1
  43. package/dist/esm/drawingSvg/drawPolyline.js.map +1 -1
  44. package/dist/esm/enums/ChangeTypes.js +1 -0
  45. package/dist/esm/enums/ChangeTypes.js.map +1 -1
  46. package/dist/esm/eventDispatchers/keyboardEventHandlers/keyDown.js +1 -1
  47. package/dist/esm/eventDispatchers/keyboardEventHandlers/keyDown.js.map +1 -1
  48. package/dist/esm/stateManagement/annotation/helpers/state.js +3 -2
  49. package/dist/esm/stateManagement/annotation/helpers/state.js.map +1 -1
  50. package/dist/esm/tools/annotation/LivewireContourSegmentationTool.js +81 -0
  51. package/dist/esm/tools/annotation/LivewireContourSegmentationTool.js.map +1 -1
  52. package/dist/esm/tools/annotation/LivewireContourTool.js +57 -44
  53. package/dist/esm/tools/annotation/LivewireContourTool.js.map +1 -1
  54. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +2 -1
  55. package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  56. package/dist/esm/tools/annotation/SplineROITool.js +3 -3
  57. package/dist/esm/tools/annotation/SplineROITool.js.map +1 -1
  58. package/dist/esm/utilities/contours/interpolation/acceptAutogeneratedInterpolations.js.map +1 -1
  59. package/dist/esm/utilities/contours/interpolation/createPolylineToolData.js +2 -1
  60. package/dist/esm/utilities/contours/interpolation/createPolylineToolData.js.map +1 -1
  61. package/dist/esm/utilities/contours/interpolation/findAnnotationForInterpolation.js +2 -1
  62. package/dist/esm/utilities/contours/interpolation/findAnnotationForInterpolation.js.map +1 -1
  63. package/dist/esm/utilities/contours/interpolation/getInterpolationData.js +3 -1
  64. package/dist/esm/utilities/contours/interpolation/getInterpolationData.js.map +1 -1
  65. package/dist/esm/utilities/contours/interpolation/interpolate.js +57 -43
  66. package/dist/esm/utilities/contours/interpolation/interpolate.js.map +1 -1
  67. package/dist/esm/utilities/contours/interpolation/selectHandles.js +164 -0
  68. package/dist/esm/utilities/contours/interpolation/selectHandles.js.map +1 -0
  69. package/dist/esm/utilities/livewire/LivewireScissors.js +46 -24
  70. package/dist/esm/utilities/livewire/LivewireScissors.js.map +1 -1
  71. package/dist/esm/utilities/segmentation/InterpolationManager/InterpolationManager.js +13 -3
  72. package/dist/esm/utilities/segmentation/InterpolationManager/InterpolationManager.js.map +1 -1
  73. package/dist/types/enums/ChangeTypes.d.ts +2 -1
  74. package/dist/types/enums/ChangeTypes.d.ts.map +1 -1
  75. package/dist/types/stateManagement/annotation/helpers/state.d.ts +2 -1
  76. package/dist/types/stateManagement/annotation/helpers/state.d.ts.map +1 -1
  77. package/dist/types/tools/annotation/LivewireContourSegmentationTool.d.ts +4 -0
  78. package/dist/types/tools/annotation/LivewireContourSegmentationTool.d.ts.map +1 -1
  79. package/dist/types/tools/annotation/LivewireContourTool.d.ts +10 -9
  80. package/dist/types/tools/annotation/LivewireContourTool.d.ts.map +1 -1
  81. package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
  82. package/dist/types/types/ContourSegmentationAnnotation.d.ts +8 -0
  83. package/dist/types/types/ContourSegmentationAnnotation.d.ts.map +1 -1
  84. package/dist/types/types/InterpolationTypes.d.ts +2 -0
  85. package/dist/types/types/InterpolationTypes.d.ts.map +1 -1
  86. package/dist/types/types/ToolSpecificAnnotationTypes.d.ts +2 -5
  87. package/dist/types/types/ToolSpecificAnnotationTypes.d.ts.map +1 -1
  88. package/dist/types/utilities/contours/interpolation/acceptAutogeneratedInterpolations.d.ts.map +1 -1
  89. package/dist/types/utilities/contours/interpolation/createPolylineToolData.d.ts.map +1 -1
  90. package/dist/types/utilities/contours/interpolation/findAnnotationForInterpolation.d.ts.map +1 -1
  91. package/dist/types/utilities/contours/interpolation/getInterpolationData.d.ts.map +1 -1
  92. package/dist/types/utilities/contours/interpolation/interpolate.d.ts +8 -0
  93. package/dist/types/utilities/contours/interpolation/interpolate.d.ts.map +1 -1
  94. package/dist/types/utilities/contours/interpolation/selectHandles.d.ts +5 -0
  95. package/dist/types/utilities/contours/interpolation/selectHandles.d.ts.map +1 -0
  96. package/dist/types/utilities/livewire/LivewireScissors.d.ts +2 -1
  97. package/dist/types/utilities/livewire/LivewireScissors.d.ts.map +1 -1
  98. package/dist/types/utilities/segmentation/InterpolationManager/InterpolationManager.d.ts.map +1 -1
  99. package/dist/umd/index.js +1 -1
  100. package/dist/umd/index.js.map +1 -1
  101. package/package.json +3 -3
  102. package/src/drawingSvg/drawPolyline.ts +1 -1
  103. package/src/enums/ChangeTypes.ts +4 -0
  104. package/src/eventDispatchers/keyboardEventHandlers/keyDown.ts +1 -1
  105. package/src/stateManagement/annotation/helpers/state.ts +4 -2
  106. package/src/tools/annotation/LivewireContourSegmentationTool.ts +151 -0
  107. package/src/tools/annotation/LivewireContourTool.ts +113 -82
  108. package/src/tools/annotation/PlanarFreehandROITool.ts +8 -3
  109. package/src/tools/annotation/SplineROITool.ts +3 -3
  110. package/src/types/ContourSegmentationAnnotation.ts +38 -0
  111. package/src/types/InterpolationTypes.ts +6 -0
  112. package/src/types/ToolSpecificAnnotationTypes.ts +7 -5
  113. package/src/utilities/contours/interpolation/acceptAutogeneratedInterpolations.ts +3 -1
  114. package/src/utilities/contours/interpolation/createPolylineToolData.ts +7 -1
  115. package/src/utilities/contours/interpolation/findAnnotationForInterpolation.ts +2 -1
  116. package/src/utilities/contours/interpolation/getInterpolationData.ts +3 -1
  117. package/src/utilities/contours/interpolation/interpolate.ts +94 -75
  118. package/src/utilities/contours/interpolation/selectHandles.ts +240 -0
  119. package/src/utilities/livewire/LivewireScissors.ts +65 -53
  120. package/src/utilities/segmentation/InterpolationManager/InterpolationManager.ts +39 -4
  121. package/dist/cjs/utilities/contours/PointsArray.d.ts +0 -29
  122. package/dist/cjs/utilities/contours/PointsArray.js +0 -104
  123. package/dist/cjs/utilities/contours/PointsArray.js.map +0 -1
  124. package/dist/esm/utilities/contours/PointsArray.js +0 -98
  125. package/dist/esm/utilities/contours/PointsArray.js.map +0 -1
  126. package/dist/types/utilities/contours/PointsArray.d.ts +0 -30
  127. package/dist/types/utilities/contours/PointsArray.d.ts.map +0 -1
  128. package/src/utilities/contours/PointsArray.ts +0 -165
@@ -1,4 +1,6 @@
1
+ import type { Types } from '@cornerstonejs/core';
1
2
  import { ContourAnnotation } from './ContourAnnotation';
3
+ // Import the type so it isn't recursive imports
2
4
 
3
5
  export type ContourSegmentationAnnotationData = {
4
6
  autoGenerated?: boolean;
@@ -8,7 +10,43 @@ export type ContourSegmentationAnnotationData = {
8
10
  segmentIndex: number;
9
11
  segmentationRepresentationUID: string;
10
12
  };
13
+ contour: {
14
+ /** The original polyline before livewire, to show comparison with
15
+ * regenerated data (eg based on spline or livewire changes).
16
+ */
17
+ originalPolyline?: Types.Point3[];
18
+ };
19
+ };
20
+ handles: {
21
+ /**
22
+ * Segmentation contours can be interpolated between slices to produce
23
+ * intermediate data. The interpolation sources are source data for
24
+ * the interpolation corresponding to the handle points. The object
25
+ * will have the kIndex assigned so that one can determine relative slice
26
+ * locations that the handles are in originally.
27
+ *
28
+ * This does NOT necessarily correspond to the handles used on the original
29
+ * source data, but is the set of point uses to interpolate the current handles.
30
+ * That is, for linear interpolation:
31
+ * ```
32
+ * handles.points[i] = linear(interpolationSources[0].getPoint(i),
33
+ * interpolationSources[1].getPoint(i));
34
+ * ```
35
+ *
36
+ * These are sometimes required for things like livewire which need to
37
+ * update the handle position with a snap to nearest live point or can
38
+ * be used as an indicator that interpolation has taken place.
39
+ */
40
+ interpolationSources?: Types.PointsManager<Types.Point3>[];
11
41
  };
42
+
43
+ /**
44
+ * This is called when interpolation is performed, and can be used to add
45
+ * data specific settings to the annotation instance.
46
+ */
47
+ onInterpolationComplete?: (
48
+ annotation: ContourSegmentationAnnotation
49
+ ) => unknown;
12
50
  };
13
51
 
14
52
  export type ContourSegmentationAnnotation = ContourAnnotation &
@@ -14,6 +14,8 @@ export type InterpolationViewportData = {
14
14
  /** The viewport that this interpolation is occurring within */
15
15
  viewport: Types.IViewport;
16
16
  sliceData: Types.ImageSliceData;
17
+ /** True if the interpolation data is being regenerated because of an update */
18
+ isInterpolationUpdate?: boolean;
17
19
  };
18
20
 
19
21
  export type ImageInterpolationData = {
@@ -39,4 +41,8 @@ export type AcceptInterpolationSelector = {
39
41
  * Applies just to the given segment index.
40
42
  */
41
43
  segmentIndex?: number;
44
+ /**
45
+ * Only apply to the given slice index
46
+ */
47
+ sliceIndex?: number;
42
48
  };
@@ -141,11 +141,7 @@ export type SplineROIAnnotation = ContourAnnotation & {
141
141
  export type SplineContourSegmentationAnnotation = SplineROIAnnotation &
142
142
  ContourSegmentationAnnotationData;
143
143
 
144
- export type LivewireContourAnnotation = ContourAnnotation & {
145
- data: {
146
- label?: string;
147
- };
148
- };
144
+ export type LivewireContourAnnotation = ContourAnnotation;
149
145
 
150
146
  export type LivewireContourSegmentationAnnotation = LivewireContourAnnotation &
151
147
  ContourSegmentationAnnotationData;
@@ -277,6 +273,12 @@ export type InterpolationROIAnnotation = ContourAnnotation & {
277
273
  referencedSliceIndex?: number;
278
274
  };
279
275
  interpolationUID?: string;
276
+ /**
277
+ * A flag to track updates to annotations caused by things like
278
+ * spline or livewire regeenration of the data, and which should cause further
279
+ * updates to occur (or not as the tool decides).
280
+ */
281
+ isInterpolationUpdate?: boolean;
280
282
  };
281
283
 
282
284
  export interface ArrowAnnotation extends Annotation {
@@ -1,3 +1,5 @@
1
+ import { getEnabledElement } from '@cornerstonejs/core';
2
+
1
3
  import InterpolationManager from '../../segmentation/InterpolationManager/InterpolationManager';
2
4
  import type { AcceptInterpolationSelector } from '../../../types/InterpolationTypes';
3
5
  import type AnnotationGroupSelector from '../../../types/AnnotationGroupSelector';
@@ -5,7 +7,7 @@ import type AnnotationGroupSelector from '../../../types/AnnotationGroupSelector
5
7
  /**
6
8
  * Accepts interpolated annotations, marking them as autoGenerated false.
7
9
  *
8
- * @param annotationGroupSelector - viewport or FOR to select annotations for
10
+ * @param annotationGroupSelector - viewport or FOR to select annotations on
9
11
  * @param selector - nested selection criteria
10
12
  */
11
13
  export default function acceptAutogeneratedInterpolations(
@@ -33,7 +33,13 @@ export default function createPolylineToolData(
33
33
  });
34
34
  Object.assign(annotation.data, {
35
35
  handles: {
36
- points: handlePoints || [],
36
+ points: handlePoints.points || handlePoints || [],
37
+ /**
38
+ * The interpolation sources contains the source points used for interpolating
39
+ * to generate the new handles. This allows performing other types of
40
+ * interpolation to generate the new handles, such as livewire.
41
+ */
42
+ interpolationSources: handlePoints.sources,
37
43
  activeHandleIndex: null,
38
44
  textBox: {
39
45
  hasMoved: false,
@@ -129,7 +129,8 @@ function _sliceNeedsInterpolating(
129
129
  ): boolean {
130
130
  const annotations = interpolationData.get(sliceIndex);
131
131
  return (
132
- !annotations || (annotations.length === 1 && annotations[0].autoGenerated)
132
+ !annotations?.length ||
133
+ (annotations.length === 1 && annotations[0].autoGenerated)
133
134
  );
134
135
  }
135
136
 
@@ -68,7 +68,9 @@ export default function getInterpolationData(
68
68
  }
69
69
  );
70
70
 
71
- interpolationDatas.set(i, filteredInterpolatedAnnotations);
71
+ if (filteredInterpolatedAnnotations.length) {
72
+ interpolationDatas.set(i, filteredInterpolatedAnnotations);
73
+ }
72
74
  }
73
75
 
74
76
  return interpolationDatas;
@@ -1,4 +1,4 @@
1
- import { triggerEvent } from '@cornerstonejs/core';
1
+ import { triggerEvent, utilities } from '@cornerstonejs/core';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
  import { vec3 } from 'gl-matrix';
4
4
 
@@ -9,13 +9,20 @@ import type { InterpolationROIAnnotation } from '../../../types/ToolSpecificAnno
9
9
  import type { AnnotationInterpolationCompletedEventDetail } from '../../../types/EventTypes';
10
10
  import EventTypes from '../../../enums/Events';
11
11
  import * as annotationState from '../../../stateManagement/annotation';
12
- import { PointsArray } from '../PointsArray';
12
+ import selectHandles from './selectHandles';
13
+
14
+ const { PointsManager } = utilities;
13
15
 
14
16
  /**
15
17
  * An XYZ encoded points that also includes an indicator I for whether the
16
18
  * point is included in the original contour.
17
19
  */
18
- type PointsXYZI = Types.PointsXYZ & {
20
+ export type PointsXYZI = Types.PointsXYZ & {
21
+ I?: boolean[];
22
+ kIndex?: number;
23
+ };
24
+
25
+ export type PointsArray3 = Types.PointsManager<Types.Point3> & {
19
26
  I?: boolean[];
20
27
  };
21
28
 
@@ -25,7 +32,13 @@ let interpolating = false;
25
32
 
26
33
  /**
27
34
  * interpolate - Interpolate missing contours in the ROIContours.
28
- * If input is tool data collection, it is expected to be sorted in the order of stack image in which it was drawn
35
+ * If input is tool data collection, it is expected to be sorted in the order
36
+ * of stack image in which it was drawn.
37
+ *
38
+ * This is performed in a microtask in order to avoid delaying the event handler
39
+ * excessively, but to ensure it is completed before the data is additionally
40
+ * changed. It was originally done in a setTimeout, but that allowed the data
41
+ * to be updated between calls, causing issues with the interpolation process.
29
42
  *
30
43
  * @param viewportData - Object
31
44
  * @returns null
@@ -35,11 +48,24 @@ function interpolate(viewportData: InterpolationViewportData) {
35
48
  return;
36
49
  }
37
50
  interpolating = true;
38
- try {
39
- startInterpolation(viewportData);
40
- } finally {
41
- interpolating = false;
42
- }
51
+ const { isInterpolationUpdate, annotation } = viewportData;
52
+ queueMicrotask(() => {
53
+ try {
54
+ if (isInterpolationUpdate) {
55
+ annotation.isInterpolationUpdate = true;
56
+ // This may not be true long term, but treat it as user generated for
57
+ // this run.
58
+ annotation.autoGenerated = false;
59
+ }
60
+ startInterpolation(viewportData);
61
+ } finally {
62
+ interpolating = false;
63
+ if (isInterpolationUpdate) {
64
+ // Reset the auto generated flag
65
+ annotation.autoGenerated = true;
66
+ }
67
+ }
68
+ });
43
69
  }
44
70
 
45
71
  /**
@@ -111,6 +137,8 @@ function _linearlyInterpolateBetween(
111
137
  );
112
138
 
113
139
  const { c1Interp, c2Interp } = _generateInterpolationContourPair(c1, c2);
140
+ c1Interp.kIndex = annotationPair[0];
141
+ c2Interp.kIndex = annotationPair[1];
114
142
 
115
143
  // Using the newly constructed contours, interpolate each ROI.
116
144
  indices.forEach(function (index) {
@@ -126,6 +154,16 @@ function _linearlyInterpolateBetween(
126
154
  });
127
155
  }
128
156
 
157
+ function getPointCount(pointArray) {
158
+ let sum = 0;
159
+ for (let i = 0; i < pointArray.I.length; i++) {
160
+ if (pointArray.I[i]) {
161
+ sum++;
162
+ }
163
+ }
164
+ return sum;
165
+ }
166
+
129
167
  /**
130
168
  * _linearlyInterpolateContour - Inserts a linearly interpolated contour at
131
169
  * specified slice index.
@@ -133,7 +171,7 @@ function _linearlyInterpolateBetween(
133
171
  * @param c1Interp - object, The first reference contour.
134
172
  * @param c2Interp - object, The second reference contour.
135
173
  * @param sliceIndex - Number, The slice index to interpolate.
136
- * @param annotationPair - Number[], The slice indicies of the reference contours.
174
+ * @param annotationPair - Number[], The slice indices of the reference contours.
137
175
  * @param interpolationData - object[], Data for the slice location of contours
138
176
  * for the ROIContour.
139
177
  * @param c1HasMoreNodes - boolean, True if c1 has more nodes than c2.
@@ -162,17 +200,7 @@ function _linearlyInterpolateContour(
162
200
  annotationPair[zInterp > 0.5 ? 1 : 0]
163
201
  )[0];
164
202
 
165
- // A bit adhoc figuring out how many handles to use, but this seems to generate
166
- // enough handles for use.
167
- const handleCount = Math.round(
168
- Math.max(
169
- 8,
170
- interpolationData.get(startIndex)[0].data.handles.points.length,
171
- interpolationData.get(endIndex)[0].data.handles.points.length,
172
- interpolated3DPoints.x.length / 50
173
- )
174
- );
175
- const handlePoints = _subselect(interpolated3DPoints, handleCount);
203
+ const handlePoints = selectHandles(interpolated3DPoints);
176
204
 
177
205
  if (interpolationData.has(sliceIndex)) {
178
206
  _editInterpolatedContour(
@@ -193,25 +221,6 @@ function _linearlyInterpolateContour(
193
221
  }
194
222
  }
195
223
 
196
- function _subselect(points, count = 10) {
197
- const handles = [];
198
- const { length } = points.x;
199
- if (!length) {
200
- return handles;
201
- }
202
- for (let i = 0; i < count; i++) {
203
- const handleIndex = Math.floor((length * i) / count);
204
- handles.push(
205
- vec3.fromValues(
206
- points.x[handleIndex],
207
- points.y[handleIndex],
208
- points.z[handleIndex]
209
- )
210
- );
211
- }
212
- return handles;
213
- }
214
-
215
224
  /**
216
225
  * _addInterpolatedContour - Adds a new contour to the imageId.
217
226
  *
@@ -223,13 +232,13 @@ function _subselect(points, count = 10) {
223
232
  * @returns null
224
233
  */
225
234
  function _addInterpolatedContour(
226
- interpolated3DPoints: Types.PointsXYZ,
227
- handlePoints: Types.Point3[],
235
+ interpolated3DPoints: PointsArray3,
236
+ handlePoints: PointsArray3,
228
237
  sliceIndex: number,
229
238
  referencedToolData,
230
239
  eventData
231
240
  ) {
232
- const points = PointsArray.fromXYZ(interpolated3DPoints).points;
241
+ const points = interpolated3DPoints.points;
233
242
  const { viewport } = eventData;
234
243
 
235
244
  const interpolatedAnnotation = createPolylineToolData(
@@ -242,7 +251,7 @@ function _addInterpolatedContour(
242
251
  interpolatedAnnotation.metadata.referencedImageId = targetId;
243
252
  interpolatedAnnotation.metadata.referencedSliceIndex = sliceIndex;
244
253
  annotationState.state.addAnnotation(interpolatedAnnotation, viewport.element);
245
- referencedToolData.postInterpolateAction?.(
254
+ referencedToolData.onInterpolationComplete?.(
246
255
  interpolatedAnnotation,
247
256
  referencedToolData
248
257
  );
@@ -260,8 +269,8 @@ function _addInterpolatedContour(
260
269
  * @returns null
261
270
  */
262
271
  function _editInterpolatedContour(
263
- interpolated3DPoints: Types.PointsXYZ,
264
- handlePoints: Types.Point3[],
272
+ interpolated3DPoints: PointsArray3,
273
+ handlePoints: PointsArray3,
265
274
  sliceIndex,
266
275
  referencedToolData,
267
276
  eventData
@@ -296,7 +305,7 @@ function _editInterpolatedContour(
296
305
  }
297
306
 
298
307
  const oldToolData = annotations[toolDataIndex] as InterpolationROIAnnotation;
299
- const points = PointsArray.fromXYZ(interpolated3DPoints).points;
308
+ const points = interpolated3DPoints.points;
300
309
  const interpolatedAnnotation = createPolylineToolData(
301
310
  points,
302
311
  handlePoints,
@@ -327,22 +336,39 @@ function _generateInterpolatedOpenContour(
327
336
  c2ir,
328
337
  zInterp,
329
338
  c1HasMoreNodes
330
- ): PointsXYZI {
331
- const cInterp = {
332
- x: [],
333
- y: [],
334
- z: [],
335
- };
336
-
339
+ ): PointsArray3 {
337
340
  const indices = c1HasMoreNodes ? c1ir.I : c2ir.I;
338
341
 
342
+ const c1 = PointsManager.fromXYZ(c1ir);
343
+ const c2 = PointsManager.fromXYZ(c2ir);
344
+ const { length } = c1;
345
+ const cInterp = PointsManager.create3(length) as PointsArray3;
346
+
347
+ const vecSubtract = vec3.create();
348
+ const vecResult = vec3.create();
349
+ const c1Source = PointsManager.create3(length);
350
+ c1Source.kIndex = c1ir.kIndex;
351
+ const c2Source = PointsManager.create3(length);
352
+ c2Source.kIndex = c2ir.kIndex;
353
+
339
354
  for (let i = 0; i < c1ir.x.length; i++) {
340
355
  if (indices[i]) {
341
- cInterp.x.push(c1ir.x[i] + (c2ir.x[i] - c1ir.x[i]) * zInterp);
342
- cInterp.y.push(c1ir.y[i] + (c2ir.y[i] - c1ir.y[i]) * zInterp);
343
- cInterp.z.push(c1ir.z[i] + (c2ir.z[i] - c1ir.z[i]) * zInterp);
356
+ const c1point = c1.getPoint(i);
357
+ const c2point = c2.getPoint(i);
358
+ c1Source.push(c1point);
359
+ c2Source.push(c2point);
360
+ vec3.sub(vecSubtract, c2point, c1point);
361
+ cInterp.push(
362
+ vec3.scaleAndAdd(
363
+ vecResult,
364
+ c1point,
365
+ vecSubtract,
366
+ zInterp
367
+ ) as Types.Point3
368
+ );
344
369
  }
345
370
  }
371
+ cInterp.sources = [c1Source, c2Source];
346
372
 
347
373
  return cInterp;
348
374
  }
@@ -370,12 +396,12 @@ function _generateInterpolationContourPair(c1, c2) {
370
396
  const numNodes1 = interpNodes + c2.x.length;
371
397
  const numNodes2 = interpNodes + c1.x.length;
372
398
 
373
- // concatinate p && cumPerimNorm
399
+ // concatenate p && cumPerimNorm
374
400
  const perim1Interp = _getInterpolatedPerim(numNodes1, cumPerim1Norm);
375
401
  const perim2Interp = _getInterpolatedPerim(numNodes2, cumPerim2Norm);
376
402
 
377
- const perim1Ind = _getIndicatorArray(c1, numNodes1);
378
- const perim2Ind = _getIndicatorArray(c2, numNodes2);
403
+ const perim1Ind = _getIndicatorArray(numNodes1 - 2, c1.x.length);
404
+ const perim2Ind = _getIndicatorArray(numNodes2 - 2, c2.x.length);
379
405
 
380
406
  const nodesPerSegment1 = _getNodesPerSegment(perim1Interp, perim1Ind);
381
407
  const nodesPerSegment2 = _getNodesPerSegment(perim2Interp, perim2Ind);
@@ -398,13 +424,13 @@ function _generateInterpolationContourPair(c1, c2) {
398
424
  * @returns An object containing the two reduced contours.
399
425
  */
400
426
  function _reduceContoursToOriginNodes(c1i: PointsXYZI, c2i: PointsXYZI) {
401
- const c1Interp = {
427
+ const c1Interp: PointsXYZI = {
402
428
  x: [],
403
429
  y: [],
404
430
  z: [],
405
431
  I: [],
406
432
  };
407
- const c2Interp = {
433
+ const c2Interp: PointsXYZI = {
408
434
  x: [],
409
435
  y: [],
410
436
  z: [],
@@ -505,7 +531,7 @@ function _shiftCircularArray(arr, count) {
505
531
  * per line segment.
506
532
  * @returns object, The super sampled contour.
507
533
  */
508
- function _getSuperSampledContour(c, nodesPerSegment) {
534
+ function _getSuperSampledContour(c, nodesPerSegment): PointsXYZI {
509
535
  const ci = {
510
536
  x: [],
511
537
  y: [],
@@ -593,17 +619,10 @@ function _getNodesPerSegment(perimInterp, perimInd) {
593
619
  * @param numNodes - Number, The number of nodes added.
594
620
  * @returns boolean[], The indicator array of original node locations.
595
621
  */
596
- function _getIndicatorArray(contour, numNodes) {
597
- const perimInd = [];
598
-
599
- for (let i = 0; i < numNodes - 2; i++) {
600
- perimInd.push(false);
601
- }
602
-
603
- for (let i = 0; i < contour.x.length; i++) {
604
- perimInd.push(true);
605
- }
606
-
622
+ function _getIndicatorArray(numFalse, numTrue) {
623
+ const perimInd = new Array(numFalse + numTrue);
624
+ perimInd.fill(false, 0, numFalse);
625
+ perimInd.fill(true, numFalse, numFalse + numTrue);
607
626
  return perimInd;
608
627
  }
609
628
 
@@ -619,7 +638,7 @@ function _getInterpolatedPerim(numNodes, cumPerimNorm) {
619
638
  const diff = 1 / (numNodes - 1);
620
639
  const linspace = [diff];
621
640
 
622
- // Length - 2 as we are discarding 0 an 1 for efficiency (no need to calculate them).
641
+ // Length - 2 as we are discarding 0 and 1 for efficiency (no need to calculate them).
623
642
  for (let i = 1; i < numNodes - 2; i++) {
624
643
  linspace.push(linspace[linspace.length - 1] + diff);
625
644
  }