@cornerstonejs/tools 1.52.0 → 1.53.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 (251) hide show
  1. package/dist/cjs/drawingSvg/drawPath.d.ts +11 -0
  2. package/dist/cjs/drawingSvg/drawPath.js +55 -0
  3. package/dist/cjs/drawingSvg/drawPath.js.map +1 -0
  4. package/dist/cjs/drawingSvg/drawPolyline.d.ts +1 -1
  5. package/dist/cjs/drawingSvg/drawPolyline.js +2 -10
  6. package/dist/cjs/drawingSvg/drawPolyline.js.map +1 -1
  7. package/dist/cjs/drawingSvg/index.d.ts +2 -1
  8. package/dist/cjs/drawingSvg/index.js +3 -1
  9. package/dist/cjs/drawingSvg/index.js.map +1 -1
  10. package/dist/cjs/eventDispatchers/shared/getActiveToolForMouseEvent.js.map +1 -1
  11. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts +1 -1
  12. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +165 -78
  13. package/dist/cjs/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
  14. package/dist/cjs/stateManagement/annotation/annotationState.d.ts +6 -1
  15. package/dist/cjs/stateManagement/annotation/annotationState.js +49 -1
  16. package/dist/cjs/stateManagement/annotation/annotationState.js.map +1 -1
  17. package/dist/cjs/stateManagement/annotation/helpers/state.d.ts +2 -1
  18. package/dist/cjs/stateManagement/annotation/helpers/state.js +14 -3
  19. package/dist/cjs/stateManagement/annotation/helpers/state.js.map +1 -1
  20. package/dist/cjs/stateManagement/index.d.ts +6 -1
  21. package/dist/cjs/stateManagement/index.js +6 -1
  22. package/dist/cjs/stateManagement/index.js.map +1 -1
  23. package/dist/cjs/store/ToolGroupManager/ToolGroup.d.ts +3 -1
  24. package/dist/cjs/store/ToolGroupManager/ToolGroup.js +3 -2
  25. package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
  26. package/dist/cjs/tools/SegmentationIntersectionTool.js +1 -1
  27. package/dist/cjs/tools/SegmentationIntersectionTool.js.map +1 -1
  28. package/dist/cjs/tools/annotation/LivewireContourSegmentationTool.js +1 -1
  29. package/dist/cjs/tools/annotation/LivewireContourSegmentationTool.js.map +1 -1
  30. package/dist/cjs/tools/annotation/LivewireContourTool.d.ts +4 -3
  31. package/dist/cjs/tools/annotation/LivewireContourTool.js +26 -26
  32. package/dist/cjs/tools/annotation/LivewireContourTool.js.map +1 -1
  33. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +1 -0
  34. package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  35. package/dist/cjs/tools/annotation/SplineROITool.d.ts +6 -3
  36. package/dist/cjs/tools/annotation/SplineROITool.js +37 -18
  37. package/dist/cjs/tools/annotation/SplineROITool.js.map +1 -1
  38. package/dist/cjs/tools/annotation/planarFreehandROITool/closedContourEditLoop.js +12 -7
  39. package/dist/cjs/tools/annotation/planarFreehandROITool/closedContourEditLoop.js.map +1 -1
  40. package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js +24 -18
  41. package/dist/cjs/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
  42. package/dist/cjs/tools/annotation/planarFreehandROITool/openContourEditLoop.js +16 -10
  43. package/dist/cjs/tools/annotation/planarFreehandROITool/openContourEditLoop.js.map +1 -1
  44. package/dist/cjs/tools/annotation/planarFreehandROITool/renderMethods.js +19 -7
  45. package/dist/cjs/tools/annotation/planarFreehandROITool/renderMethods.js.map +1 -1
  46. package/dist/cjs/tools/annotation/splines/LinearSpline.js +1 -1
  47. package/dist/cjs/tools/annotation/splines/LinearSpline.js.map +1 -1
  48. package/dist/cjs/tools/annotation/splines/Spline.d.ts +2 -0
  49. package/dist/cjs/tools/annotation/splines/Spline.js +7 -3
  50. package/dist/cjs/tools/annotation/splines/Spline.js.map +1 -1
  51. package/dist/cjs/tools/base/AnnotationTool.js.map +1 -1
  52. package/dist/cjs/tools/base/ContourBaseTool.d.ts +1 -0
  53. package/dist/cjs/tools/base/ContourBaseTool.js +18 -1
  54. package/dist/cjs/tools/base/ContourBaseTool.js.map +1 -1
  55. package/dist/cjs/tools/base/ContourSegmentationBaseTool.js +4 -0
  56. package/dist/cjs/tools/base/ContourSegmentationBaseTool.js.map +1 -1
  57. package/dist/cjs/tools/displayTools/Contour/contourConfig.js +1 -0
  58. package/dist/cjs/tools/displayTools/Contour/contourConfig.js.map +1 -1
  59. package/dist/cjs/types/AnnotationTypes.d.ts +2 -0
  60. package/dist/cjs/types/ContourAnnotation.d.ts +6 -0
  61. package/dist/cjs/types/ContourAnnotation.js +7 -0
  62. package/dist/cjs/types/ContourAnnotation.js.map +1 -1
  63. package/dist/cjs/types/ContourTypes.d.ts +1 -0
  64. package/dist/cjs/types/EventTypes.d.ts +4 -1
  65. package/dist/cjs/types/ISpline.d.ts +1 -0
  66. package/dist/cjs/types/SplineProps.d.ts +1 -0
  67. package/dist/cjs/utilities/contours/getContourHolesDataCanvas.d.ts +3 -0
  68. package/dist/cjs/utilities/contours/getContourHolesDataCanvas.js +21 -0
  69. package/dist/cjs/utilities/contours/getContourHolesDataCanvas.js.map +1 -0
  70. package/dist/cjs/utilities/contours/getContourHolesDataWorld.d.ts +3 -0
  71. package/dist/cjs/utilities/contours/getContourHolesDataWorld.js +10 -0
  72. package/dist/cjs/utilities/contours/getContourHolesDataWorld.js.map +1 -0
  73. package/dist/cjs/utilities/contours/index.d.ts +4 -1
  74. package/dist/cjs/utilities/contours/index.js +7 -1
  75. package/dist/cjs/utilities/contours/index.js.map +1 -1
  76. package/dist/cjs/utilities/contours/updateContourPolyline.d.ts +10 -0
  77. package/dist/cjs/utilities/contours/updateContourPolyline.js +64 -0
  78. package/dist/cjs/utilities/contours/updateContourPolyline.js.map +1 -0
  79. package/dist/cjs/utilities/math/polyline/containsPoints.d.ts +2 -0
  80. package/dist/cjs/utilities/math/polyline/containsPoints.js +16 -0
  81. package/dist/cjs/utilities/math/polyline/containsPoints.js.map +1 -0
  82. package/dist/cjs/utilities/math/polyline/getWindingDirection.d.ts +2 -0
  83. package/dist/cjs/utilities/math/polyline/getWindingDirection.js +12 -0
  84. package/dist/cjs/utilities/math/polyline/getWindingDirection.js.map +1 -0
  85. package/dist/cjs/utilities/math/polyline/index.d.ts +3 -1
  86. package/dist/cjs/utilities/math/polyline/index.js +5 -1
  87. package/dist/cjs/utilities/math/polyline/index.js.map +1 -1
  88. package/dist/cjs/utilities/math/polyline/planarFreehandROIInternalTypes.d.ts +1 -0
  89. package/dist/esm/drawingSvg/drawPath.js +49 -0
  90. package/dist/esm/drawingSvg/drawPath.js.map +1 -0
  91. package/dist/esm/drawingSvg/drawPolyline.js +2 -10
  92. package/dist/esm/drawingSvg/drawPolyline.js.map +1 -1
  93. package/dist/esm/drawingSvg/index.js +2 -1
  94. package/dist/esm/drawingSvg/index.js.map +1 -1
  95. package/dist/esm/eventDispatchers/shared/getActiveToolForMouseEvent.js.map +1 -1
  96. package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js +106 -32
  97. package/dist/esm/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.js.map +1 -1
  98. package/dist/esm/stateManagement/annotation/annotationState.js +42 -1
  99. package/dist/esm/stateManagement/annotation/annotationState.js.map +1 -1
  100. package/dist/esm/stateManagement/annotation/helpers/state.js +12 -2
  101. package/dist/esm/stateManagement/annotation/helpers/state.js.map +1 -1
  102. package/dist/esm/stateManagement/index.js +2 -2
  103. package/dist/esm/stateManagement/index.js.map +1 -1
  104. package/dist/esm/store/ToolGroupManager/ToolGroup.js +3 -2
  105. package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
  106. package/dist/esm/tools/SegmentationIntersectionTool.js +1 -1
  107. package/dist/esm/tools/SegmentationIntersectionTool.js.map +1 -1
  108. package/dist/esm/tools/annotation/LivewireContourSegmentationTool.js +1 -1
  109. package/dist/esm/tools/annotation/LivewireContourSegmentationTool.js.map +1 -1
  110. package/dist/esm/tools/annotation/LivewireContourTool.js +28 -28
  111. package/dist/esm/tools/annotation/LivewireContourTool.js.map +1 -1
  112. package/dist/esm/tools/annotation/PlanarFreehandROITool.js +2 -1
  113. package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
  114. package/dist/esm/tools/annotation/SplineROITool.js +37 -19
  115. package/dist/esm/tools/annotation/SplineROITool.js.map +1 -1
  116. package/dist/esm/tools/annotation/planarFreehandROITool/closedContourEditLoop.js +12 -7
  117. package/dist/esm/tools/annotation/planarFreehandROITool/closedContourEditLoop.js.map +1 -1
  118. package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js +25 -19
  119. package/dist/esm/tools/annotation/planarFreehandROITool/drawLoop.js.map +1 -1
  120. package/dist/esm/tools/annotation/planarFreehandROITool/openContourEditLoop.js +16 -10
  121. package/dist/esm/tools/annotation/planarFreehandROITool/openContourEditLoop.js.map +1 -1
  122. package/dist/esm/tools/annotation/planarFreehandROITool/renderMethods.js +20 -8
  123. package/dist/esm/tools/annotation/planarFreehandROITool/renderMethods.js.map +1 -1
  124. package/dist/esm/tools/annotation/splines/LinearSpline.js +1 -1
  125. package/dist/esm/tools/annotation/splines/LinearSpline.js.map +1 -1
  126. package/dist/esm/tools/annotation/splines/Spline.js +5 -1
  127. package/dist/esm/tools/annotation/splines/Spline.js.map +1 -1
  128. package/dist/esm/tools/base/AnnotationTool.js.map +1 -1
  129. package/dist/esm/tools/base/ContourBaseTool.js +20 -3
  130. package/dist/esm/tools/base/ContourBaseTool.js.map +1 -1
  131. package/dist/esm/tools/base/ContourSegmentationBaseTool.js +4 -0
  132. package/dist/esm/tools/base/ContourSegmentationBaseTool.js.map +1 -1
  133. package/dist/esm/tools/displayTools/Contour/contourConfig.js +1 -0
  134. package/dist/esm/tools/displayTools/Contour/contourConfig.js.map +1 -1
  135. package/dist/esm/types/ContourAnnotation.js +6 -1
  136. package/dist/esm/types/ContourAnnotation.js.map +1 -1
  137. package/dist/esm/utilities/contours/getContourHolesDataCanvas.js +15 -0
  138. package/dist/esm/utilities/contours/getContourHolesDataCanvas.js.map +1 -0
  139. package/dist/esm/utilities/contours/getContourHolesDataWorld.js +6 -0
  140. package/dist/esm/utilities/contours/getContourHolesDataWorld.js.map +1 -0
  141. package/dist/esm/utilities/contours/index.js +4 -1
  142. package/dist/esm/utilities/contours/index.js.map +1 -1
  143. package/dist/esm/utilities/contours/updateContourPolyline.js +38 -0
  144. package/dist/esm/utilities/contours/updateContourPolyline.js.map +1 -0
  145. package/dist/esm/utilities/math/polyline/containsPoints.js +10 -0
  146. package/dist/esm/utilities/math/polyline/containsPoints.js.map +1 -0
  147. package/dist/esm/utilities/math/polyline/getWindingDirection.js +6 -0
  148. package/dist/esm/utilities/math/polyline/getWindingDirection.js.map +1 -0
  149. package/dist/esm/utilities/math/polyline/index.js +3 -1
  150. package/dist/esm/utilities/math/polyline/index.js.map +1 -1
  151. package/dist/types/drawingSvg/drawPath.d.ts +12 -0
  152. package/dist/types/drawingSvg/drawPath.d.ts.map +1 -0
  153. package/dist/types/drawingSvg/drawPolyline.d.ts +1 -1
  154. package/dist/types/drawingSvg/drawPolyline.d.ts.map +1 -1
  155. package/dist/types/drawingSvg/index.d.ts +2 -1
  156. package/dist/types/drawingSvg/index.d.ts.map +1 -1
  157. package/dist/types/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts +1 -1
  158. package/dist/types/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.d.ts.map +1 -1
  159. package/dist/types/stateManagement/annotation/annotationState.d.ts +6 -1
  160. package/dist/types/stateManagement/annotation/annotationState.d.ts.map +1 -1
  161. package/dist/types/stateManagement/annotation/helpers/state.d.ts +2 -1
  162. package/dist/types/stateManagement/annotation/helpers/state.d.ts.map +1 -1
  163. package/dist/types/stateManagement/index.d.ts +6 -1
  164. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts +3 -1
  165. package/dist/types/store/ToolGroupManager/ToolGroup.d.ts.map +1 -1
  166. package/dist/types/tools/annotation/LivewireContourTool.d.ts +4 -3
  167. package/dist/types/tools/annotation/LivewireContourTool.d.ts.map +1 -1
  168. package/dist/types/tools/annotation/PlanarFreehandROITool.d.ts.map +1 -1
  169. package/dist/types/tools/annotation/SplineROITool.d.ts +6 -3
  170. package/dist/types/tools/annotation/SplineROITool.d.ts.map +1 -1
  171. package/dist/types/tools/annotation/planarFreehandROITool/closedContourEditLoop.d.ts.map +1 -1
  172. package/dist/types/tools/annotation/planarFreehandROITool/drawLoop.d.ts.map +1 -1
  173. package/dist/types/tools/annotation/planarFreehandROITool/openContourEditLoop.d.ts.map +1 -1
  174. package/dist/types/tools/annotation/planarFreehandROITool/renderMethods.d.ts.map +1 -1
  175. package/dist/types/tools/annotation/splines/Spline.d.ts +2 -0
  176. package/dist/types/tools/annotation/splines/Spline.d.ts.map +1 -1
  177. package/dist/types/tools/base/AnnotationTool.d.ts.map +1 -1
  178. package/dist/types/tools/base/ContourBaseTool.d.ts +1 -0
  179. package/dist/types/tools/base/ContourBaseTool.d.ts.map +1 -1
  180. package/dist/types/tools/base/ContourSegmentationBaseTool.d.ts.map +1 -1
  181. package/dist/types/tools/displayTools/Contour/contourConfig.d.ts.map +1 -1
  182. package/dist/types/types/AnnotationTypes.d.ts +2 -0
  183. package/dist/types/types/AnnotationTypes.d.ts.map +1 -1
  184. package/dist/types/types/ContourAnnotation.d.ts +6 -0
  185. package/dist/types/types/ContourAnnotation.d.ts.map +1 -1
  186. package/dist/types/types/ContourTypes.d.ts +1 -0
  187. package/dist/types/types/ContourTypes.d.ts.map +1 -1
  188. package/dist/types/types/EventTypes.d.ts +4 -1
  189. package/dist/types/types/EventTypes.d.ts.map +1 -1
  190. package/dist/types/types/ISpline.d.ts +1 -0
  191. package/dist/types/types/ISpline.d.ts.map +1 -1
  192. package/dist/types/types/SplineProps.d.ts +1 -0
  193. package/dist/types/types/SplineProps.d.ts.map +1 -1
  194. package/dist/types/utilities/contours/getContourHolesDataCanvas.d.ts +4 -0
  195. package/dist/types/utilities/contours/getContourHolesDataCanvas.d.ts.map +1 -0
  196. package/dist/types/utilities/contours/getContourHolesDataWorld.d.ts +4 -0
  197. package/dist/types/utilities/contours/getContourHolesDataWorld.d.ts.map +1 -0
  198. package/dist/types/utilities/contours/index.d.ts +4 -1
  199. package/dist/types/utilities/contours/index.d.ts.map +1 -1
  200. package/dist/types/utilities/contours/updateContourPolyline.d.ts +11 -0
  201. package/dist/types/utilities/contours/updateContourPolyline.d.ts.map +1 -0
  202. package/dist/types/utilities/math/polyline/containsPoints.d.ts +3 -0
  203. package/dist/types/utilities/math/polyline/containsPoints.d.ts.map +1 -0
  204. package/dist/types/utilities/math/polyline/getWindingDirection.d.ts +3 -0
  205. package/dist/types/utilities/math/polyline/getWindingDirection.d.ts.map +1 -0
  206. package/dist/types/utilities/math/polyline/index.d.ts +3 -1
  207. package/dist/types/utilities/math/polyline/index.d.ts.map +1 -1
  208. package/dist/types/utilities/math/polyline/planarFreehandROIInternalTypes.d.ts +1 -0
  209. package/dist/types/utilities/math/polyline/planarFreehandROIInternalTypes.d.ts.map +1 -1
  210. package/dist/umd/index.js +1 -1
  211. package/dist/umd/index.js.map +1 -1
  212. package/package.json +3 -3
  213. package/src/drawingSvg/drawPath.ts +96 -0
  214. package/src/drawingSvg/drawPolyline.ts +12 -16
  215. package/src/drawingSvg/index.ts +2 -0
  216. package/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts +1 -1
  217. package/src/eventListeners/annotations/contourSegmentation/contourSegmentationCompleted.ts +194 -58
  218. package/src/stateManagement/annotation/annotationState.ts +101 -0
  219. package/src/stateManagement/annotation/helpers/state.ts +29 -1
  220. package/src/stateManagement/index.js +10 -0
  221. package/src/store/ToolGroupManager/ToolGroup.ts +9 -2
  222. package/src/tools/SegmentationIntersectionTool.ts +1 -1
  223. package/src/tools/annotation/LivewireContourSegmentationTool.ts +1 -1
  224. package/src/tools/annotation/LivewireContourTool.ts +65 -38
  225. package/src/tools/annotation/PlanarFreehandROITool.ts +6 -1
  226. package/src/tools/annotation/SplineROITool.ts +75 -28
  227. package/src/tools/annotation/planarFreehandROITool/closedContourEditLoop.ts +20 -11
  228. package/src/tools/annotation/planarFreehandROITool/drawLoop.ts +40 -21
  229. package/src/tools/annotation/planarFreehandROITool/openContourEditLoop.ts +28 -13
  230. package/src/tools/annotation/planarFreehandROITool/renderMethods.ts +28 -10
  231. package/src/tools/annotation/splines/LinearSpline.ts +1 -1
  232. package/src/tools/annotation/splines/Spline.ts +13 -1
  233. package/src/tools/base/AnnotationTool.ts +1 -0
  234. package/src/tools/base/ContourBaseTool.ts +45 -3
  235. package/src/tools/base/ContourSegmentationBaseTool.ts +6 -0
  236. package/src/tools/displayTools/Contour/contourConfig.ts +1 -0
  237. package/src/types/AnnotationTypes.ts +14 -0
  238. package/src/types/ContourAnnotation.ts +13 -0
  239. package/src/types/ContourTypes.ts +3 -0
  240. package/src/types/EventTypes.ts +9 -0
  241. package/src/types/ISpline.ts +3 -0
  242. package/src/types/SplineProps.ts +10 -0
  243. package/src/utilities/contours/getContourHolesDataCanvas.ts +33 -0
  244. package/src/utilities/contours/getContourHolesDataWorld.ts +19 -0
  245. package/src/utilities/contours/index.ts +6 -0
  246. package/src/utilities/contours/updateContourPolyline.ts +74 -0
  247. package/src/utilities/math/polyline/containsPoint.ts +1 -1
  248. package/src/utilities/math/polyline/containsPoints.ts +22 -0
  249. package/src/utilities/math/polyline/getWindingDirection.ts +14 -0
  250. package/src/utilities/math/polyline/index.ts +4 -0
  251. package/src/utilities/math/polyline/planarFreehandROIInternalTypes.ts +1 -0
@@ -11,12 +11,14 @@ import {
11
11
  shouldSmooth,
12
12
  getInterpolatedPoints,
13
13
  } from '../../../utilities/planarFreehandROITool/smoothPoints';
14
+ import getMouseModifierKey from '../../../eventDispatchers/shared/getMouseModifier';
14
15
  import triggerAnnotationRenderForViewportIds from '../../../utilities/triggerAnnotationRenderForViewportIds';
15
- import { triggerAnnotationCompleted } from '../../../stateManagement/annotation/helpers/state';
16
+ import { triggerContourAnnotationCompleted } from '../../../stateManagement/annotation/helpers/state';
16
17
  import { PlanarFreehandROIAnnotation } from '../../../types/ToolSpecificAnnotationTypes';
17
18
  import findOpenUShapedContourVectorToPeak from './findOpenUShapedContourVectorToPeak';
18
19
  import { polyline } from '../../../utilities/math';
19
20
  import { removeAnnotation } from '../../../stateManagement/annotation/annotationState';
21
+ import { updateContourPolyline } from '../../../utilities/contours/';
20
22
  import reverseIfAntiClockwise from '../../../utilities/contours/reverseIfAntiClockwise';
21
23
 
22
24
  const {
@@ -41,6 +43,9 @@ function activateDraw(
41
43
  const canvasPos = currentPoints.canvas;
42
44
  const enabledElement = getEnabledElement(element);
43
45
  const { viewport } = enabledElement;
46
+ const contourHoleProcessingEnabled =
47
+ getMouseModifierKey(evt.detail.event) ===
48
+ this.configuration.contourHoleAdditionModifierKey;
44
49
 
45
50
  const { spacing, xDir, yDir } = getSubPixelSpacingAndXYDirections(
46
51
  viewport,
@@ -50,6 +55,7 @@ function activateDraw(
50
55
  this.drawData = {
51
56
  canvasPoints: [canvasPos],
52
57
  polylineIndex: 0,
58
+ contourHoleProcessingEnabled,
53
59
  };
54
60
 
55
61
  this.commonData = {
@@ -171,7 +177,7 @@ function mouseDragDrawCallback(evt: EventTypes.InteractionEventType): void {
171
177
  */
172
178
  function mouseUpDrawCallback(evt: EventTypes.InteractionEventType): void {
173
179
  const { allowOpenContours } = this.configuration;
174
- const { canvasPoints } = this.drawData;
180
+ const { canvasPoints, contourHoleProcessingEnabled } = this.drawData;
175
181
  const firstPoint = canvasPoints[0];
176
182
  const lastPoint = canvasPoints[canvasPoints.length - 1];
177
183
  const eventDetail = evt.detail;
@@ -185,16 +191,19 @@ function mouseUpDrawCallback(evt: EventTypes.InteractionEventType): void {
185
191
  this.configuration.closeContourProximity
186
192
  )
187
193
  ) {
188
- this.completeDrawOpenContour(element);
194
+ this.completeDrawOpenContour(element, contourHoleProcessingEnabled);
189
195
  } else {
190
- this.completeDrawClosedContour(element);
196
+ this.completeDrawClosedContour(element, contourHoleProcessingEnabled);
191
197
  }
192
198
  }
193
199
 
194
200
  /**
195
201
  * Completes the contour being drawn, creating a closed contour annotation. It will return true if contour is completed or false in case contour drawing is halted.
196
202
  */
197
- function completeDrawClosedContour(element: HTMLDivElement): boolean {
203
+ function completeDrawClosedContour(
204
+ element: HTMLDivElement,
205
+ contourHoleProcessingEnabled: boolean
206
+ ): boolean {
198
207
  this.removeCrossedLinesOnCompleteDraw();
199
208
  const { canvasPoints } = this.drawData;
200
209
 
@@ -228,17 +237,20 @@ function completeDrawClosedContour(element: HTMLDivElement): boolean {
228
237
  // Note: -> This is pretty expensive and may not scale well with hundreds of
229
238
  // contours. A future optimisation if we use this for segmentation is to re-do
230
239
  // this rendering with the GPU rather than SVG.
231
- const worldPoints = updatedPoints.map((canvasPoint) =>
232
- viewport.canvasToWorld(canvasPoint)
240
+
241
+ updateContourPolyline(
242
+ annotation,
243
+ {
244
+ points: updatedPoints,
245
+ closed: true,
246
+ },
247
+ viewport
233
248
  );
234
249
 
235
- annotation.data.contour.polyline = worldPoints;
236
- annotation.data.contour.closed = true;
237
- annotation.invalidated = true;
238
250
  const { textBox } = annotation.data.handles;
239
251
 
240
252
  if (!textBox.hasMoved) {
241
- triggerAnnotationCompleted(annotation);
253
+ triggerContourAnnotationCompleted(annotation, contourHoleProcessingEnabled);
242
254
  }
243
255
 
244
256
  this.isDrawing = false;
@@ -280,7 +292,10 @@ function removeCrossedLinesOnCompleteDraw(): void {
280
292
  /**
281
293
  * Completes the contour being drawn, creating an open contour annotation. It will return true if contour is completed or false in case contour drawing is halted.
282
294
  */
283
- function completeDrawOpenContour(element: HTMLDivElement): boolean {
295
+ function completeDrawOpenContour(
296
+ element: HTMLDivElement,
297
+ contourHoleProcessingEnabled: boolean
298
+ ): boolean {
284
299
  const { canvasPoints } = this.drawData;
285
300
 
286
301
  // check and halt if necessary the drawing process, last chance to complete drawing and fire events.
@@ -299,14 +314,18 @@ function completeDrawOpenContour(element: HTMLDivElement): boolean {
299
314
  // Note: -> This is pretty expensive and may not scale well with hundreds of
300
315
  // contours. A future optimisation if we use this for segmentation is to re-do
301
316
  // this rendering with the GPU rather than SVG.
302
- const worldPoints = updatedPoints.map((canvasPoint) =>
303
- viewport.canvasToWorld(canvasPoint)
317
+
318
+ updateContourPolyline(
319
+ annotation,
320
+ {
321
+ points: updatedPoints,
322
+ closed: false,
323
+ },
324
+ viewport
304
325
  );
305
326
 
306
- annotation.data.contour.polyline = worldPoints;
307
- annotation.data.contour.closed = false;
308
- annotation.invalidated = true;
309
327
  const { textBox } = annotation.data.handles;
328
+ const worldPoints = annotation.data.contour.polyline;
310
329
 
311
330
  // Add the first and last points to the list of handles. These means they
312
331
  // will render handles on mouse hover.
@@ -322,7 +341,7 @@ function completeDrawOpenContour(element: HTMLDivElement): boolean {
322
341
  }
323
342
 
324
343
  if (!textBox.hasMoved) {
325
- triggerAnnotationCompleted(annotation);
344
+ triggerContourAnnotationCompleted(annotation, contourHoleProcessingEnabled);
326
345
  }
327
346
 
328
347
  this.isDrawing = false;
@@ -407,7 +426,7 @@ function applyCreateOnCross(
407
426
  */
408
427
  function cancelDrawing(element: HTMLElement) {
409
428
  const { allowOpenContours } = this.configuration;
410
- const { canvasPoints } = this.drawData;
429
+ const { canvasPoints, contourHoleProcessingEnabled } = this.drawData;
411
430
  const firstPoint = canvasPoints[0];
412
431
  const lastPoint = canvasPoints[canvasPoints.length - 1];
413
432
 
@@ -419,9 +438,9 @@ function cancelDrawing(element: HTMLElement) {
419
438
  this.configuration.closeContourProximity
420
439
  )
421
440
  ) {
422
- this.completeDrawOpenContour(element);
441
+ this.completeDrawOpenContour(element, contourHoleProcessingEnabled);
423
442
  } else {
424
- this.completeDrawClosedContour(element);
443
+ this.completeDrawClosedContour(element, contourHoleProcessingEnabled);
425
444
  }
426
445
  }
427
446
 
@@ -15,6 +15,7 @@ import {
15
15
  getInterpolatedPoints,
16
16
  } from '../../../utilities/planarFreehandROITool/smoothPoints';
17
17
  import triggerAnnotationRenderForViewportIds from '../../../utilities/triggerAnnotationRenderForViewportIds';
18
+ import { updateContourPolyline } from '../../../utilities/contours';
18
19
  import findOpenUShapedContourVectorToPeak from './findOpenUShapedContourVectorToPeak';
19
20
  import { triggerAnnotationModified } from '../../../stateManagement/annotation/helpers/state';
20
21
 
@@ -213,12 +214,17 @@ function openContourEditOverwriteEnd(
213
214
  const { annotation, viewportIdsToRender } = this.commonData;
214
215
  const fusedCanvasPoints = this.fuseEditPointsForOpenContourEndEdit();
215
216
 
216
- const worldPoints = fusedCanvasPoints.map((canvasPoint) =>
217
- viewport.canvasToWorld(canvasPoint)
217
+ updateContourPolyline(
218
+ annotation,
219
+ {
220
+ points: fusedCanvasPoints,
221
+ closed: false,
222
+ },
223
+ viewport
218
224
  );
219
225
 
220
- annotation.data.contour.polyline = worldPoints;
221
- annotation.data.contour.closed = false;
226
+ const worldPoints = annotation.data.contour.polyline;
227
+
222
228
  // Note: Contours generate from fusedCanvasPoints will be in the direction
223
229
  // with the last point being the current mouse position
224
230
  annotation.data.handles.points = [
@@ -495,12 +501,17 @@ function finishEditOpenOnSecondCrossing(
495
501
  const { annotation, viewportIdsToRender } = this.commonData;
496
502
  const { fusedCanvasPoints, editCanvasPoints } = this.editData;
497
503
 
498
- const worldPoints = fusedCanvasPoints.map((canvasPoint) =>
499
- viewport.canvasToWorld(canvasPoint)
504
+ updateContourPolyline(
505
+ annotation,
506
+ {
507
+ points: fusedCanvasPoints,
508
+ closed: false,
509
+ },
510
+ viewport
500
511
  );
501
512
 
502
- annotation.data.contour.polyline = worldPoints;
503
- annotation.data.contour.closed = false;
513
+ const worldPoints = annotation.data.contour.polyline;
514
+
504
515
  annotation.data.handles.points = [
505
516
  worldPoints[0],
506
517
  worldPoints[worldPoints.length - 1],
@@ -551,13 +562,17 @@ function completeOpenContourEdit(element: HTMLDivElement) {
551
562
  )
552
563
  : fusedCanvasPoints;
553
564
 
554
- const worldPoints = updatedPoints.map((canvasPoint) =>
555
- viewport.canvasToWorld(canvasPoint)
565
+ updateContourPolyline(
566
+ annotation,
567
+ {
568
+ points: updatedPoints,
569
+ closed: false,
570
+ },
571
+ viewport
556
572
  );
557
573
 
558
- annotation.invalidated = true;
559
- annotation.data.contour.polyline = worldPoints;
560
- annotation.data.contour.closed = false;
574
+ const worldPoints = annotation.data.contour.polyline;
575
+
561
576
  annotation.data.handles.points = [
562
577
  worldPoints[0],
563
578
  worldPoints[worldPoints.length - 1],
@@ -2,12 +2,14 @@ import type { Types } from '@cornerstonejs/core';
2
2
  import {
3
3
  drawHandles as drawHandlesSvg,
4
4
  drawPolyline as drawPolylineSvg,
5
+ drawPath as drawPathSvg,
5
6
  } from '../../../drawingSvg';
6
7
  import { polyline } from '../../../utilities/math';
7
8
  import { findOpenUShapedContourVectorToPeakOnRender } from './findOpenUShapedContourVectorToPeak';
8
9
  import { PlanarFreehandROIAnnotation } from '../../../types/ToolSpecificAnnotationTypes';
9
10
  import { StyleSpecifier } from '../../../types/AnnotationStyle';
10
11
  import { SVGDrawingHelper } from '../../../types';
12
+ import { getContourHolesDataCanvas } from '../../../utilities/contours';
11
13
 
12
14
  const { pointsAreWithinCloseContourProximity } = polyline;
13
15
 
@@ -42,7 +44,7 @@ function _getRenderingOptions(
42
44
  lineDash,
43
45
  fillColor,
44
46
  fillOpacity,
45
- connectLastToFirst: isClosedContour,
47
+ closePath: isClosedContour,
46
48
  };
47
49
 
48
50
  return options;
@@ -106,6 +108,10 @@ function renderClosedContour(
106
108
  svgDrawingHelper: SVGDrawingHelper,
107
109
  annotation: PlanarFreehandROIAnnotation
108
110
  ): void {
111
+ if (annotation.parentAnnotationUID) {
112
+ return;
113
+ }
114
+
109
115
  const { viewport } = enabledElement;
110
116
  const options = this._getRenderingOptions(enabledElement, annotation);
111
117
 
@@ -114,17 +120,19 @@ function renderClosedContour(
114
120
  // element on the tool? That feels very weird also as we'd need to manage
115
121
  // it/clean them up. Its a pre-optimisation for now and we can tackle it if it
116
122
  // becomes a problem.
117
- const canvasPoints = annotation.data.contour.polyline.map((worldPos) =>
123
+ const canvasPolyline = annotation.data.contour.polyline.map((worldPos) =>
118
124
  viewport.worldToCanvas(worldPos)
119
125
  );
120
126
 
127
+ const childContours = getContourHolesDataCanvas(annotation, viewport);
128
+ const allContours = [canvasPolyline, ...childContours];
121
129
  const polylineUID = '1';
122
130
 
123
- drawPolylineSvg(
131
+ drawPathSvg(
124
132
  svgDrawingHelper,
125
133
  annotation.annotationUID,
126
134
  polylineUID,
127
- canvasPoints,
135
+ allContours,
128
136
  options
129
137
  );
130
138
  }
@@ -245,7 +253,7 @@ function renderOpenUShapedContour(
245
253
  {
246
254
  color: options.color,
247
255
  width: options.width,
248
- connectLastToFirst: false,
256
+ closePath: false,
249
257
  lineDash: '2,2',
250
258
  }
251
259
  );
@@ -262,7 +270,7 @@ function renderOpenUShapedContour(
262
270
  {
263
271
  color: options.color,
264
272
  width: options.width,
265
- connectLastToFirst: false,
273
+ closePath: false,
266
274
  lineDash: '2,2',
267
275
  }
268
276
  );
@@ -284,7 +292,7 @@ function renderContourBeingDrawn(
284
292
 
285
293
  // Override rendering whilst drawing the contour, we don't know if its open
286
294
  // or closed yet
287
- options.connectLastToFirst = false;
295
+ options.closePath = false;
288
296
 
289
297
  drawPolylineSvg(
290
298
  svgDrawingHelper,
@@ -337,6 +345,7 @@ function renderClosedContourBeingEdited(
337
345
  svgDrawingHelper,
338
346
  annotation
339
347
  ): void {
348
+ const { viewport } = enabledElement;
340
349
  const { fusedCanvasPoints } = this.editData;
341
350
 
342
351
  if (fusedCanvasPoints === undefined) {
@@ -346,15 +355,24 @@ function renderClosedContourBeingEdited(
346
355
  return;
347
356
  }
348
357
 
349
- const options = this._getRenderingOptions(enabledElement, annotation);
358
+ // Get the polylines from child annotations (holes)
359
+ const childContours = getContourHolesDataCanvas(annotation, viewport);
350
360
 
361
+ const allContours = [fusedCanvasPoints, ...childContours];
362
+ const options = this._getRenderingOptions(enabledElement, annotation);
351
363
  const polylineUIDToRender = 'preview-1';
352
364
 
353
- drawPolylineSvg(
365
+ // Set `fillOpacity` to zero if it is a child annotation (hole) otherwise
366
+ // it would "close" the hole when editing it
367
+ if (annotation.parentAnnotationUID && options.fillOpacity) {
368
+ options.fillOpacity = 0;
369
+ }
370
+
371
+ drawPathSvg(
354
372
  svgDrawingHelper,
355
373
  annotation.annotationUID,
356
374
  polylineUIDToRender,
357
- fusedCanvasPoints,
375
+ allContours,
358
376
  options
359
377
  );
360
378
  }
@@ -13,7 +13,7 @@ import { CardinalSpline } from './CardinalSpline';
13
13
  */
14
14
  class LinearSpline extends CardinalSpline {
15
15
  constructor() {
16
- super({ scale: 0, fixedScale: true });
16
+ super({ resolution: 0, fixedResolution: true, scale: 0, fixedScale: true });
17
17
  }
18
18
  }
19
19
 
@@ -26,6 +26,7 @@ type CurveSegmentDistanceSquared = {
26
26
  abstract class Spline implements ISpline {
27
27
  private _controlPoints: Types.Point2[] = [];
28
28
  private _resolution: number;
29
+ private _fixedResolution: boolean;
29
30
  private _closed: boolean;
30
31
  private _invalidated = false;
31
32
  private _curveSegments: SplineCurveSegment[];
@@ -35,6 +36,7 @@ abstract class Spline implements ISpline {
35
36
  constructor(props?: SplineProps) {
36
37
  this._controlPoints = [];
37
38
  this._resolution = props?.resolution ?? 20;
39
+ this._fixedResolution = props?.fixedResolution ?? false;
38
40
  this._closed = props?.closed ?? false;
39
41
  this._invalidated = true;
40
42
  }
@@ -61,7 +63,7 @@ abstract class Spline implements ISpline {
61
63
 
62
64
  /** Set the resolution of the spline curve */
63
65
  public set resolution(resolution: number) {
64
- if (this._resolution === resolution) {
66
+ if (this._fixedResolution || this._resolution === resolution) {
65
67
  return;
66
68
  }
67
69
 
@@ -69,6 +71,16 @@ abstract class Spline implements ISpline {
69
71
  this.invalidated = true;
70
72
  }
71
73
 
74
+ /** Fixed resolution
75
+ *
76
+ * Linar spline is one of the splines that does not allow changing the resolution
77
+ * for better performance otherwise it would calculate and render 20 line segments
78
+ * instead of a single one..
79
+ */
80
+ public get fixedResolution() {
81
+ return this._fixedResolution;
82
+ }
83
+
72
84
  /** Flag that is set to true when the curve is already closed */
73
85
  public get closed(): boolean {
74
86
  return this._closed;
@@ -19,6 +19,7 @@ import {
19
19
  InteractionTypes,
20
20
  ToolProps,
21
21
  PublicToolProps,
22
+ IToolBinding,
22
23
  } from '../../types';
23
24
  import { StyleSpecifier } from '../../types/AnnotationStyle';
24
25
 
@@ -3,6 +3,7 @@ import type { Types } from '@cornerstonejs/core';
3
3
  import {
4
4
  addAnnotation,
5
5
  getAnnotations,
6
+ getChildAnnotations,
6
7
  } from '../../stateManagement/annotation/annotationState';
7
8
  import type {
8
9
  Annotation,
@@ -13,9 +14,10 @@ import type {
13
14
  SVGDrawingHelper,
14
15
  AnnotationRenderContext,
15
16
  } from '../../types';
16
- import { drawPolyline as drawPolylineSvg } from '../../drawingSvg';
17
+ import { drawPath as drawPathSvg } from '../../drawingSvg';
17
18
  import { StyleSpecifier } from '../../types/AnnotationStyle';
18
19
  import AnnotationTool from './AnnotationTool';
20
+ import { getContourHolesDataCanvas } from '../../utilities/contours';
19
21
 
20
22
  /**
21
23
  * A contour base class responsible for rendering contour instances such as
@@ -177,6 +179,37 @@ abstract class ContourBaseTool extends AnnotationTool {
177
179
  // noop method just to give a chance for child classes to override it
178
180
  }
179
181
 
182
+ /**
183
+ * Move an annotation and all its child annotations in a recursive way.
184
+ *
185
+ * That is useful when clicking on a spline contour to completely translate
186
+ * it to a different place. In that case all holes (child annotations) must
187
+ * also be translated too.
188
+ *
189
+ * @param annotation - Annotation
190
+ * @param worldPosDelta - Delta in world space
191
+ */
192
+ protected moveAnnotation(
193
+ annotation: Annotation,
194
+ worldPosDelta: Types.Point3
195
+ ): void {
196
+ const { points } = annotation.data.handles;
197
+
198
+ for (let i = 0, numPoints = points.length; i < numPoints; i++) {
199
+ const point = points[i];
200
+
201
+ point[0] += worldPosDelta[0];
202
+ point[1] += worldPosDelta[1];
203
+ point[2] += worldPosDelta[2];
204
+ }
205
+
206
+ annotation.invalidated = true;
207
+
208
+ getChildAnnotations(annotation).forEach((childAnnotation) =>
209
+ this.moveAnnotation(childAnnotation, worldPosDelta)
210
+ );
211
+ }
212
+
180
213
  /**
181
214
  * Get polyline points in world space.
182
215
  * Just to give a chance for child classes to override it.
@@ -197,6 +230,12 @@ abstract class ContourBaseTool extends AnnotationTool {
197
230
  ): boolean {
198
231
  const { enabledElement, annotationStyle, svgDrawingHelper } = renderContext;
199
232
  const annotation = renderContext.annotation as ContourAnnotation;
233
+
234
+ // Do not render the contour because it must be rendered by the parent annotation
235
+ if (annotation.parentAnnotationUID) {
236
+ return;
237
+ }
238
+
200
239
  const { annotationUID } = annotation;
201
240
  const { viewport } = enabledElement;
202
241
  const { worldToCanvas } = viewport;
@@ -206,11 +245,14 @@ abstract class ContourBaseTool extends AnnotationTool {
206
245
  const { lineWidth, lineDash, color, fillColor, fillOpacity } =
207
246
  annotationStyle;
208
247
 
209
- drawPolylineSvg(
248
+ const childContours = getContourHolesDataCanvas(annotation, viewport);
249
+ const allContours = [polylineCanvasPoints, ...childContours];
250
+
251
+ drawPathSvg(
210
252
  svgDrawingHelper,
211
253
  annotationUID,
212
254
  'contourPolyline',
213
- polylineCanvasPoints,
255
+ allContours,
214
256
  {
215
257
  color,
216
258
  lineDash,
@@ -175,6 +175,7 @@ abstract class ContourSegmentationBaseTool extends ContourBaseTool {
175
175
  const annotation = context.annotation as ContourSegmentationAnnotation;
176
176
  const { segmentationRepresentationUID, segmentationId, segmentIndex } =
177
177
  annotation.data.segmentation;
178
+ const segmentation = segmentationState.getSegmentation(segmentationId);
178
179
  const segmentationRepresentation =
179
180
  segmentationState.getSegmentationRepresentationByUID(
180
181
  toolGroupId,
@@ -252,6 +253,11 @@ abstract class ContourSegmentationBaseTool extends ContourBaseTool {
252
253
  fillOpacity = mergedConfig.fillAlphaInactive ?? fillOpacity;
253
254
  }
254
255
 
256
+ // Change the line thickness when the mouse is over the contour segment
257
+ if (segmentation.activeSegmentIndex === segmentIndex) {
258
+ lineWidth += mergedConfig.activeSegmentOutlineWidthDelta;
259
+ }
260
+
255
261
  lineWidth = mergedConfig.renderOutline ? lineWidth : 0;
256
262
  fillOpacity = mergedConfig.renderFill ? fillOpacity : 0;
257
263
 
@@ -10,6 +10,7 @@ const defaultContourConfig: ContourConfig = {
10
10
  outlineDashActive: undefined,
11
11
  outlineDashInactive: undefined,
12
12
  outlineDashAutoGenerated: '5,3',
13
+ activeSegmentOutlineWidthDelta: 0,
13
14
  renderFill: true,
14
15
  fillAlpha: 0.5,
15
16
  fillAlphaInactive: 0.3,
@@ -3,6 +3,20 @@ import type { Types } from '@cornerstonejs/core';
3
3
  type Annotation = {
4
4
  /** A unique identifier for this annotation */
5
5
  annotationUID?: string;
6
+ /**
7
+ * Parent annotation UID
8
+ *
9
+ * An annotation may have a parent annotation when it is, for example, a
10
+ * hole inside a contour.
11
+ */
12
+ parentAnnotationUID?: string;
13
+ /**
14
+ * Array that contains all child annotation UID
15
+ *
16
+ * An annotation may have one or more child annotations when it is contour
17
+ * and have some holes in it.
18
+ */
19
+ childAnnotationUIDs?: string[];
6
20
  /** If the annotation is being hovered over and is highlighted */
7
21
  highlighted?: boolean;
8
22
  /** If the annotation is locked for manipulation */
@@ -1,11 +1,24 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import { Annotation } from './AnnotationTypes';
3
3
 
4
+ /**
5
+ * Polyline winding direction
6
+ *
7
+ * It is defined as -1 and 1 to make it easier to change its direction multiplying
8
+ * by -1 whenever polyline.reverse() is called instead of using IF/ELSE
9
+ */
10
+ export enum ContourWindingDirection {
11
+ CounterClockwise = -1,
12
+ Unknown = 0,
13
+ Clockwise = 1,
14
+ }
15
+
4
16
  export type ContourAnnotationData = {
5
17
  data: {
6
18
  contour: {
7
19
  polyline: Types.Point3[];
8
20
  closed: boolean;
21
+ windingDirection?: ContourWindingDirection;
9
22
  };
10
23
  };
11
24
  };
@@ -16,6 +16,9 @@ export type ContourConfig = {
16
16
  outlineDashActive?: string;
17
17
  /** dash style of the outline when segmentation is inactive */
18
18
  outlineDashInactive?: string;
19
+ /** delta thickness of the active segment index outline (0 means same thickness,
20
+ * 1 means 1px thicker, -1 means 1px thinner) */
21
+ activeSegmentOutlineWidthDelta?: number;
19
22
  /**
20
23
  * Dash style of the outline when segmentation is auto-generated
21
24
  */
@@ -214,6 +214,14 @@ type AnnotationInterpolationRemovedEventDetail = {
214
214
  renderingEngineId: string;
215
215
  };
216
216
 
217
+ /**
218
+ * The data that is passed to the event handler when a new contour annotation is
219
+ * completed drawing on the viewport.
220
+ */
221
+ type ContourAnnotationCompletedEventDetail = AnnotationCompletedEventDetail & {
222
+ contourHoleProcessingEnabled: boolean;
223
+ };
224
+
217
225
  /**
218
226
  * EventDetail for when a Segmentation Data is modified by a tool
219
227
  */
@@ -713,6 +721,7 @@ export {
713
721
  AnnotationInterpolationCompletedEventType,
714
722
  AnnotationInterpolationRemovedEventDetail,
715
723
  AnnotationInterpolationRemovedEventType,
724
+ ContourAnnotationCompletedEventDetail,
716
725
  SegmentationDataModifiedEventType,
717
726
  SegmentationRepresentationModifiedEventDetail,
718
727
  SegmentationRepresentationModifiedEventType,
@@ -19,6 +19,9 @@ export interface ISpline {
19
19
  /** Set the resolution of the spline curve */
20
20
  set resolution(resolution: number);
21
21
 
22
+ /** Fixed resolution (eg: Linear Spline) */
23
+ get fixedResolution(): boolean;
24
+
22
25
  /** Flag that is set to true when the curve is already closed */
23
26
  get closed(): boolean;
24
27
 
@@ -10,6 +10,16 @@ export type SplineProps = {
10
10
  */
11
11
  resolution?: number;
12
12
 
13
+ /**
14
+ * Fixed resolution (Linear spline)
15
+ *
16
+ * Splines with `fixedResolution` set to true shall attempt to change the
17
+ * resolution (eg: spline.resolution = 10). That is useful, for example, for
18
+ * linear splines because having more line segments between two control points
19
+ * would not change its resolution and that is why it is fixed to 0.
20
+ */
21
+ fixedResolution?: boolean;
22
+
13
23
  /** Flag that is set to true when the curve is closed */
14
24
  closed?: boolean;
15
25
  };
@@ -0,0 +1,33 @@
1
+ import type { Types } from '@cornerstonejs/core';
2
+ import type { Annotation } from '../../types';
3
+ import getContourHolesDataWorld from './getContourHolesDataWorld';
4
+
5
+ /**
6
+ * Get the polylines for the child annotations (holes)
7
+ * @param annotation - Annotation
8
+ * @param viewport - Viewport used to convert the points from world to canvas space
9
+ * @returns An array that contains all child polylines
10
+ */
11
+ export default function getContourHolesDataCanvas(
12
+ annotation: Annotation,
13
+ viewport: Types.IViewport
14
+ ): Types.Point2[][] {
15
+ const worldHoleContours = getContourHolesDataWorld(annotation);
16
+ const canvasHoleContours = [];
17
+
18
+ worldHoleContours.forEach((worldHoleContour) => {
19
+ const numPoints = worldHoleContour.length;
20
+
21
+ // Pre-allocated arrays are 3-4x faster than multiple "push()" calls
22
+ const canvasHoleContour: Types.Point2[] = new Array(numPoints);
23
+
24
+ // Using FOR loop instead of map() for better performance when processing large arrays
25
+ for (let i = 0; i < numPoints; i++) {
26
+ canvasHoleContour[i] = viewport.worldToCanvas(worldHoleContour[i]);
27
+ }
28
+
29
+ canvasHoleContours.push(canvasHoleContour);
30
+ });
31
+
32
+ return canvasHoleContours;
33
+ }