@cornerstonejs/tools 0.56.1 → 0.56.3

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 (360) hide show
  1. package/dist/cjs/tools/CrosshairsTool.d.ts +1 -0
  2. package/dist/cjs/tools/CrosshairsTool.js +4 -1
  3. package/dist/cjs/tools/CrosshairsTool.js.map +1 -1
  4. package/dist/esm/tools/CrosshairsTool.d.ts +1 -0
  5. package/dist/esm/tools/CrosshairsTool.js +4 -1
  6. package/dist/esm/tools/CrosshairsTool.js.map +1 -1
  7. package/dist/umd/index.js +1 -1
  8. package/dist/umd/index.js.map +1 -1
  9. package/package.json +5 -4
  10. package/src/constants/COLOR_LUT.ts +262 -0
  11. package/src/constants/index.ts +3 -0
  12. package/src/cursors/ImageMouseCursor.ts +39 -0
  13. package/src/cursors/MouseCursor.ts +114 -0
  14. package/src/cursors/SVGCursorDescriptor.ts +462 -0
  15. package/src/cursors/SVGMouseCursor.ts +145 -0
  16. package/src/cursors/elementCursor.ts +69 -0
  17. package/src/cursors/index.ts +24 -0
  18. package/src/cursors/setCursorForElement.ts +33 -0
  19. package/src/drawingSvg/_getHash.ts +9 -0
  20. package/src/drawingSvg/_setAttributesIfNecessary.ts +13 -0
  21. package/src/drawingSvg/_setNewAttributesIfValid.ts +10 -0
  22. package/src/drawingSvg/clearByToolType.ts +26 -0
  23. package/src/drawingSvg/draw.ts +16 -0
  24. package/src/drawingSvg/drawArrow.ts +82 -0
  25. package/src/drawingSvg/drawCircle.ts +62 -0
  26. package/src/drawingSvg/drawEllipse.ts +71 -0
  27. package/src/drawingSvg/drawHandles.ts +87 -0
  28. package/src/drawingSvg/drawLine.ts +70 -0
  29. package/src/drawingSvg/drawLink.ts +76 -0
  30. package/src/drawingSvg/drawLinkedTextBox.ts +64 -0
  31. package/src/drawingSvg/drawPolyline.ts +80 -0
  32. package/src/drawingSvg/drawRect.ts +70 -0
  33. package/src/drawingSvg/drawTextBox.ts +213 -0
  34. package/src/drawingSvg/getSvgDrawingHelper.ts +98 -0
  35. package/src/drawingSvg/index.ts +23 -0
  36. package/src/enums/AnnotationStyleStates.ts +22 -0
  37. package/src/enums/Events.ts +242 -0
  38. package/src/enums/SegmentationRepresentations.ts +12 -0
  39. package/src/enums/ToolBindings.ts +37 -0
  40. package/src/enums/ToolModes.ts +31 -0
  41. package/src/enums/Touch.ts +8 -0
  42. package/src/enums/index.js +16 -0
  43. package/src/eventDispatchers/annotationModifiedEventDispatcher.ts +41 -0
  44. package/src/eventDispatchers/cameraModifiedEventDispatcher.ts +41 -0
  45. package/src/eventDispatchers/imageRenderedEventDispatcher.ts +37 -0
  46. package/src/eventDispatchers/imageSpacingCalibratedEventDispatcher.ts +50 -0
  47. package/src/eventDispatchers/index.js +15 -0
  48. package/src/eventDispatchers/keyboardEventHandlers/index.js +4 -0
  49. package/src/eventDispatchers/keyboardEventHandlers/keyDown.ts +29 -0
  50. package/src/eventDispatchers/keyboardEventHandlers/keyUp.ts +33 -0
  51. package/src/eventDispatchers/keyboardToolEventDispatcher.ts +28 -0
  52. package/src/eventDispatchers/mouseEventHandlers/index.js +19 -0
  53. package/src/eventDispatchers/mouseEventHandlers/mouseClick.ts +13 -0
  54. package/src/eventDispatchers/mouseEventHandlers/mouseDoubleClick.ts +13 -0
  55. package/src/eventDispatchers/mouseEventHandlers/mouseDown.ts +196 -0
  56. package/src/eventDispatchers/mouseEventHandlers/mouseDownActivate.ts +35 -0
  57. package/src/eventDispatchers/mouseEventHandlers/mouseDrag.ts +25 -0
  58. package/src/eventDispatchers/mouseEventHandlers/mouseMove.ts +70 -0
  59. package/src/eventDispatchers/mouseEventHandlers/mouseUp.ts +9 -0
  60. package/src/eventDispatchers/mouseEventHandlers/mouseWheel.ts +13 -0
  61. package/src/eventDispatchers/mouseToolEventDispatcher.ts +64 -0
  62. package/src/eventDispatchers/shared/customCallbackHandler.ts +73 -0
  63. package/src/eventDispatchers/shared/getActiveToolForKeyboardEvent.ts +58 -0
  64. package/src/eventDispatchers/shared/getActiveToolForMouseEvent.ts +61 -0
  65. package/src/eventDispatchers/shared/getActiveToolForTouchEvent.ts +64 -0
  66. package/src/eventDispatchers/shared/getMouseModifier.ts +30 -0
  67. package/src/eventDispatchers/shared/getToolsWithModesForMouseEvent.ts +56 -0
  68. package/src/eventDispatchers/shared/getToolsWithModesForTouchEvent.ts +54 -0
  69. package/src/eventDispatchers/touchEventHandlers/index.js +15 -0
  70. package/src/eventDispatchers/touchEventHandlers/touchDrag.ts +23 -0
  71. package/src/eventDispatchers/touchEventHandlers/touchEnd.ts +9 -0
  72. package/src/eventDispatchers/touchEventHandlers/touchPress.ts +13 -0
  73. package/src/eventDispatchers/touchEventHandlers/touchStart.ts +174 -0
  74. package/src/eventDispatchers/touchEventHandlers/touchStartActivate.ts +36 -0
  75. package/src/eventDispatchers/touchEventHandlers/touchTap.ts +9 -0
  76. package/src/eventDispatchers/touchToolEventDispatcher.ts +51 -0
  77. package/src/eventListeners/annotations/annotationModifiedListener.ts +22 -0
  78. package/src/eventListeners/annotations/annotationSelectionListener.ts +29 -0
  79. package/src/eventListeners/annotations/index.ts +4 -0
  80. package/src/eventListeners/index.ts +28 -0
  81. package/src/eventListeners/keyboard/index.ts +16 -0
  82. package/src/eventListeners/keyboard/keyDownListener.ts +99 -0
  83. package/src/eventListeners/mouse/getMouseEventPoints.ts +66 -0
  84. package/src/eventListeners/mouse/index.ts +55 -0
  85. package/src/eventListeners/mouse/mouseDoubleClickListener.ts +55 -0
  86. package/src/eventListeners/mouse/mouseDownListener.ts +519 -0
  87. package/src/eventListeners/mouse/mouseMoveListener.ts +33 -0
  88. package/src/eventListeners/segmentation/index.ts +11 -0
  89. package/src/eventListeners/segmentation/segmentationDataModifiedEventListener.ts +61 -0
  90. package/src/eventListeners/segmentation/segmentationModifiedEventListener.ts +32 -0
  91. package/src/eventListeners/segmentation/segmentationRepresentationModifiedEventListener.ts +15 -0
  92. package/src/eventListeners/segmentation/segmentationRepresentationRemovedEventListener.ts +16 -0
  93. package/src/eventListeners/touch/getTouchEventPoints.ts +75 -0
  94. package/src/eventListeners/touch/index.ts +37 -0
  95. package/src/eventListeners/touch/preventGhostClick.js +72 -0
  96. package/src/eventListeners/touch/touchStartListener.ts +499 -0
  97. package/src/eventListeners/wheel/index.ts +27 -0
  98. package/src/eventListeners/wheel/normalizeWheel.ts +69 -0
  99. package/src/eventListeners/wheel/wheelListener.ts +51 -0
  100. package/src/index.ts +133 -0
  101. package/src/init.ts +187 -0
  102. package/src/stateManagement/annotation/FrameOfReferenceSpecificAnnotationManager.ts +399 -0
  103. package/src/stateManagement/annotation/annotationLocking.ts +178 -0
  104. package/src/stateManagement/annotation/annotationSelection.ts +163 -0
  105. package/src/stateManagement/annotation/annotationState.ts +180 -0
  106. package/src/stateManagement/annotation/annotationVisibility.ts +156 -0
  107. package/src/stateManagement/annotation/config/ToolStyle.ts +265 -0
  108. package/src/stateManagement/annotation/config/getFont.ts +36 -0
  109. package/src/stateManagement/annotation/config/getState.ts +26 -0
  110. package/src/stateManagement/annotation/config/helpers.ts +55 -0
  111. package/src/stateManagement/annotation/config/index.ts +5 -0
  112. package/src/stateManagement/annotation/helpers/state.ts +83 -0
  113. package/src/stateManagement/annotation/index.ts +15 -0
  114. package/src/stateManagement/index.js +40 -0
  115. package/src/stateManagement/segmentation/SegmentationStateManager.ts +491 -0
  116. package/src/stateManagement/segmentation/activeSegmentation.ts +60 -0
  117. package/src/stateManagement/segmentation/addSegmentationRepresentations.ts +77 -0
  118. package/src/stateManagement/segmentation/addSegmentations.ts +27 -0
  119. package/src/stateManagement/segmentation/config/index.ts +29 -0
  120. package/src/stateManagement/segmentation/config/segmentationColor.ts +132 -0
  121. package/src/stateManagement/segmentation/config/segmentationConfig.ts +195 -0
  122. package/src/stateManagement/segmentation/config/segmentationVisibility.ts +171 -0
  123. package/src/stateManagement/segmentation/helpers/index.ts +3 -0
  124. package/src/stateManagement/segmentation/helpers/normalizeSegmentationInput.ts +35 -0
  125. package/src/stateManagement/segmentation/helpers/validateSegmentationInput.ts +41 -0
  126. package/src/stateManagement/segmentation/index.ts +22 -0
  127. package/src/stateManagement/segmentation/removeSegmentationsFromToolGroup.ts +85 -0
  128. package/src/stateManagement/segmentation/segmentIndex.ts +38 -0
  129. package/src/stateManagement/segmentation/segmentLocking.ts +72 -0
  130. package/src/stateManagement/segmentation/segmentationState.ts +429 -0
  131. package/src/stateManagement/segmentation/triggerSegmentationEvents.ts +157 -0
  132. package/src/store/SynchronizerManager/Synchronizer.ts +344 -0
  133. package/src/store/SynchronizerManager/createSynchronizer.ts +41 -0
  134. package/src/store/SynchronizerManager/destroy.ts +14 -0
  135. package/src/store/SynchronizerManager/destroySynchronizer.ts +25 -0
  136. package/src/store/SynchronizerManager/getAllSynchronizers.ts +12 -0
  137. package/src/store/SynchronizerManager/getSynchronizer.ts +13 -0
  138. package/src/store/SynchronizerManager/getSynchronizersForViewport.ts +44 -0
  139. package/src/store/SynchronizerManager/index.js +15 -0
  140. package/src/store/ToolGroupManager/ToolGroup.ts +679 -0
  141. package/src/store/ToolGroupManager/createToolGroup.ts +33 -0
  142. package/src/store/ToolGroupManager/destroy.ts +24 -0
  143. package/src/store/ToolGroupManager/destroyToolGroup.ts +26 -0
  144. package/src/store/ToolGroupManager/getAllToolGroups.ts +12 -0
  145. package/src/store/ToolGroupManager/getToolGroup.ts +14 -0
  146. package/src/store/ToolGroupManager/getToolGroupForViewport.ts +44 -0
  147. package/src/store/ToolGroupManager/getToolGroupsWithToolName.ts +33 -0
  148. package/src/store/ToolGroupManager/index.ts +17 -0
  149. package/src/store/addEnabledElement.ts +137 -0
  150. package/src/store/addTool.ts +56 -0
  151. package/src/store/cancelActiveManipulations.ts +30 -0
  152. package/src/store/filterMoveableAnnotationTools.ts +61 -0
  153. package/src/store/filterToolsWithAnnotationsForElement.ts +51 -0
  154. package/src/store/filterToolsWithMoveableHandles.ts +51 -0
  155. package/src/store/index.ts +29 -0
  156. package/src/store/removeEnabledElement.ts +132 -0
  157. package/src/store/state.ts +57 -0
  158. package/src/store/svgNodeCache.ts +7 -0
  159. package/src/synchronizers/callbacks/areViewportsCoplanar .ts +12 -0
  160. package/src/synchronizers/callbacks/cameraSyncCallback.ts +33 -0
  161. package/src/synchronizers/callbacks/stackImageSyncCallback.ts +157 -0
  162. package/src/synchronizers/callbacks/voiSyncCallback.ts +51 -0
  163. package/src/synchronizers/callbacks/zoomPanSyncCallback.ts +43 -0
  164. package/src/synchronizers/index.ts +11 -0
  165. package/src/synchronizers/synchronizers/createCameraPositionSynchronizer.ts +25 -0
  166. package/src/synchronizers/synchronizers/createStackImageSynchronizer.ts +25 -0
  167. package/src/synchronizers/synchronizers/createVOISynchronizer.ts +24 -0
  168. package/src/synchronizers/synchronizers/createZoomPanSynchronizer.ts +25 -0
  169. package/src/synchronizers/synchronizers/index.ts +11 -0
  170. package/src/tools/CrosshairsTool.ts +2693 -0
  171. package/src/tools/MIPJumpToClickTool.ts +99 -0
  172. package/src/tools/MagnifyTool.ts +319 -0
  173. package/src/tools/PanTool.ts +58 -0
  174. package/src/tools/PlanarRotateTool.ts +77 -0
  175. package/src/tools/ReferenceCursors.ts +466 -0
  176. package/src/tools/ReferenceLinesTool.ts +279 -0
  177. package/src/tools/ScaleOverlayTool.ts +685 -0
  178. package/src/tools/StackScrollTool.ts +97 -0
  179. package/src/tools/StackScrollToolMouseWheelTool.ts +58 -0
  180. package/src/tools/TrackballRotateTool.ts +141 -0
  181. package/src/tools/VolumeRotateMouseWheelTool.ts +86 -0
  182. package/src/tools/WindowLevelTool.ts +260 -0
  183. package/src/tools/ZoomTool.ts +293 -0
  184. package/src/tools/annotation/AngleTool.ts +835 -0
  185. package/src/tools/annotation/ArrowAnnotateTool.ts +820 -0
  186. package/src/tools/annotation/BidirectionalTool.ts +1350 -0
  187. package/src/tools/annotation/CircleROITool.ts +1070 -0
  188. package/src/tools/annotation/CobbAngleTool.ts +815 -0
  189. package/src/tools/annotation/DragProbeTool.ts +213 -0
  190. package/src/tools/annotation/EllipticalROITool.ts +1223 -0
  191. package/src/tools/annotation/LengthTool.ts +861 -0
  192. package/src/tools/annotation/PlanarFreehandROITool.ts +636 -0
  193. package/src/tools/annotation/ProbeTool.ts +681 -0
  194. package/src/tools/annotation/RectangleROITool.ts +1028 -0
  195. package/src/tools/annotation/planarFreehandROITool/closedContourEditLoop.ts +488 -0
  196. package/src/tools/annotation/planarFreehandROITool/drawLoop.ts +462 -0
  197. package/src/tools/annotation/planarFreehandROITool/editLoopCommon.ts +331 -0
  198. package/src/tools/annotation/planarFreehandROITool/findOpenUShapedContourVectorToPeak.ts +74 -0
  199. package/src/tools/annotation/planarFreehandROITool/openContourEditLoop.ts +612 -0
  200. package/src/tools/annotation/planarFreehandROITool/openContourEndEditLoop.ts +74 -0
  201. package/src/tools/annotation/planarFreehandROITool/renderMethods.ts +407 -0
  202. package/src/tools/base/AnnotationDisplayTool.ts +228 -0
  203. package/src/tools/base/AnnotationTool.ts +307 -0
  204. package/src/tools/base/BaseTool.ts +215 -0
  205. package/src/tools/base/index.ts +4 -0
  206. package/src/tools/displayTools/Contour/addContourToElement.ts +135 -0
  207. package/src/tools/displayTools/Contour/contourDisplay.ts +252 -0
  208. package/src/tools/displayTools/Contour/index.ts +3 -0
  209. package/src/tools/displayTools/Contour/removeContourFromElement.ts +35 -0
  210. package/src/tools/displayTools/Labelmap/addLabelmapToElement.ts +57 -0
  211. package/src/tools/displayTools/Labelmap/index.ts +4 -0
  212. package/src/tools/displayTools/Labelmap/labelmapConfig.ts +37 -0
  213. package/src/tools/displayTools/Labelmap/labelmapDisplay.ts +461 -0
  214. package/src/tools/displayTools/Labelmap/removeLabelmapFromElement.ts +27 -0
  215. package/src/tools/displayTools/Labelmap/validateRepresentationData.ts +30 -0
  216. package/src/tools/displayTools/SegmentationDisplayTool.ts +198 -0
  217. package/src/tools/index.ts +84 -0
  218. package/src/tools/segmentation/BrushTool.ts +474 -0
  219. package/src/tools/segmentation/CircleScissorsTool.ts +365 -0
  220. package/src/tools/segmentation/PaintFillTool.ts +370 -0
  221. package/src/tools/segmentation/RectangleROIStartEndThresholdTool.ts +471 -0
  222. package/src/tools/segmentation/RectangleROIThresholdTool.ts +281 -0
  223. package/src/tools/segmentation/RectangleScissorsTool.ts +382 -0
  224. package/src/tools/segmentation/SphereScissorsTool.ts +368 -0
  225. package/src/tools/segmentation/strategies/eraseCircle.ts +30 -0
  226. package/src/tools/segmentation/strategies/eraseRectangle.ts +81 -0
  227. package/src/tools/segmentation/strategies/eraseSphere.ts +27 -0
  228. package/src/tools/segmentation/strategies/fillCircle.ts +185 -0
  229. package/src/tools/segmentation/strategies/fillRectangle.ts +110 -0
  230. package/src/tools/segmentation/strategies/fillSphere.ts +88 -0
  231. package/src/tools/segmentation/strategies/index.ts +9 -0
  232. package/src/types/AnnotationGroupSelector.ts +7 -0
  233. package/src/types/AnnotationStyle.ts +42 -0
  234. package/src/types/AnnotationTypes.ts +109 -0
  235. package/src/types/BoundsIJK.ts +5 -0
  236. package/src/types/CINETypes.ts +32 -0
  237. package/src/types/ContourTypes.ts +26 -0
  238. package/src/types/CursorTypes.ts +12 -0
  239. package/src/types/EventTypes.ts +657 -0
  240. package/src/types/FloodFillTypes.ts +19 -0
  241. package/src/types/IAnnotationManager.ts +89 -0
  242. package/src/types/IDistance.ts +16 -0
  243. package/src/types/IPoints.ts +18 -0
  244. package/src/types/ISetToolModeOptions.ts +29 -0
  245. package/src/types/ISynchronizerEventHandler.ts +11 -0
  246. package/src/types/IToolClassReference.ts +5 -0
  247. package/src/types/IToolGroup.ts +72 -0
  248. package/src/types/ITouchPoints.ts +14 -0
  249. package/src/types/InteractionTypes.ts +6 -0
  250. package/src/types/InternalToolTypes.ts +19 -0
  251. package/src/types/JumpToSliceOptions.ts +7 -0
  252. package/src/types/LabelmapTypes.ts +41 -0
  253. package/src/types/PlanarBoundingBox.ts +8 -0
  254. package/src/types/SVGDrawingHelper.ts +10 -0
  255. package/src/types/ScrollOptions.ts +9 -0
  256. package/src/types/SegmentationStateTypes.ts +248 -0
  257. package/src/types/ToolHandle.ts +26 -0
  258. package/src/types/ToolProps.ts +16 -0
  259. package/src/types/ToolSpecificAnnotationTypes.ts +311 -0
  260. package/src/types/index.ts +115 -0
  261. package/src/utilities/boundingBox/extend2DBoundingBoxInViewAxis.ts +29 -0
  262. package/src/utilities/boundingBox/getBoundingBoxAroundShape.ts +57 -0
  263. package/src/utilities/boundingBox/index.ts +4 -0
  264. package/src/utilities/calibrateImageSpacing.ts +46 -0
  265. package/src/utilities/cine/events.ts +9 -0
  266. package/src/utilities/cine/index.ts +5 -0
  267. package/src/utilities/cine/playClip.ts +435 -0
  268. package/src/utilities/cine/state.ts +18 -0
  269. package/src/utilities/clip.js +30 -0
  270. package/src/utilities/debounce.js +217 -0
  271. package/src/utilities/drawing/getTextBoxCoordsCanvas.ts +45 -0
  272. package/src/utilities/drawing/index.ts +3 -0
  273. package/src/utilities/dynamicVolume/getDataInTime.ts +110 -0
  274. package/src/utilities/dynamicVolume/index.ts +2 -0
  275. package/src/utilities/getAnnotationNearPoint.ts +130 -0
  276. package/src/utilities/getModalityUnit.ts +11 -0
  277. package/src/utilities/getToolsWithModesForElement.ts +52 -0
  278. package/src/utilities/index.ts +68 -0
  279. package/src/utilities/isObject.js +29 -0
  280. package/src/utilities/math/angle/angleBetweenLines.ts +29 -0
  281. package/src/utilities/math/circle/_types.ts +6 -0
  282. package/src/utilities/math/circle/getCanvasCircleCorners.ts +23 -0
  283. package/src/utilities/math/circle/getCanvasCircleRadius.ts +16 -0
  284. package/src/utilities/math/circle/index.ts +4 -0
  285. package/src/utilities/math/ellipse/getCanvasEllipseCorners.ts +26 -0
  286. package/src/utilities/math/ellipse/index.ts +4 -0
  287. package/src/utilities/math/ellipse/pointInEllipse.ts +38 -0
  288. package/src/utilities/math/ellipse/pointInEllipsoidWithConstraint.ts +35 -0
  289. package/src/utilities/math/index.ts +8 -0
  290. package/src/utilities/math/line/distanceToPoint.ts +24 -0
  291. package/src/utilities/math/line/distanceToPointSquared.ts +44 -0
  292. package/src/utilities/math/line/index.ts +5 -0
  293. package/src/utilities/math/line/intersectLine.ts +92 -0
  294. package/src/utilities/math/midPoint.ts +24 -0
  295. package/src/utilities/math/point/distanceToPoint.ts +22 -0
  296. package/src/utilities/math/point/index.ts +3 -0
  297. package/src/utilities/math/polyline/addCanvasPointsToArray.ts +62 -0
  298. package/src/utilities/math/polyline/calculateAreaOfPoints.ts +23 -0
  299. package/src/utilities/math/polyline/getIntersectionWithPolyline.ts +182 -0
  300. package/src/utilities/math/polyline/getSubPixelSpacingAndXYDirections.ts +99 -0
  301. package/src/utilities/math/polyline/index.ts +19 -0
  302. package/src/utilities/math/polyline/planarFreehandROIInternalTypes.ts +36 -0
  303. package/src/utilities/math/polyline/pointCanProjectOnLine.ts +57 -0
  304. package/src/utilities/math/polyline/pointsAreWithinCloseContourProximity.ts +15 -0
  305. package/src/utilities/math/rectangle/distanceToPoint.ts +82 -0
  306. package/src/utilities/math/rectangle/index.ts +3 -0
  307. package/src/utilities/math/sphere/index.ts +3 -0
  308. package/src/utilities/math/sphere/pointInSphere.ts +31 -0
  309. package/src/utilities/math/vec2/findClosestPoint.ts +40 -0
  310. package/src/utilities/math/vec2/index.ts +4 -0
  311. package/src/utilities/math/vec2/liangBarksyClip.ts +84 -0
  312. package/src/utilities/orientation/getOrientationStringLPS.ts +52 -0
  313. package/src/utilities/orientation/index.ts +4 -0
  314. package/src/utilities/orientation/invertOrientationStringLPS.ts +21 -0
  315. package/src/utilities/planar/filterAnnotationsForDisplay.ts +68 -0
  316. package/src/utilities/planar/filterAnnotationsWithinSlice.ts +85 -0
  317. package/src/utilities/planar/getPointInLineOfSightWithCriteria.ts +104 -0
  318. package/src/utilities/planar/getWorldWidthAndHeightFromCorners.ts +51 -0
  319. package/src/utilities/planar/getWorldWidthAndHeightFromTwoPoints.ts +51 -0
  320. package/src/utilities/planar/index.ts +18 -0
  321. package/src/utilities/planarFreehandROITool/index.ts +7 -0
  322. package/src/utilities/planarFreehandROITool/interpolateAnnotation.ts +87 -0
  323. package/src/utilities/planarFreehandROITool/interpolatePoints.ts +214 -0
  324. package/src/utilities/planarFreehandROITool/interpolation/algorithms/bspline.ts +55 -0
  325. package/src/utilities/planarFreehandROITool/interpolation/interpolateSegmentPoints.ts +90 -0
  326. package/src/utilities/pointInShapeCallback.ts +138 -0
  327. package/src/utilities/pointInSurroundingSphereCallback.ts +188 -0
  328. package/src/utilities/rectangleROITool/getBoundsIJKFromRectangleAnnotations.ts +76 -0
  329. package/src/utilities/rectangleROITool/index.ts +3 -0
  330. package/src/utilities/scroll.ts +62 -0
  331. package/src/utilities/segmentation/brushSizeForToolGroup.ts +72 -0
  332. package/src/utilities/segmentation/brushThresholdForToolGroup.ts +65 -0
  333. package/src/utilities/segmentation/createLabelmapVolumeForViewport.ts +74 -0
  334. package/src/utilities/segmentation/createMergedLabelmapForIndex.ts +65 -0
  335. package/src/utilities/segmentation/floodFill.ts +194 -0
  336. package/src/utilities/segmentation/getDefaultRepresentationConfig.ts +20 -0
  337. package/src/utilities/segmentation/index.ts +33 -0
  338. package/src/utilities/segmentation/isValidRepresentationConfig.ts +22 -0
  339. package/src/utilities/segmentation/rectangleROIThresholdVolumeByRange.ts +91 -0
  340. package/src/utilities/segmentation/thresholdSegmentationByRange.ts +129 -0
  341. package/src/utilities/segmentation/thresholdVolumeByRange.ts +150 -0
  342. package/src/utilities/segmentation/triggerSegmentationRender.ts +206 -0
  343. package/src/utilities/segmentation/utilities.ts +116 -0
  344. package/src/utilities/stackPrefetch/index.ts +8 -0
  345. package/src/utilities/stackPrefetch/stackPrefetch.ts +405 -0
  346. package/src/utilities/stackPrefetch/state.ts +17 -0
  347. package/src/utilities/throttle.js +69 -0
  348. package/src/utilities/touch/index.ts +246 -0
  349. package/src/utilities/triggerAnnotationRender.ts +237 -0
  350. package/src/utilities/triggerAnnotationRenderForViewportIds.ts +18 -0
  351. package/src/utilities/viewport/index.ts +5 -0
  352. package/src/utilities/viewport/isViewportPreScaled.ts +24 -0
  353. package/src/utilities/viewport/jumpToSlice.ts +73 -0
  354. package/src/utilities/viewport/jumpToWorld.ts +58 -0
  355. package/src/utilities/viewportFilters/filterViewportsWithFrameOfReferenceUID.ts +28 -0
  356. package/src/utilities/viewportFilters/filterViewportsWithParallelNormals.ts +26 -0
  357. package/src/utilities/viewportFilters/filterViewportsWithSameOrientation.ts +15 -0
  358. package/src/utilities/viewportFilters/filterViewportsWithToolEnabled.ts +72 -0
  359. package/src/utilities/viewportFilters/getViewportIdsWithToolToRender.ts +45 -0
  360. package/src/utilities/viewportFilters/index.ts +11 -0
@@ -0,0 +1,1350 @@
1
+ import { vec2, vec3, mat2, mat3, mat2d } from 'gl-matrix';
2
+ import {
3
+ getEnabledElement,
4
+ triggerEvent,
5
+ eventTarget,
6
+ utilities as csUtils,
7
+ } from '@cornerstonejs/core';
8
+ import type { Types } from '@cornerstonejs/core';
9
+
10
+ import { AnnotationTool } from '../base';
11
+ import throttle from '../../utilities/throttle';
12
+ import {
13
+ addAnnotation,
14
+ getAnnotations,
15
+ removeAnnotation,
16
+ } from '../../stateManagement/annotation/annotationState';
17
+ import { isAnnotationLocked } from '../../stateManagement/annotation/annotationLocking';
18
+ import { isAnnotationVisible } from '../../stateManagement/annotation/annotationVisibility';
19
+ import {
20
+ drawLine as drawLineSvg,
21
+ drawHandles as drawHandlesSvg,
22
+ drawLinkedTextBox as drawLinkedTextBoxSvg,
23
+ } from '../../drawingSvg';
24
+ import { state } from '../../store';
25
+ import { Events } from '../../enums';
26
+ import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
27
+ import * as lineSegment from '../../utilities/math/line';
28
+ import { getTextBoxCoordsCanvas } from '../../utilities/drawing';
29
+ import {
30
+ resetElementCursor,
31
+ hideElementCursor,
32
+ } from '../../cursors/elementCursor';
33
+ import {
34
+ EventTypes,
35
+ ToolHandle,
36
+ TextBoxHandle,
37
+ PublicToolProps,
38
+ ToolProps,
39
+ InteractionTypes,
40
+ SVGDrawingHelper,
41
+ } from '../../types';
42
+ import { BidirectionalAnnotation } from '../../types/ToolSpecificAnnotationTypes';
43
+
44
+ import {
45
+ AnnotationCompletedEventDetail,
46
+ AnnotationModifiedEventDetail,
47
+ MouseDragEventType,
48
+ MouseMoveEventType,
49
+ } from '../../types/EventTypes';
50
+ import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
51
+ import { StyleSpecifier } from '../../types/AnnotationStyle';
52
+
53
+ const { transformWorldToIndex } = csUtils;
54
+
55
+ /**
56
+ * BidirectionalTool let you draw annotations that measures the length and
57
+ * width at the same time in `mm` unit. It is consisted of two perpendicular lines and
58
+ * a text box. You can use the BidirectionalTool in all planes even in oblique
59
+ * reconstructed planes. Note: annotation tools in cornerstone3DTools exists in the exact location
60
+ * in the physical 3d space, as a result, by default, all annotations that are
61
+ * drawing in the same frameOfReference will get shared between viewports that
62
+ * are in the same frameOfReference.
63
+ *
64
+ * The resulting annotation's data (statistics) and metadata (the
65
+ * state of the viewport while drawing was happening) will get added to the
66
+ * ToolState manager and can be accessed from the ToolState by calling getAnnotations
67
+ * or similar methods.
68
+ *
69
+ * ```js
70
+ * cornerstoneTools.addTool(BidirectionalTool)
71
+ *
72
+ * const toolGroup = ToolGroupManager.createToolGroup('toolGroupId')
73
+ *
74
+ * toolGroup.addTool(BidirectionalTool.toolName)
75
+ *
76
+ * toolGroup.addViewport('viewportId', 'renderingEngineId')
77
+ *
78
+ * toolGroup.setToolActive(BidirectionalTool.toolName, {
79
+ * bindings: [
80
+ * {
81
+ * mouseButton: MouseBindings.Primary, // Left Click
82
+ * },
83
+ * ],
84
+ * })
85
+ * ```
86
+ *
87
+ * Read more in the Docs section of the website.
88
+ */
89
+ class BidirectionalTool extends AnnotationTool {
90
+ static toolName;
91
+
92
+ touchDragCallback: any;
93
+ mouseDragCallback: any;
94
+ _throttledCalculateCachedStats: any;
95
+ editData: {
96
+ annotation: any;
97
+ viewportIdsToRender: string[];
98
+ handleIndex?: number;
99
+ movingTextBox: boolean;
100
+ newAnnotation?: boolean;
101
+ hasMoved?: boolean;
102
+ } | null;
103
+ isDrawing: boolean;
104
+ isHandleOutsideImage: boolean;
105
+ preventHandleOutsideImage: boolean;
106
+
107
+ constructor(
108
+ toolProps: PublicToolProps = {},
109
+ defaultToolProps: ToolProps = {
110
+ supportedInteractionTypes: ['Mouse', 'Touch'],
111
+ configuration: {
112
+ preventHandleOutsideImage: false,
113
+ },
114
+ }
115
+ ) {
116
+ super(toolProps, defaultToolProps);
117
+
118
+ this._throttledCalculateCachedStats = throttle(
119
+ this._calculateCachedStats,
120
+ 100,
121
+ { trailing: true }
122
+ );
123
+ }
124
+
125
+ /**
126
+ * Based on the current position of the mouse and the current imageId to create
127
+ * a Bidirectional Annotation and stores it in the annotationManager
128
+ *
129
+ * @param evt - EventTypes.NormalizedMouseEventType
130
+ * @returns The annotation object.
131
+ *
132
+ */
133
+ addNewAnnotation(
134
+ evt: EventTypes.InteractionEventType
135
+ ): BidirectionalAnnotation {
136
+ const eventDetail = evt.detail;
137
+ const { currentPoints, element } = eventDetail;
138
+ const worldPos = currentPoints.world;
139
+ const enabledElement = getEnabledElement(element);
140
+ const { viewport, renderingEngine } = enabledElement;
141
+
142
+ this.isDrawing = true;
143
+
144
+ const camera = viewport.getCamera();
145
+ const { viewPlaneNormal, viewUp } = camera;
146
+
147
+ const referencedImageId = this.getReferencedImageId(
148
+ viewport,
149
+ worldPos,
150
+ viewPlaneNormal,
151
+ viewUp
152
+ );
153
+
154
+ const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
155
+
156
+ const annotation: BidirectionalAnnotation = {
157
+ highlighted: true,
158
+ invalidated: true,
159
+ metadata: {
160
+ toolName: this.getToolName(),
161
+ viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
162
+ viewUp: <Types.Point3>[...viewUp],
163
+ FrameOfReferenceUID,
164
+ referencedImageId,
165
+ },
166
+ data: {
167
+ handles: {
168
+ points: [
169
+ // long
170
+ <Types.Point3>[...worldPos],
171
+ <Types.Point3>[...worldPos],
172
+ // short
173
+ <Types.Point3>[...worldPos],
174
+ <Types.Point3>[...worldPos],
175
+ ],
176
+ textBox: {
177
+ hasMoved: false,
178
+ worldPosition: <Types.Point3>[0, 0, 0],
179
+ worldBoundingBox: {
180
+ topLeft: <Types.Point3>[0, 0, 0],
181
+ topRight: <Types.Point3>[0, 0, 0],
182
+ bottomLeft: <Types.Point3>[0, 0, 0],
183
+ bottomRight: <Types.Point3>[0, 0, 0],
184
+ },
185
+ },
186
+ activeHandleIndex: null,
187
+ },
188
+ label: '',
189
+ cachedStats: {},
190
+ },
191
+ };
192
+
193
+ addAnnotation(annotation, element);
194
+
195
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
196
+ element,
197
+ this.getToolName()
198
+ );
199
+
200
+ this.editData = {
201
+ annotation,
202
+ viewportIdsToRender,
203
+ handleIndex: 1,
204
+ movingTextBox: false,
205
+ newAnnotation: true,
206
+ hasMoved: false,
207
+ };
208
+ this._activateDraw(element);
209
+
210
+ hideElementCursor(element);
211
+
212
+ evt.preventDefault();
213
+
214
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
215
+
216
+ return annotation;
217
+ }
218
+
219
+ /**
220
+ * It returns if the canvas point is near the provided annotation in the provided
221
+ * element or not. A proximity is passed to the function to determine the
222
+ * proximity of the point to the annotation in number of pixels.
223
+ *
224
+ * @param element - HTML Element
225
+ * @param annotation - Annotation
226
+ * @param canvasCoords - Canvas coordinates
227
+ * @param proximity - Proximity to tool to consider
228
+ * @returns Boolean, whether the canvas point is near tool
229
+ */
230
+ isPointNearTool = (
231
+ element: HTMLDivElement,
232
+ annotation: BidirectionalAnnotation,
233
+ canvasCoords: Types.Point2,
234
+ proximity: number
235
+ ): boolean => {
236
+ const enabledElement = getEnabledElement(element);
237
+ const { viewport } = enabledElement;
238
+ const { data } = annotation;
239
+ const { points } = data.handles;
240
+
241
+ // Check long axis
242
+ let canvasPoint1 = viewport.worldToCanvas(points[0]);
243
+ let canvasPoint2 = viewport.worldToCanvas(points[1]);
244
+
245
+ let line = {
246
+ start: {
247
+ x: canvasPoint1[0],
248
+ y: canvasPoint1[1],
249
+ },
250
+ end: {
251
+ x: canvasPoint2[0],
252
+ y: canvasPoint2[1],
253
+ },
254
+ };
255
+
256
+ let distanceToPoint = lineSegment.distanceToPoint(
257
+ [line.start.x, line.start.y],
258
+ [line.end.x, line.end.y],
259
+ [canvasCoords[0], canvasCoords[1]]
260
+ );
261
+
262
+ if (distanceToPoint <= proximity) {
263
+ return true;
264
+ }
265
+
266
+ // Check short axis
267
+ canvasPoint1 = viewport.worldToCanvas(points[2]);
268
+ canvasPoint2 = viewport.worldToCanvas(points[3]);
269
+
270
+ line = {
271
+ start: {
272
+ x: canvasPoint1[0],
273
+ y: canvasPoint1[1],
274
+ },
275
+ end: {
276
+ x: canvasPoint2[0],
277
+ y: canvasPoint2[1],
278
+ },
279
+ };
280
+
281
+ distanceToPoint = lineSegment.distanceToPoint(
282
+ [line.start.x, line.start.y],
283
+ [line.end.x, line.end.y],
284
+ [canvasCoords[0], canvasCoords[1]]
285
+ );
286
+
287
+ if (distanceToPoint <= proximity) {
288
+ return true;
289
+ }
290
+
291
+ return false;
292
+ };
293
+
294
+ /**
295
+ * Handles the toolSelected callback for bidirectional tool
296
+ * @param evt - EventTypes.MouseDownEventType
297
+ * @param annotation - Bidirectional annotation
298
+ * @param interactionType - interaction type (mouse, touch)
299
+ */
300
+ toolSelectedCallback = (
301
+ evt: EventTypes.InteractionEventType,
302
+ annotation: BidirectionalAnnotation
303
+ ): void => {
304
+ const eventDetail = evt.detail;
305
+ const { element } = eventDetail;
306
+
307
+ annotation.highlighted = true;
308
+
309
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
310
+ element,
311
+ this.getToolName()
312
+ );
313
+
314
+ this.editData = {
315
+ annotation,
316
+ viewportIdsToRender,
317
+ movingTextBox: false,
318
+ };
319
+
320
+ this._activateModify(element);
321
+
322
+ const enabledElement = getEnabledElement(element);
323
+ const { renderingEngine } = enabledElement;
324
+
325
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
326
+
327
+ hideElementCursor(element);
328
+
329
+ evt.preventDefault();
330
+ };
331
+
332
+ /**
333
+ * Executes the callback for when mouse has selected a handle (anchor point) of
334
+ * the bidirectional tool or when the text box has been selected.
335
+ *
336
+ * @param evt - EventTypes.MouseDownEventType
337
+ * @param annotation - Bidirectional annotation
338
+ * @param handle - Handle index or selected textBox information
339
+ * @param interactionType - interaction type (mouse, touch)
340
+ */
341
+ handleSelectedCallback = (
342
+ evt: EventTypes.InteractionEventType,
343
+ annotation: BidirectionalAnnotation,
344
+ handle: ToolHandle
345
+ ): void => {
346
+ const eventDetail = evt.detail;
347
+ const { element } = eventDetail;
348
+ const data = annotation.data;
349
+
350
+ annotation.highlighted = true;
351
+
352
+ let movingTextBox = false;
353
+ let handleIndex;
354
+
355
+ if ((handle as TextBoxHandle).worldPosition) {
356
+ movingTextBox = true;
357
+ } else {
358
+ handleIndex = data.handles.points.findIndex((p) => p === handle);
359
+ }
360
+
361
+ // Find viewports to render on drag.
362
+ const viewportIdsToRender = getViewportIdsWithToolToRender(
363
+ element,
364
+ this.getToolName()
365
+ );
366
+
367
+ hideElementCursor(element);
368
+
369
+ this.editData = {
370
+ annotation,
371
+ viewportIdsToRender,
372
+ handleIndex,
373
+ movingTextBox,
374
+ };
375
+ this._activateModify(element);
376
+
377
+ const enabledElement = getEnabledElement(element);
378
+ const { renderingEngine } = enabledElement;
379
+
380
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
381
+
382
+ evt.preventDefault();
383
+ };
384
+
385
+ /**
386
+ * Handles the mouse up action for the bidirectional tool. It can be at the end
387
+ * of the annotation drawing (MouseUpEventType) or when the user clicks and release
388
+ * the mouse button instantly which let to the annotation to draw without holding
389
+ * the mouse button (MouseClickEventType).
390
+ *
391
+ * @param evt - mouse up or mouse click event types
392
+ */
393
+ _endCallback = (evt: EventTypes.InteractionEventType): void => {
394
+ const eventDetail = evt.detail;
395
+ const { element } = eventDetail;
396
+
397
+ const { annotation, viewportIdsToRender, newAnnotation, hasMoved } =
398
+ this.editData;
399
+ const { data } = annotation;
400
+
401
+ if (newAnnotation && !hasMoved) {
402
+ return;
403
+ }
404
+
405
+ data.handles.activeHandleIndex = null;
406
+
407
+ this._deactivateModify(element);
408
+ this._deactivateDraw(element);
409
+
410
+ resetElementCursor(element);
411
+
412
+ const enabledElement = getEnabledElement(element);
413
+ const { renderingEngine } = enabledElement;
414
+
415
+ if (this.editData.handleIndex !== undefined) {
416
+ const { points } = data.handles;
417
+ const firstLineSegmentLength = vec3.distance(points[0], points[1]);
418
+ const secondLineSegmentLength = vec3.distance(points[2], points[3]);
419
+
420
+ if (secondLineSegmentLength > firstLineSegmentLength) {
421
+ // Switch points so [0,1] is the long axis and [2,3] is the short axis.
422
+
423
+ const longAxis = [[...points[2]], [...points[3]]];
424
+
425
+ const shortAxisPoint0 = [...points[0]];
426
+ const shortAxisPoint1 = [...points[1]];
427
+
428
+ // shortAxis[0->1] should be perpendicular (counter-clockwise) to longAxis[0->1]
429
+ const longAxisVector = vec2.create();
430
+
431
+ vec2.set(
432
+ longAxisVector,
433
+ longAxis[1][0] - longAxis[0][0],
434
+ longAxis[1][1] - longAxis[1][0]
435
+ );
436
+
437
+ const counterClockWisePerpendicularToLongAxis = vec2.create();
438
+
439
+ vec2.set(
440
+ counterClockWisePerpendicularToLongAxis,
441
+ -longAxisVector[1],
442
+ longAxisVector[0]
443
+ );
444
+
445
+ const currentShortAxisVector = vec2.create();
446
+
447
+ vec2.set(
448
+ currentShortAxisVector,
449
+ shortAxisPoint1[0] - shortAxisPoint0[0],
450
+ shortAxisPoint1[1] - shortAxisPoint0[0]
451
+ );
452
+
453
+ let shortAxis;
454
+
455
+ if (
456
+ vec2.dot(
457
+ currentShortAxisVector,
458
+ counterClockWisePerpendicularToLongAxis
459
+ ) > 0
460
+ ) {
461
+ shortAxis = [shortAxisPoint0, shortAxisPoint1];
462
+ } else {
463
+ shortAxis = [shortAxisPoint1, shortAxisPoint0];
464
+ }
465
+
466
+ data.handles.points = [
467
+ longAxis[0],
468
+ longAxis[1],
469
+ shortAxis[0],
470
+ shortAxis[1],
471
+ ];
472
+ }
473
+ }
474
+
475
+ if (
476
+ this.isHandleOutsideImage &&
477
+ this.configuration.preventHandleOutsideImage
478
+ ) {
479
+ removeAnnotation(annotation.annotationUID);
480
+ }
481
+
482
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
483
+
484
+ if (newAnnotation) {
485
+ const eventType = Events.ANNOTATION_COMPLETED;
486
+
487
+ const eventDetail: AnnotationCompletedEventDetail = {
488
+ annotation,
489
+ };
490
+
491
+ triggerEvent(eventTarget, eventType, eventDetail);
492
+ }
493
+
494
+ this.editData = null;
495
+ this.isDrawing = false;
496
+ };
497
+
498
+ /**
499
+ * @param evt - mouse move event type or mouse drag
500
+ */
501
+ _dragDrawCallback = (evt: EventTypes.InteractionEventType): void => {
502
+ this.isDrawing = true;
503
+
504
+ const eventDetail = evt.detail;
505
+ const { currentPoints, element } = eventDetail;
506
+ const enabledElement = getEnabledElement(element);
507
+ const { renderingEngine, viewport } = enabledElement;
508
+ const { worldToCanvas } = viewport;
509
+ const { annotation, viewportIdsToRender, handleIndex } = this.editData;
510
+ const { data } = annotation;
511
+
512
+ const worldPos = currentPoints.world;
513
+
514
+ // Update first move handle
515
+ data.handles.points[handleIndex] = [...worldPos];
516
+
517
+ const canvasCoordPoints = data.handles.points.map(worldToCanvas);
518
+
519
+ const canvasCoords = {
520
+ longLineSegment: {
521
+ start: {
522
+ x: canvasCoordPoints[0][0],
523
+ y: canvasCoordPoints[0][1],
524
+ },
525
+ end: {
526
+ x: canvasCoordPoints[1][0],
527
+ y: canvasCoordPoints[1][1],
528
+ },
529
+ },
530
+ shortLineSegment: {
531
+ start: {
532
+ x: canvasCoordPoints[2][0],
533
+ y: canvasCoordPoints[2][1],
534
+ },
535
+ end: {
536
+ x: canvasCoordPoints[3][0],
537
+ y: canvasCoordPoints[3][1],
538
+ },
539
+ },
540
+ };
541
+
542
+ // ~~ calculate worldPos of our short axis handles
543
+ // short axis is perpendicular to long axis, and we set its length to be 2/3 of long axis
544
+ // (meaning each)
545
+ const dist = vec2.distance(canvasCoordPoints[0], canvasCoordPoints[1]);
546
+
547
+ const shortAxisDistFromCenter = dist / 3;
548
+ // Calculate long line's incline
549
+ const dx =
550
+ canvasCoords.longLineSegment.start.x - canvasCoords.longLineSegment.end.x;
551
+ const dy =
552
+ canvasCoords.longLineSegment.start.y - canvasCoords.longLineSegment.end.y;
553
+ const length = Math.sqrt(dx * dx + dy * dy);
554
+ const vectorX = dx / length;
555
+ const vectorY = dy / length;
556
+ // middle point between long line segment's points
557
+ const xMid =
558
+ (canvasCoords.longLineSegment.start.x +
559
+ canvasCoords.longLineSegment.end.x) /
560
+ 2;
561
+ const yMid =
562
+ (canvasCoords.longLineSegment.start.y +
563
+ canvasCoords.longLineSegment.end.y) /
564
+ 2;
565
+ // short points 1/3 distance from center of long points
566
+ const startX = xMid + shortAxisDistFromCenter * vectorY;
567
+ const startY = yMid - shortAxisDistFromCenter * vectorX;
568
+ const endX = xMid - shortAxisDistFromCenter * vectorY;
569
+ const endY = yMid + shortAxisDistFromCenter * vectorX;
570
+
571
+ // Update perpendicular line segment's points
572
+ data.handles.points[2] = viewport.canvasToWorld([startX, startY]);
573
+ data.handles.points[3] = viewport.canvasToWorld([endX, endY]);
574
+
575
+ annotation.invalidated = true;
576
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
577
+
578
+ this.editData.hasMoved = true;
579
+ };
580
+
581
+ /**
582
+ * Mouse drag to edit annotation callback
583
+ * @param evt - mouse drag event
584
+ */
585
+ _dragModifyCallback = (evt: EventTypes.InteractionEventType): void => {
586
+ this.isDrawing = true;
587
+
588
+ const eventDetail = evt.detail;
589
+ const { element } = eventDetail;
590
+ const enabledElement = getEnabledElement(element);
591
+ const { renderingEngine } = enabledElement;
592
+ const { annotation, viewportIdsToRender, handleIndex, movingTextBox } =
593
+ this.editData;
594
+ const { data } = annotation;
595
+ if (movingTextBox) {
596
+ const { deltaPoints } = eventDetail;
597
+ const worldPosDelta = deltaPoints.world;
598
+
599
+ const { textBox } = data.handles;
600
+ const { worldPosition } = textBox;
601
+
602
+ worldPosition[0] += worldPosDelta[0];
603
+ worldPosition[1] += worldPosDelta[1];
604
+ worldPosition[2] += worldPosDelta[2];
605
+
606
+ textBox.hasMoved = true;
607
+ } else if (handleIndex === undefined) {
608
+ // Moving tool
609
+ const { deltaPoints } = eventDetail;
610
+ const worldPosDelta = deltaPoints.world;
611
+ const points = data.handles.points;
612
+
613
+ points.forEach((point) => {
614
+ point[0] += worldPosDelta[0];
615
+ point[1] += worldPosDelta[1];
616
+ point[2] += worldPosDelta[2];
617
+ });
618
+ annotation.invalidated = true;
619
+ } else {
620
+ this._dragModifyHandle(evt);
621
+ annotation.invalidated = true;
622
+ }
623
+
624
+ triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender);
625
+ };
626
+
627
+ /**
628
+ * Mouse dragging a handle callback
629
+ * @param evt - mouse drag event
630
+ */
631
+ _dragModifyHandle = (evt: EventTypes.InteractionEventType): void => {
632
+ const eventDetail = evt.detail;
633
+ const { currentPoints, element } = eventDetail;
634
+ const enabledElement = getEnabledElement(element);
635
+ const { viewport } = enabledElement;
636
+ const { annotation, handleIndex: movingHandleIndex } = this.editData;
637
+ const { data } = annotation;
638
+
639
+ // Moving handle
640
+ const worldPos = currentPoints.world;
641
+ const canvasCoordHandlesCurrent = [
642
+ viewport.worldToCanvas(data.handles.points[0]),
643
+ viewport.worldToCanvas(data.handles.points[1]),
644
+ viewport.worldToCanvas(data.handles.points[2]),
645
+ viewport.worldToCanvas(data.handles.points[3]),
646
+ ];
647
+
648
+ const firstLineSegment = {
649
+ start: {
650
+ x: canvasCoordHandlesCurrent[0][0],
651
+ y: canvasCoordHandlesCurrent[0][1],
652
+ },
653
+ end: {
654
+ x: canvasCoordHandlesCurrent[1][0],
655
+ y: canvasCoordHandlesCurrent[1][1],
656
+ },
657
+ };
658
+ const secondLineSegment = {
659
+ start: {
660
+ x: canvasCoordHandlesCurrent[2][0],
661
+ y: canvasCoordHandlesCurrent[2][1],
662
+ },
663
+ end: {
664
+ x: canvasCoordHandlesCurrent[3][0],
665
+ y: canvasCoordHandlesCurrent[3][1],
666
+ },
667
+ };
668
+
669
+ // Handle we've selected's proposed point
670
+ const proposedPoint = <Types.Point3>[...worldPos];
671
+ const proposedCanvasCoord = viewport.worldToCanvas(proposedPoint);
672
+
673
+ if (movingHandleIndex === 0 || movingHandleIndex === 1) {
674
+ const fixedHandleIndex = movingHandleIndex === 0 ? 1 : 0;
675
+
676
+ const fixedHandleCanvasCoord =
677
+ canvasCoordHandlesCurrent[fixedHandleIndex];
678
+
679
+ const fixedHandleToProposedCoordVec = vec2.set(
680
+ vec2.create(),
681
+ proposedCanvasCoord[0] - fixedHandleCanvasCoord[0],
682
+ proposedCanvasCoord[1] - fixedHandleCanvasCoord[1]
683
+ );
684
+
685
+ const fixedHandleToOldCoordVec = vec2.set(
686
+ vec2.create(),
687
+ canvasCoordHandlesCurrent[movingHandleIndex][0] -
688
+ fixedHandleCanvasCoord[0],
689
+ canvasCoordHandlesCurrent[movingHandleIndex][1] -
690
+ fixedHandleCanvasCoord[1]
691
+ );
692
+
693
+ // normalize vector
694
+ vec2.normalize(
695
+ fixedHandleToProposedCoordVec,
696
+ fixedHandleToProposedCoordVec
697
+ );
698
+ vec2.normalize(fixedHandleToOldCoordVec, fixedHandleToOldCoordVec);
699
+
700
+ // Check whether this
701
+ const proposedFirstLineSegment = {
702
+ start: {
703
+ x: fixedHandleCanvasCoord[0],
704
+ y: fixedHandleCanvasCoord[1],
705
+ },
706
+ end: {
707
+ x: proposedCanvasCoord[0],
708
+ y: proposedCanvasCoord[1],
709
+ },
710
+ };
711
+
712
+ // Note: this is the case when we are modifying the long axis line segment
713
+ // and we make it shorter and shorter until its second half size becomes zero
714
+ // which basically means that any more modification would make the long axis
715
+ // second half disappear. In this case, we just bail out and do not update
716
+ // since we don't want to disrupt the bidirectional shape.
717
+ if (
718
+ this._movingLongAxisWouldPutItThroughShortAxis(
719
+ proposedFirstLineSegment,
720
+ secondLineSegment
721
+ )
722
+ ) {
723
+ return;
724
+ }
725
+
726
+ const centerOfRotation = fixedHandleCanvasCoord;
727
+
728
+ const angle = this._getSignedAngle(
729
+ fixedHandleToOldCoordVec,
730
+ fixedHandleToProposedCoordVec
731
+ );
732
+
733
+ // rotate handles around the center of rotation, first translate to origin,
734
+ // then rotate, then translate back
735
+ let firstPointX = canvasCoordHandlesCurrent[2][0];
736
+ let firstPointY = canvasCoordHandlesCurrent[2][1];
737
+
738
+ let secondPointX = canvasCoordHandlesCurrent[3][0];
739
+ let secondPointY = canvasCoordHandlesCurrent[3][1];
740
+
741
+ // translate to origin
742
+ firstPointX -= centerOfRotation[0];
743
+ firstPointY -= centerOfRotation[1];
744
+
745
+ secondPointX -= centerOfRotation[0];
746
+ secondPointY -= centerOfRotation[1];
747
+
748
+ // rotate
749
+ const rotatedFirstPoint =
750
+ firstPointX * Math.cos(angle) - firstPointY * Math.sin(angle);
751
+ const rotatedFirstPointY =
752
+ firstPointX * Math.sin(angle) + firstPointY * Math.cos(angle);
753
+
754
+ const rotatedSecondPoint =
755
+ secondPointX * Math.cos(angle) - secondPointY * Math.sin(angle);
756
+ const rotatedSecondPointY =
757
+ secondPointX * Math.sin(angle) + secondPointY * Math.cos(angle);
758
+
759
+ // translate back
760
+ firstPointX = rotatedFirstPoint + centerOfRotation[0];
761
+ firstPointY = rotatedFirstPointY + centerOfRotation[1];
762
+
763
+ secondPointX = rotatedSecondPoint + centerOfRotation[0];
764
+ secondPointY = rotatedSecondPointY + centerOfRotation[1];
765
+
766
+ // update handles
767
+ const newFirstPoint = viewport.canvasToWorld([firstPointX, firstPointY]);
768
+ const newSecondPoint = viewport.canvasToWorld([
769
+ secondPointX,
770
+ secondPointY,
771
+ ]);
772
+
773
+ // the fixed handle is the one that is not being moved so we
774
+ // don't need to update it
775
+ data.handles.points[movingHandleIndex] = proposedPoint;
776
+ data.handles.points[2] = newFirstPoint;
777
+ data.handles.points[3] = newSecondPoint;
778
+ } else {
779
+ // Translation manipulator
780
+ const translateHandleIndex = movingHandleIndex === 2 ? 3 : 2;
781
+
782
+ const canvasCoordsCurrent = {
783
+ longLineSegment: {
784
+ start: firstLineSegment.start,
785
+ end: firstLineSegment.end,
786
+ },
787
+ shortLineSegment: {
788
+ start: secondLineSegment.start,
789
+ end: secondLineSegment.end,
790
+ },
791
+ };
792
+
793
+ const longLineSegmentVec = vec2.subtract(
794
+ vec2.create(),
795
+ [
796
+ canvasCoordsCurrent.longLineSegment.end.x,
797
+ canvasCoordsCurrent.longLineSegment.end.y,
798
+ ],
799
+ [
800
+ canvasCoordsCurrent.longLineSegment.start.x,
801
+ canvasCoordsCurrent.longLineSegment.start.y,
802
+ ]
803
+ );
804
+
805
+ const longLineSegmentVecNormalized = vec2.normalize(
806
+ vec2.create(),
807
+ longLineSegmentVec
808
+ );
809
+
810
+ const proposedToCurrentVec = vec2.subtract(
811
+ vec2.create(),
812
+ [proposedCanvasCoord[0], proposedCanvasCoord[1]],
813
+ [
814
+ canvasCoordHandlesCurrent[movingHandleIndex][0],
815
+ canvasCoordHandlesCurrent[movingHandleIndex][1],
816
+ ]
817
+ );
818
+
819
+ const movementLength = vec2.length(proposedToCurrentVec);
820
+
821
+ const angle = this._getSignedAngle(
822
+ longLineSegmentVecNormalized,
823
+ proposedToCurrentVec
824
+ );
825
+
826
+ const movementAlongLineSegmentLength = Math.cos(angle) * movementLength;
827
+
828
+ const newTranslatedPoint = vec2.scaleAndAdd(
829
+ vec2.create(),
830
+ [
831
+ canvasCoordHandlesCurrent[translateHandleIndex][0],
832
+ canvasCoordHandlesCurrent[translateHandleIndex][1],
833
+ ],
834
+ longLineSegmentVecNormalized,
835
+ movementAlongLineSegmentLength
836
+ );
837
+
838
+ // don't update if it passes through the other line segment
839
+ if (
840
+ this._movingLongAxisWouldPutItThroughShortAxis(
841
+ {
842
+ start: {
843
+ x: proposedCanvasCoord[0],
844
+ y: proposedCanvasCoord[1],
845
+ },
846
+ end: {
847
+ x: newTranslatedPoint[0],
848
+ y: newTranslatedPoint[1],
849
+ },
850
+ },
851
+ {
852
+ start: {
853
+ x: canvasCoordsCurrent.longLineSegment.start.x,
854
+ y: canvasCoordsCurrent.longLineSegment.start.y,
855
+ },
856
+ end: {
857
+ x: canvasCoordsCurrent.longLineSegment.end.x,
858
+ y: canvasCoordsCurrent.longLineSegment.end.y,
859
+ },
860
+ }
861
+ )
862
+ ) {
863
+ return;
864
+ }
865
+
866
+ const intersectionPoint = lineSegment.intersectLine(
867
+ [proposedCanvasCoord[0], proposedCanvasCoord[1]],
868
+ [newTranslatedPoint[0], newTranslatedPoint[1]],
869
+ [firstLineSegment.start.x, firstLineSegment.start.y],
870
+ [firstLineSegment.end.x, firstLineSegment.end.y]
871
+ );
872
+
873
+ // don't update if it doesn't intersect
874
+ if (!intersectionPoint) {
875
+ return;
876
+ }
877
+
878
+ data.handles.points[translateHandleIndex] = viewport.canvasToWorld(
879
+ newTranslatedPoint as Types.Point2
880
+ );
881
+ data.handles.points[movingHandleIndex] = proposedPoint;
882
+ }
883
+ };
884
+
885
+ /**
886
+ * Cancels an ongoing drawing of a bidirectional annotation
887
+ * @param element - HTML Element
888
+ */
889
+ cancel = (element: HTMLDivElement) => {
890
+ // If it is mid-draw or mid-modify
891
+ if (this.isDrawing) {
892
+ this.isDrawing = false;
893
+ this._deactivateDraw(element);
894
+ this._deactivateModify(element);
895
+ resetElementCursor(element);
896
+
897
+ const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
898
+ const { data } = annotation;
899
+
900
+ annotation.highlighted = false;
901
+ data.handles.activeHandleIndex = null;
902
+
903
+ const enabledElement = getEnabledElement(element);
904
+ const { renderingEngine } = enabledElement;
905
+
906
+ triggerAnnotationRenderForViewportIds(
907
+ renderingEngine,
908
+ viewportIdsToRender
909
+ );
910
+
911
+ if (newAnnotation) {
912
+ const eventType = Events.ANNOTATION_COMPLETED;
913
+
914
+ const eventDetail: AnnotationCompletedEventDetail = {
915
+ annotation,
916
+ };
917
+
918
+ triggerEvent(eventTarget, eventType, eventDetail);
919
+ }
920
+
921
+ this.editData = null;
922
+ return annotation.annotationUID;
923
+ }
924
+ };
925
+
926
+ _activateDraw = (element) => {
927
+ state.isInteractingWithTool = true;
928
+
929
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
930
+ element.addEventListener(Events.MOUSE_DRAG, this._dragDrawCallback);
931
+ element.addEventListener(Events.MOUSE_MOVE, this._dragDrawCallback);
932
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
933
+
934
+ element.addEventListener(
935
+ Events.TOUCH_TAP,
936
+ this._endCallback as EventListener
937
+ );
938
+ element.addEventListener(
939
+ Events.TOUCH_END,
940
+ this._endCallback as EventListener
941
+ );
942
+ element.addEventListener(
943
+ Events.TOUCH_DRAG,
944
+ this._dragDrawCallback as EventListener
945
+ );
946
+ };
947
+
948
+ _deactivateDraw = (element) => {
949
+ state.isInteractingWithTool = false;
950
+
951
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
952
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragDrawCallback);
953
+ element.removeEventListener(Events.MOUSE_MOVE, this._dragDrawCallback);
954
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
955
+
956
+ element.removeEventListener(
957
+ Events.TOUCH_TAP,
958
+ this._endCallback as EventListener
959
+ );
960
+ element.removeEventListener(
961
+ Events.TOUCH_END,
962
+ this._endCallback as EventListener
963
+ );
964
+ element.removeEventListener(
965
+ Events.TOUCH_DRAG,
966
+ this._dragDrawCallback as EventListener
967
+ );
968
+ };
969
+
970
+ _activateModify = (element) => {
971
+ state.isInteractingWithTool = true;
972
+
973
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
974
+ element.addEventListener(Events.MOUSE_DRAG, this._dragModifyCallback);
975
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
976
+
977
+ element.addEventListener(
978
+ Events.TOUCH_END,
979
+ this._endCallback as EventListener
980
+ );
981
+ element.addEventListener(
982
+ Events.TOUCH_DRAG,
983
+ this._dragModifyCallback as EventListener
984
+ );
985
+ element.addEventListener(
986
+ Events.TOUCH_TAP,
987
+ this._endCallback as EventListener
988
+ );
989
+ };
990
+
991
+ _deactivateModify = (element) => {
992
+ state.isInteractingWithTool = false;
993
+
994
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
995
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragModifyCallback);
996
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
997
+
998
+ element.removeEventListener(
999
+ Events.TOUCH_END,
1000
+ this._endCallback as EventListener
1001
+ );
1002
+ element.removeEventListener(
1003
+ Events.TOUCH_DRAG,
1004
+ this._dragModifyCallback as EventListener
1005
+ );
1006
+ element.removeEventListener(
1007
+ Events.TOUCH_TAP,
1008
+ this._endCallback as EventListener
1009
+ );
1010
+ };
1011
+
1012
+ /**
1013
+ * it is used to draw the bidirectional annotation in each
1014
+ * request animation frame. It calculates the updated cached statistics if
1015
+ * data is invalidated and cache it.
1016
+ *
1017
+ * @param enabledElement - The Cornerstone's enabledElement.
1018
+ * @param svgDrawingHelper - The svgDrawingHelper providing the context for drawing.
1019
+ */
1020
+ renderAnnotation = (
1021
+ enabledElement: Types.IEnabledElement,
1022
+ svgDrawingHelper: SVGDrawingHelper
1023
+ ): boolean => {
1024
+ let renderStatus = true;
1025
+ const { viewport } = enabledElement;
1026
+ const { element } = viewport;
1027
+ let annotations = getAnnotations(this.getToolName(), element);
1028
+
1029
+ if (!annotations?.length) {
1030
+ return renderStatus;
1031
+ }
1032
+
1033
+ annotations = this.filterInteractableAnnotationsForElement(
1034
+ element,
1035
+ annotations
1036
+ );
1037
+
1038
+ if (!annotations?.length) {
1039
+ return renderStatus;
1040
+ }
1041
+
1042
+ const targetId = this.getTargetId(viewport);
1043
+
1044
+ const renderingEngine = viewport.getRenderingEngine();
1045
+
1046
+ const styleSpecifier: StyleSpecifier = {
1047
+ toolGroupId: this.toolGroupId,
1048
+ toolName: this.getToolName(),
1049
+ viewportId: enabledElement.viewport.id,
1050
+ };
1051
+
1052
+ for (let i = 0; i < annotations.length; i++) {
1053
+ const annotation = annotations[i] as BidirectionalAnnotation;
1054
+ const { annotationUID, data } = annotation;
1055
+ const { points, activeHandleIndex } = data.handles;
1056
+ const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
1057
+
1058
+ styleSpecifier.annotationUID = annotationUID;
1059
+
1060
+ const lineWidth = this.getStyle('lineWidth', styleSpecifier, annotation);
1061
+ const lineDash = this.getStyle('lineDash', styleSpecifier, annotation);
1062
+ const color = this.getStyle('color', styleSpecifier, annotation);
1063
+ const shadow = this.getStyle('shadow', styleSpecifier, annotation);
1064
+
1065
+ // If cachedStats does not exist, or the unit is missing (as part of import/hydration etc.),
1066
+ // force to recalculate the stats from the points
1067
+ if (
1068
+ !data.cachedStats[targetId] ||
1069
+ data.cachedStats[targetId].unit === undefined
1070
+ ) {
1071
+ data.cachedStats[targetId] = {
1072
+ length: null,
1073
+ width: null,
1074
+ unit: null,
1075
+ };
1076
+
1077
+ this._calculateCachedStats(annotation, renderingEngine, enabledElement);
1078
+ } else if (annotation.invalidated) {
1079
+ this._throttledCalculateCachedStats(
1080
+ annotation,
1081
+ renderingEngine,
1082
+ enabledElement
1083
+ );
1084
+ }
1085
+
1086
+ // If rendering engine has been destroyed while rendering
1087
+ if (!viewport.getRenderingEngine()) {
1088
+ console.warn('Rendering Engine has been destroyed');
1089
+ return renderStatus;
1090
+ }
1091
+
1092
+ let activeHandleCanvasCoords;
1093
+
1094
+ if (!isAnnotationVisible(annotationUID)) {
1095
+ continue;
1096
+ }
1097
+
1098
+ if (
1099
+ !isAnnotationLocked(annotation) &&
1100
+ !this.editData &&
1101
+ activeHandleIndex !== null
1102
+ ) {
1103
+ // Not locked or creating and hovering over handle, so render handle.
1104
+ activeHandleCanvasCoords = [canvasCoordinates[activeHandleIndex]];
1105
+ }
1106
+
1107
+ if (activeHandleCanvasCoords) {
1108
+ const handleGroupUID = '0';
1109
+
1110
+ drawHandlesSvg(
1111
+ svgDrawingHelper,
1112
+ annotationUID,
1113
+ handleGroupUID,
1114
+ activeHandleCanvasCoords,
1115
+ {
1116
+ color,
1117
+ }
1118
+ );
1119
+ }
1120
+
1121
+ const dataId1 = `${annotationUID}-line-1`;
1122
+ const dataId2 = `${annotationUID}-line-2`;
1123
+
1124
+ const lineUID = '0';
1125
+ drawLineSvg(
1126
+ svgDrawingHelper,
1127
+ annotationUID,
1128
+ lineUID,
1129
+ canvasCoordinates[0],
1130
+ canvasCoordinates[1],
1131
+ {
1132
+ color,
1133
+ lineDash,
1134
+ lineWidth,
1135
+ shadow,
1136
+ },
1137
+ dataId1
1138
+ );
1139
+
1140
+ const secondLineUID = '1';
1141
+ drawLineSvg(
1142
+ svgDrawingHelper,
1143
+ annotationUID,
1144
+ secondLineUID,
1145
+ canvasCoordinates[2],
1146
+ canvasCoordinates[3],
1147
+ {
1148
+ color,
1149
+ lineDash,
1150
+ lineWidth,
1151
+ shadow,
1152
+ },
1153
+ dataId2
1154
+ );
1155
+
1156
+ renderStatus = true;
1157
+
1158
+ const textLines = this._getTextLines(data, targetId);
1159
+
1160
+ if (!textLines || textLines.length === 0) {
1161
+ continue;
1162
+ }
1163
+ let canvasTextBoxCoords;
1164
+
1165
+ if (!data.handles.textBox.hasMoved) {
1166
+ canvasTextBoxCoords = getTextBoxCoordsCanvas(canvasCoordinates);
1167
+
1168
+ data.handles.textBox.worldPosition =
1169
+ viewport.canvasToWorld(canvasTextBoxCoords);
1170
+ }
1171
+
1172
+ const textBoxPosition = viewport.worldToCanvas(
1173
+ data.handles.textBox.worldPosition
1174
+ );
1175
+
1176
+ const textBoxUID = '1';
1177
+ const boundingBox = drawLinkedTextBoxSvg(
1178
+ svgDrawingHelper,
1179
+ annotationUID,
1180
+ textBoxUID,
1181
+ textLines,
1182
+ textBoxPosition,
1183
+ canvasCoordinates,
1184
+ {},
1185
+ this.getLinkedTextBoxStyle(styleSpecifier, annotation)
1186
+ );
1187
+
1188
+ const { x: left, y: top, width, height } = boundingBox;
1189
+
1190
+ data.handles.textBox.worldBoundingBox = {
1191
+ topLeft: viewport.canvasToWorld([left, top]),
1192
+ topRight: viewport.canvasToWorld([left + width, top]),
1193
+ bottomLeft: viewport.canvasToWorld([left, top + height]),
1194
+ bottomRight: viewport.canvasToWorld([left + width, top + height]),
1195
+ };
1196
+ }
1197
+
1198
+ return renderStatus;
1199
+ };
1200
+
1201
+ _movingLongAxisWouldPutItThroughShortAxis = (
1202
+ firstLineSegment,
1203
+ secondLineSegment
1204
+ ) => {
1205
+ const vectorInSecondLineDirection = vec2.create();
1206
+
1207
+ vec2.set(
1208
+ vectorInSecondLineDirection,
1209
+ secondLineSegment.end.x - secondLineSegment.start.x,
1210
+ secondLineSegment.end.y - secondLineSegment.start.y
1211
+ );
1212
+
1213
+ vec2.normalize(vectorInSecondLineDirection, vectorInSecondLineDirection);
1214
+
1215
+ const extendedSecondLineSegment = {
1216
+ start: {
1217
+ x: secondLineSegment.start.x - vectorInSecondLineDirection[0] * 10,
1218
+ y: secondLineSegment.start.y - vectorInSecondLineDirection[1] * 10,
1219
+ },
1220
+ end: {
1221
+ x: secondLineSegment.end.x + vectorInSecondLineDirection[0] * 10,
1222
+ y: secondLineSegment.end.y + vectorInSecondLineDirection[1] * 10,
1223
+ },
1224
+ };
1225
+
1226
+ // Add some buffer in the secondLineSegment when finding the proposedIntersectionPoint
1227
+ // Of points to stop us getting stack when rotating quickly.
1228
+
1229
+ const proposedIntersectionPoint = lineSegment.intersectLine(
1230
+ [extendedSecondLineSegment.start.x, extendedSecondLineSegment.start.y],
1231
+ [extendedSecondLineSegment.end.x, extendedSecondLineSegment.end.y],
1232
+ [firstLineSegment.start.x, firstLineSegment.start.y],
1233
+ [firstLineSegment.end.x, firstLineSegment.end.y]
1234
+ );
1235
+
1236
+ const wouldPutThroughShortAxis = !proposedIntersectionPoint;
1237
+
1238
+ return wouldPutThroughShortAxis;
1239
+ };
1240
+
1241
+ /**
1242
+ * get text box content
1243
+ */
1244
+ _getTextLines = (data, targetId) => {
1245
+ const { cachedStats } = data;
1246
+ const { length, width, unit } = cachedStats[targetId];
1247
+
1248
+ if (length === undefined) {
1249
+ return;
1250
+ }
1251
+
1252
+ // spaceBetweenSlices & pixelSpacing &
1253
+ // magnitude in each direction? Otherwise, this is "px"?
1254
+ const textLines = [
1255
+ `L: ${length.toFixed(2)} ${unit}`,
1256
+ `W: ${width.toFixed(2)} ${unit}`,
1257
+ ];
1258
+
1259
+ return textLines;
1260
+ };
1261
+
1262
+ _calculateLength(pos1, pos2) {
1263
+ const dx = pos1[0] - pos2[0];
1264
+ const dy = pos1[1] - pos2[1];
1265
+ const dz = pos1[2] - pos2[2];
1266
+
1267
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
1268
+ }
1269
+
1270
+ _calculateCachedStats = (annotation, renderingEngine, enabledElement) => {
1271
+ const { data } = annotation;
1272
+ const { viewportId, renderingEngineId } = enabledElement;
1273
+
1274
+ const worldPos1 = data.handles.points[0];
1275
+ const worldPos2 = data.handles.points[1];
1276
+ const worldPos3 = data.handles.points[2];
1277
+ const worldPos4 = data.handles.points[3];
1278
+
1279
+ const { cachedStats } = data;
1280
+ const targetIds = Object.keys(cachedStats);
1281
+
1282
+ for (let i = 0; i < targetIds.length; i++) {
1283
+ const targetId = targetIds[i];
1284
+
1285
+ const image = this.getTargetIdImage(targetId, renderingEngine);
1286
+
1287
+ // If image does not exists for the targetId, skip. This can be due
1288
+ // to various reasons such as if the target was a volumeViewport, and
1289
+ // the volumeViewport has been decached in the meantime.
1290
+ if (!image) {
1291
+ continue;
1292
+ }
1293
+
1294
+ const { imageData, dimensions, hasPixelSpacing } = image;
1295
+
1296
+ const dist1 = this._calculateLength(worldPos1, worldPos2);
1297
+ const dist2 = this._calculateLength(worldPos3, worldPos4);
1298
+ const length = dist1 > dist2 ? dist1 : dist2;
1299
+ const width = dist1 > dist2 ? dist2 : dist1;
1300
+
1301
+ const index1 = transformWorldToIndex(imageData, worldPos1);
1302
+ const index2 = transformWorldToIndex(imageData, worldPos2);
1303
+ const index3 = transformWorldToIndex(imageData, worldPos3);
1304
+ const index4 = transformWorldToIndex(imageData, worldPos4);
1305
+
1306
+ this._isInsideVolume(index1, index2, index3, index4, dimensions)
1307
+ ? (this.isHandleOutsideImage = false)
1308
+ : (this.isHandleOutsideImage = true);
1309
+
1310
+ cachedStats[targetId] = {
1311
+ length,
1312
+ width,
1313
+ unit: hasPixelSpacing ? 'mm' : 'px',
1314
+ };
1315
+ }
1316
+
1317
+ annotation.invalidated = false;
1318
+
1319
+ // Dispatching annotation modified
1320
+ const eventType = Events.ANNOTATION_MODIFIED;
1321
+
1322
+ const eventDetail: AnnotationModifiedEventDetail = {
1323
+ annotation,
1324
+ viewportId,
1325
+ renderingEngineId,
1326
+ };
1327
+ triggerEvent(eventTarget, eventType, eventDetail);
1328
+
1329
+ return cachedStats;
1330
+ };
1331
+
1332
+ _isInsideVolume = (index1, index2, index3, index4, dimensions): boolean => {
1333
+ return (
1334
+ csUtils.indexWithinDimensions(index1, dimensions) &&
1335
+ csUtils.indexWithinDimensions(index2, dimensions) &&
1336
+ csUtils.indexWithinDimensions(index3, dimensions) &&
1337
+ csUtils.indexWithinDimensions(index4, dimensions)
1338
+ );
1339
+ };
1340
+
1341
+ _getSignedAngle = (vector1, vector2) => {
1342
+ return Math.atan2(
1343
+ vector1[0] * vector2[1] - vector1[1] * vector2[0],
1344
+ vector1[0] * vector2[0] + vector1[1] * vector2[1]
1345
+ );
1346
+ };
1347
+ }
1348
+
1349
+ BidirectionalTool.toolName = 'Bidirectional';
1350
+ export default BidirectionalTool;