@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.52.0",
3
+ "version": "1.53.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.52.0",
32
+ "@cornerstonejs/core": "^1.53.0",
33
33
  "comlink": "^4.4.1",
34
34
  "lodash.clonedeep": "4.5.0",
35
35
  "lodash.get": "^4.4.2"
@@ -53,5 +53,5 @@
53
53
  "type": "individual",
54
54
  "url": "https://ohif.org/donate"
55
55
  },
56
- "gitHead": "f09289b1bbae632126eec5ba208dd89da1923a4d"
56
+ "gitHead": "881872ffe29341443f91cead0b810871a6a1929b"
57
57
  }
@@ -0,0 +1,96 @@
1
+ import type { Types } from '@cornerstonejs/core';
2
+ import _getHash from './_getHash';
3
+ import setNewAttributesIfValid from './setNewAttributesIfValid';
4
+ import setAttributesIfNecessary from './setAttributesIfNecessary';
5
+ import { SVGDrawingHelper } from '../types';
6
+
7
+ /**
8
+ * Draws an SVG path with the given points.
9
+ *
10
+ * The `closePath` option, if true, draws a closed path (last point
11
+ * connected to the first).
12
+ */
13
+ export default function drawPath(
14
+ svgDrawingHelper: SVGDrawingHelper,
15
+ annotationUID: string,
16
+ pathUID: string,
17
+ points: Types.Point2[] | Types.Point2[][],
18
+ options: {
19
+ color?: string;
20
+ fillColor?: string;
21
+ fillOpacity?: number;
22
+ width?: number;
23
+ lineWidth?: number;
24
+ lineDash?: string;
25
+ closePath?: boolean;
26
+ }
27
+ ): void {
28
+ // It may be a polyline with holes that will be an array with multiple
29
+ // 'points' arrays
30
+ const hasSubArrays =
31
+ points.length && points[0].length && Array.isArray(points[0][0]);
32
+
33
+ const pointsArrays = hasSubArrays ? points : [points];
34
+ const {
35
+ color = 'dodgerblue',
36
+ width = 10,
37
+ fillColor = 'none',
38
+ fillOpacity = 0,
39
+ lineWidth,
40
+ lineDash,
41
+ closePath = false,
42
+ } = options;
43
+
44
+ // for supporting both lineWidth and width options
45
+ const strokeWidth = lineWidth || width;
46
+
47
+ const svgns = 'http://www.w3.org/2000/svg';
48
+ const svgNodeHash = _getHash(annotationUID, 'path', pathUID);
49
+ const existingNode = svgDrawingHelper.getSvgNode(svgNodeHash);
50
+ let pointsAttribute = '';
51
+
52
+ for (let i = 0, numArrays = pointsArrays.length; i < numArrays; i++) {
53
+ const points = pointsArrays[i];
54
+ const numPoints = points.length;
55
+
56
+ if (numPoints < 2) {
57
+ continue;
58
+ }
59
+
60
+ for (let j = 0; j < numPoints; j++) {
61
+ const point = points[j];
62
+ const cmd = j ? 'L' : 'M';
63
+
64
+ pointsAttribute += `${cmd} ${point[0]},${point[1]} `;
65
+ }
66
+
67
+ if (closePath) {
68
+ pointsAttribute += 'Z ';
69
+ }
70
+ }
71
+
72
+ if (!pointsAttribute) {
73
+ return;
74
+ }
75
+
76
+ const attributes = {
77
+ d: pointsAttribute,
78
+ stroke: color,
79
+ fill: fillColor,
80
+ 'fill-opacity': fillOpacity,
81
+ 'stroke-width': strokeWidth,
82
+ 'stroke-dasharray': lineDash,
83
+ };
84
+
85
+ if (existingNode) {
86
+ // This is run to avoid re-rendering annotations that actually haven't changed
87
+ setAttributesIfNecessary(attributes, existingNode);
88
+
89
+ svgDrawingHelper.setNodeTouched(svgNodeHash);
90
+ } else {
91
+ const newNode = document.createElementNS(svgns, 'path');
92
+
93
+ setNewAttributesIfValid(attributes, newNode);
94
+ svgDrawingHelper.appendNode(newNode, svgNodeHash);
95
+ }
96
+ }
@@ -7,7 +7,7 @@ import { SVGDrawingHelper } from '../types';
7
7
  /**
8
8
  * Draws an SVG polyline with the given points.
9
9
  *
10
- * The `connectLastToFirst` option, if true, draws a closed polyline, with the
10
+ * The `closePath` option, if true, draws a closed polyline, with the
11
11
  * last point connected to the first.
12
12
  */
13
13
  export default function drawPolyline(
@@ -22,26 +22,22 @@ export default function drawPolyline(
22
22
  width?: number;
23
23
  lineWidth?: number;
24
24
  lineDash?: string;
25
- connectLastToFirst?: boolean;
25
+ closePath?: boolean;
26
26
  }
27
27
  ): void {
28
28
  if (points.length < 2) {
29
29
  return;
30
30
  }
31
31
 
32
- const { fillColor, fillOpacity, color, width, lineWidth, lineDash } =
33
- Object.assign(
34
- {
35
- color: 'dodgerblue',
36
- width: '2',
37
- fillColor: 'none',
38
- fillOpacity: 0,
39
- lineWidth: undefined,
40
- lineDash: undefined,
41
- connectLastToFirst: false,
42
- },
43
- options
44
- );
32
+ const {
33
+ color = 'dodgerblue',
34
+ width = 10,
35
+ fillColor = 'none',
36
+ fillOpacity = 0,
37
+ lineWidth,
38
+ lineDash,
39
+ closePath = false,
40
+ } = options;
45
41
 
46
42
  // for supporting both lineWidth and width options
47
43
  const strokeWidth = lineWidth || width;
@@ -56,7 +52,7 @@ export default function drawPolyline(
56
52
  pointsAttribute += `${point[0].toFixed(1)}, ${point[1].toFixed(1)} `;
57
53
  }
58
54
 
59
- if (options.connectLastToFirst) {
55
+ if (closePath) {
60
56
  const firstPoint = points[0];
61
57
 
62
58
  pointsAttribute += `${firstPoint[0]}, ${firstPoint[1]}`;
@@ -6,6 +6,7 @@ import drawHandles from './drawHandles';
6
6
  import drawHandle from './drawHandle';
7
7
  import drawLine from './drawLine';
8
8
  import drawPolyline from './drawPolyline';
9
+ import drawPath from './drawPath';
9
10
  import drawLinkedTextBox from './drawLinkedTextBox';
10
11
  import drawRect from './drawRect';
11
12
  import drawTextBox from './drawTextBox';
@@ -23,6 +24,7 @@ export {
23
24
  drawHandle,
24
25
  drawLine,
25
26
  drawPolyline,
27
+ drawPath,
26
28
  drawLinkedTextBox,
27
29
  drawRect,
28
30
  drawTextBox,
@@ -1,5 +1,5 @@
1
1
  import { ToolGroupManager } from '../../store';
2
- import { MouseBindings, ToolModes } from '../../enums';
2
+ import { ToolModes } from '../../enums';
3
3
  import { keyEventListener } from '../../eventListeners';
4
4
  import { EventTypes } from '../../types';
5
5
  import getMouseModifier from './getMouseModifier';
@@ -14,16 +14,24 @@ import {
14
14
  getAnnotations,
15
15
  addAnnotation,
16
16
  removeAnnotation,
17
+ getChildAnnotations,
18
+ addChildAnnotation,
19
+ clearParentAnnotation,
17
20
  } from '../../../stateManagement/annotation/annotationState';
18
- import { AnnotationCompletedEventType } from '../../../types/EventTypes';
21
+ import {
22
+ AnnotationCompletedEventType,
23
+ ContourAnnotationCompletedEventDetail,
24
+ } from '../../../types/EventTypes';
19
25
  import * as contourUtils from '../../../utilities/contours';
20
26
  import * as contourSegUtils from '../../../utilities/contourSegmentation';
21
27
  import { ToolGroupManager, hasTool as cstHasTool } from '../../../store';
22
28
  import { PlanarFreehandContourSegmentationTool } from '../../../tools';
29
+ import type { ContourAnnotation } from '../../../types/ContourAnnotation';
30
+ import { ContourWindingDirection } from '../../../types/ContourAnnotation';
23
31
 
24
32
  const DEFAULT_CONTOUR_SEG_TOOLNAME = 'PlanarFreehandContourSegmentationTool';
25
33
 
26
- export default function contourSegmentationCompletedListener(
34
+ export default async function contourSegmentationCompletedListener(
27
35
  evt: AnnotationCompletedEventType
28
36
  ) {
29
37
  const sourceAnnotation = evt.detail
@@ -60,15 +68,28 @@ export default function contourSegmentationCompletedListener(
60
68
  return;
61
69
  }
62
70
 
63
- const { targetAnnotation, targetPolyline } = targetAnnotationInfo;
71
+ const { targetAnnotation, targetPolyline, isContourHole } =
72
+ targetAnnotationInfo;
64
73
 
65
- processContours(
66
- viewport,
67
- sourceAnnotation,
68
- sourcePolyline,
69
- targetAnnotation,
70
- targetPolyline
71
- );
74
+ if (isContourHole) {
75
+ const { contourHoleProcessingEnabled = false } =
76
+ evt.detail as ContourAnnotationCompletedEventDetail;
77
+
78
+ // Do not create holes when contourHoleProcessingEnabled is `false`
79
+ if (!contourHoleProcessingEnabled) {
80
+ return;
81
+ }
82
+
83
+ createPolylineHole(viewport, targetAnnotation, sourceAnnotation);
84
+ } else {
85
+ combinePolylines(
86
+ viewport,
87
+ targetAnnotation,
88
+ targetPolyline,
89
+ sourceAnnotation,
90
+ sourcePolyline
91
+ );
92
+ }
72
93
  }
73
94
 
74
95
  function isFreehandContourSegToolRegistered(viewport: Types.IViewport) {
@@ -111,26 +132,16 @@ function convertContourPolylineToCanvasSpace(
111
132
  return projectedPolyline;
112
133
  }
113
134
 
114
- function convertPolylineToWorldSpace(
115
- polyline: Types.Point2[],
116
- viewport: Types.IViewport
117
- ): Types.Point3[] {
118
- const numPoints = polyline.length;
119
- const projectedPolyline = new Array(numPoints);
120
-
121
- for (let i = 0; i < numPoints; i++) {
122
- projectedPolyline[i] = viewport.canvasToWorld(polyline[i]);
123
- }
124
-
125
- return projectedPolyline;
126
- }
127
-
128
135
  function getValidContourSegmentationAnnotations(
129
136
  sourceAnnotation: ContourSegmentationAnnotation
130
137
  ): ContourSegmentationAnnotation[] {
131
138
  const { annotationUID: sourceAnnotationUID } = sourceAnnotation;
132
139
  const { FrameOfReferenceUID } = sourceAnnotation.metadata;
133
140
 
141
+ if (!FrameOfReferenceUID) {
142
+ return [];
143
+ }
144
+
134
145
  // Get all annotations and filter all contour segmentations locally
135
146
  const toolName = undefined;
136
147
  const annotationsGroups = getAnnotations(toolName, FrameOfReferenceUID);
@@ -157,6 +168,7 @@ function findIntersectingContour(
157
168
  ): {
158
169
  targetAnnotation: ContourSegmentationAnnotation;
159
170
  targetPolyline: Types.Point2[];
171
+ isContourHole: boolean;
160
172
  } {
161
173
  const sourceAABB = math.polyline.getAABB(sourcePolyline);
162
174
 
@@ -168,22 +180,81 @@ function findIntersectingContour(
168
180
  );
169
181
 
170
182
  const targetAABB = math.polyline.getAABB(targetPolyline);
171
- const polylinesIntersect =
172
- math.aabb.intersectAABB(sourceAABB, targetAABB) &&
183
+ const aabbIntersect = math.aabb.intersectAABB(sourceAABB, targetAABB);
184
+ const lineSegmentsIntersect =
185
+ aabbIntersect &&
173
186
  math.polyline.intersectPolyline(sourcePolyline, targetPolyline);
187
+ const isContourHole =
188
+ aabbIntersect &&
189
+ !lineSegmentsIntersect &&
190
+ math.polyline.containsPoints(targetPolyline, sourcePolyline);
174
191
 
175
- if (polylinesIntersect) {
176
- return { targetAnnotation, targetPolyline };
192
+ if (lineSegmentsIntersect || isContourHole) {
193
+ return { targetAnnotation, targetPolyline, isContourHole };
177
194
  }
178
195
  }
179
196
  }
180
197
 
181
- function processContours(
198
+ function createPolylineHole(
199
+ viewport: Types.IViewport,
200
+ targetAnnotation: ContourSegmentationAnnotation,
201
+ holeAnnotation: ContourSegmentationAnnotation
202
+ ) {
203
+ const { windingDirection: targetWindingDirection } =
204
+ targetAnnotation.data.contour;
205
+ const { windingDirection: holeWindingDirection } =
206
+ holeAnnotation.data.contour;
207
+
208
+ // Check if both normals are pointing to the same direction because the
209
+ // polyline for the hole needs to be in a different direction
210
+ // if (glMatrix.equals(1, dotNormals)) {
211
+ if (targetWindingDirection === holeWindingDirection) {
212
+ holeAnnotation.data.contour.polyline.reverse();
213
+ holeAnnotation.data.contour.windingDirection = targetWindingDirection * -1;
214
+ }
215
+
216
+ addChildAnnotation(targetAnnotation, holeAnnotation);
217
+
218
+ const { element } = viewport;
219
+ const enabledElement = getEnabledElement(element);
220
+ const { renderingEngine } = enabledElement;
221
+
222
+ // Updating a Spline contours, for example, should also update freehand contours
223
+ const updatedToolNames = new Set([
224
+ DEFAULT_CONTOUR_SEG_TOOLNAME,
225
+ targetAnnotation.metadata.toolName,
226
+ holeAnnotation.metadata.toolName,
227
+ ]);
228
+
229
+ for (const toolName of updatedToolNames.values()) {
230
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
231
+ element,
232
+ toolName
233
+ );
234
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
235
+ }
236
+ }
237
+
238
+ function getContourHolesData(
239
+ viewport: Types.IViewport,
240
+ annotation: ContourAnnotation
241
+ ) {
242
+ return getChildAnnotations(annotation).map((holeAnnotation) => {
243
+ const polyline = convertContourPolylineToCanvasSpace(
244
+ holeAnnotation.data.contour.polyline,
245
+ viewport
246
+ );
247
+
248
+ return { annotation: holeAnnotation, polyline };
249
+ });
250
+ }
251
+
252
+ async function combinePolylines(
182
253
  viewport: Types.IViewport,
183
- sourceAnnotation: ContourSegmentationAnnotation,
184
- sourcePolyline: Types.Point2[],
185
254
  targetAnnotation: ContourSegmentationAnnotation,
186
- targetPolyline: Types.Point2[]
255
+ targetPolyline: Types.Point2[],
256
+ sourceAnnotation: ContourSegmentationAnnotation,
257
+ sourcePolyline: Types.Point2[]
187
258
  ) {
188
259
  const sourceStartPoint = sourcePolyline[0];
189
260
  const mergePolylines = math.polyline.containsPoint(
@@ -191,6 +262,20 @@ function processContours(
191
262
  sourceStartPoint
192
263
  );
193
264
 
265
+ const contourHolesData = getContourHolesData(viewport, targetAnnotation);
266
+ const unassignedContourHolesSet = new Set(contourHolesData);
267
+ const reassignedContourHolesMap = new Map();
268
+ const assignHoleToPolyline = (parentPolyline, holeData) => {
269
+ let holes = reassignedContourHolesMap.get(parentPolyline);
270
+
271
+ if (!holes) {
272
+ holes = [];
273
+ reassignedContourHolesMap.set(parentPolyline, holes);
274
+ }
275
+
276
+ holes.push(holeData);
277
+ unassignedContourHolesSet.delete(holeData);
278
+ };
194
279
  const newPolylines = [];
195
280
 
196
281
  if (mergePolylines) {
@@ -200,32 +285,58 @@ function processContours(
200
285
  );
201
286
 
202
287
  newPolylines.push(mergedPolyline);
288
+
289
+ // Keep all holes because the contour can only grow when merging and there
290
+ // is no chance for any hole to be removed
291
+ Array.from(unassignedContourHolesSet.keys()).forEach((holeData) =>
292
+ assignHoleToPolyline(mergedPolyline, holeData)
293
+ );
203
294
  } else {
204
295
  const subtractedPolylines = math.polyline.subtractPolylines(
205
296
  targetPolyline,
206
297
  sourcePolyline
207
298
  );
208
299
 
209
- subtractedPolylines.forEach((newPolyline) =>
210
- newPolylines.push(newPolyline)
211
- );
300
+ subtractedPolylines.forEach((newPolyline) => {
301
+ newPolylines.push(newPolyline);
302
+
303
+ Array.from(unassignedContourHolesSet.keys()).forEach((holeData) => {
304
+ const containsHole = math.polyline.containsPoints(
305
+ newPolyline,
306
+ holeData.polyline
307
+ );
308
+
309
+ if (containsHole) {
310
+ assignHoleToPolyline(newPolyline, holeData);
311
+ unassignedContourHolesSet.delete(holeData);
312
+ }
313
+ });
314
+ });
212
315
  }
213
316
 
214
- removeAnnotation(sourceAnnotation.annotationUID);
215
- removeAnnotation(targetAnnotation.annotationUID);
317
+ // Make sure the holes that will be added to the new annotation are not
318
+ // associated to the target annotation that will be deleted
319
+ Array.from(reassignedContourHolesMap.values()).forEach(
320
+ (contourHolesDataArray) =>
321
+ contourHolesDataArray.forEach((contourHoleData) =>
322
+ clearParentAnnotation(contourHoleData.annotation)
323
+ )
324
+ );
216
325
 
217
326
  const { element } = viewport;
218
327
  const enabledElement = getEnabledElement(element);
219
- const { renderingEngine } = enabledElement;
220
328
  const { metadata, data } = targetAnnotation;
221
329
  const { handles, segmentation } = data;
222
330
  const { textBox } = handles;
223
331
 
332
+ removeAnnotation(sourceAnnotation.annotationUID);
333
+ removeAnnotation(targetAnnotation.annotationUID);
334
+
224
335
  for (let i = 0; i < newPolylines.length; i++) {
225
- const polyline = convertPolylineToWorldSpace(newPolylines[i], viewport);
226
- const startPoint = polyline[0];
227
- const endPoint = polyline[polyline.length - 1];
228
- const newAnnotation = {
336
+ const polyline = newPolylines[i];
337
+ const startPoint = viewport.canvasToWorld(polyline[0]);
338
+ const endPoint = viewport.canvasToWorld(polyline[polyline.length - 1]);
339
+ const newAnnotation: ContourAnnotation = {
229
340
  metadata: {
230
341
  ...metadata,
231
342
  toolName: DEFAULT_CONTOUR_SEG_TOOLNAME,
@@ -237,7 +348,7 @@ function processContours(
237
348
  textBox: textBox ? { ...textBox } : undefined,
238
349
  },
239
350
  contour: {
240
- polyline,
351
+ polyline: [],
241
352
  closed: true,
242
353
  },
243
354
  segmentation: {
@@ -251,23 +362,48 @@ function processContours(
251
362
  isVisible: undefined,
252
363
  };
253
364
 
254
- addAnnotation(newAnnotation, element);
365
+ // Calling `updateContourPolyline` method instead of setting it locally
366
+ // because it is also responsible for checking/setting the winding direction.
367
+ contourUtils.updateContourPolyline(
368
+ newAnnotation,
369
+ {
370
+ points: polyline,
371
+ closed: true,
372
+ targetWindingDirection: ContourWindingDirection.Clockwise,
373
+ },
374
+ viewport
375
+ );
255
376
 
256
- // Updating a Spline contours, for example, should also update freehand contours
257
- const updatedTtoolNames = new Set([
258
- DEFAULT_CONTOUR_SEG_TOOLNAME,
259
- targetAnnotation.metadata.toolName,
260
- ]);
377
+ addAnnotation(newAnnotation, element);
261
378
 
262
- for (const toolName of updatedTtoolNames.values()) {
263
- const viewportIdsToRender = getViewportIdsWithToolToRender(
264
- element,
265
- toolName
266
- );
267
- triggerAnnotationRenderForViewportIds(
268
- renderingEngine,
269
- viewportIdsToRender
379
+ reassignedContourHolesMap
380
+ .get(polyline)
381
+ ?.forEach((holeData) =>
382
+ addChildAnnotation(newAnnotation, holeData.annotation)
270
383
  );
271
- }
272
384
  }
385
+
386
+ updateViewports(enabledElement, targetAnnotation, sourceAnnotation);
387
+ }
388
+
389
+ function updateViewports(enabledElement, targetAnnotation, sourceAnnotation) {
390
+ const { viewport } = enabledElement;
391
+ const { element } = viewport;
392
+ const { renderingEngine } = enabledElement;
393
+
394
+ const updatedTtoolNames = new Set([
395
+ DEFAULT_CONTOUR_SEG_TOOLNAME,
396
+ targetAnnotation.metadata.toolName,
397
+ sourceAnnotation.metadata.toolName,
398
+ ]);
399
+
400
+ for (const toolName of updatedTtoolNames.values()) {
401
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
402
+ element,
403
+ toolName
404
+ );
405
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
406
+ }
407
+
408
+ return new Promise((resolve) => window.requestAnimationFrame(resolve));
273
409
  }
@@ -59,6 +59,81 @@ function getAnnotations(
59
59
  return manager.getAnnotations(groupKey, toolName) as Annotations;
60
60
  }
61
61
 
62
+ /**
63
+ * Removes the association between the annotation passed as parameter and its
64
+ * parent in case it has one (eg: contour holes).
65
+ * @param annotation - Annotation
66
+ */
67
+ function clearParentAnnotation(annotation: Annotation): void {
68
+ const { annotationUID: childUID, parentAnnotationUID } = annotation;
69
+
70
+ if (!parentAnnotationUID) {
71
+ return;
72
+ }
73
+
74
+ const parentAnnotation = getAnnotation(parentAnnotationUID);
75
+ const childUIDIndex = parentAnnotation.childAnnotationUIDs.indexOf(childUID);
76
+
77
+ parentAnnotation.childAnnotationUIDs.splice(childUIDIndex, 1);
78
+ annotation.parentAnnotationUID = undefined;
79
+ }
80
+
81
+ /**
82
+ * Creates a parent/child association between annotations.
83
+ * A annotation may have only one parent and multiple children (eg: a contour
84
+ * may have multiple holes in it).
85
+ * @param parentAnnotation - Parent annotation
86
+ * @param childAnnotation - Child annotation
87
+ */
88
+ function addChildAnnotation(
89
+ parentAnnotation: Annotation,
90
+ childAnnotation: Annotation
91
+ ): void {
92
+ const { annotationUID: parentUID } = parentAnnotation;
93
+ const { annotationUID: childUID } = childAnnotation;
94
+
95
+ // Make sure it is not associated with any other tool
96
+ clearParentAnnotation(childAnnotation);
97
+
98
+ if (!parentAnnotation.childAnnotationUIDs) {
99
+ parentAnnotation.childAnnotationUIDs = [];
100
+ }
101
+
102
+ // Check if it is already a child
103
+ if (parentAnnotation.childAnnotationUIDs.includes(childUID)) {
104
+ return;
105
+ }
106
+
107
+ parentAnnotation.childAnnotationUIDs.push(childUID);
108
+ childAnnotation.parentAnnotationUID = parentUID;
109
+ }
110
+
111
+ /**
112
+ * Returns the parent annotation of a given one since annotations can be
113
+ * associated in a parent/child way (eg: polyline holes)
114
+ * @param annotation - Annotation
115
+ * @returns Parent annotation
116
+ */
117
+ function getParentAnnotation(annotation: Annotation) {
118
+ return annotation.parentAnnotationUID
119
+ ? getAnnotation(annotation.parentAnnotationUID)
120
+ : undefined;
121
+ }
122
+
123
+ /**
124
+ * Returns all children annotation of a given one since annotations can be
125
+ * associated in a parent/child way (eg: polyline holes)
126
+ * @param annotation - Annotation
127
+ * @returns Child annotations
128
+ */
129
+ function getChildAnnotations(annotation: Annotation) {
130
+ return (
131
+ annotation.childAnnotationUIDs?.map((childAnnotationUID) =>
132
+ getAnnotation(childAnnotationUID)
133
+ ) ?? []
134
+ );
135
+ }
136
+
62
137
  /**
63
138
  * Add the annotation to the annotation manager along with the options that is
64
139
  * used to filter the annotation manager and the annotation group that
@@ -137,6 +212,11 @@ function removeAnnotation(annotationUID: string): void {
137
212
  return;
138
213
  }
139
214
 
215
+ // Remove all child annotations first
216
+ annotation.childAnnotationUIDs?.forEach((childAnnotationUID) =>
217
+ removeAnnotation(childAnnotationUID)
218
+ );
219
+
140
220
  manager.removeAnnotation(annotationUID);
141
221
 
142
222
  // trigger annotation removed
@@ -169,8 +249,28 @@ function removeAllAnnotations(): void {
169
249
  manager.removeAllAnnotations();
170
250
  }
171
251
 
252
+ /**
253
+ * Invalidate current and all parent annotations (eg: contour holes)
254
+ * @param annotation - Annotation
255
+ */
256
+ function invalidateAnnotation(annotation: Annotation): void {
257
+ let currAnnotation = annotation;
258
+
259
+ while (currAnnotation) {
260
+ currAnnotation.invalidated = true;
261
+
262
+ currAnnotation = currAnnotation.parentAnnotationUID
263
+ ? getAnnotation(currAnnotation.parentAnnotationUID)
264
+ : undefined;
265
+ }
266
+ }
267
+
172
268
  export {
173
269
  getAnnotations,
270
+ getParentAnnotation,
271
+ getChildAnnotations,
272
+ clearParentAnnotation,
273
+ addChildAnnotation,
174
274
  getNumberOfAnnotations,
175
275
  addAnnotation,
176
276
  getAnnotation,
@@ -180,4 +280,5 @@ export {
180
280
  setAnnotationManager,
181
281
  getAnnotationManager,
182
282
  resetAnnotationManager,
283
+ invalidateAnnotation,
183
284
  };