@cornerstonejs/tools 1.32.3 → 1.33.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 (206) hide show
  1. package/dist/cjs/eventListeners/index.d.ts +2 -2
  2. package/dist/cjs/eventListeners/index.js +2 -1
  3. package/dist/cjs/eventListeners/index.js.map +1 -1
  4. package/dist/cjs/eventListeners/segmentation/imageChangeEventListener.d.ts +5 -0
  5. package/dist/cjs/eventListeners/segmentation/imageChangeEventListener.js +143 -0
  6. package/dist/cjs/eventListeners/segmentation/imageChangeEventListener.js.map +1 -0
  7. package/dist/cjs/eventListeners/segmentation/index.d.ts +2 -1
  8. package/dist/cjs/eventListeners/segmentation/index.js +3 -1
  9. package/dist/cjs/eventListeners/segmentation/index.js.map +1 -1
  10. package/dist/cjs/eventListeners/segmentation/segmentationDataModifiedEventListener.js +31 -5
  11. package/dist/cjs/eventListeners/segmentation/segmentationDataModifiedEventListener.js.map +1 -1
  12. package/dist/cjs/store/addEnabledElement.js +1 -0
  13. package/dist/cjs/store/addEnabledElement.js.map +1 -1
  14. package/dist/cjs/store/removeEnabledElement.js +2 -0
  15. package/dist/cjs/store/removeEnabledElement.js.map +1 -1
  16. package/dist/cjs/tools/annotation/CircleROITool.js +3 -1
  17. package/dist/cjs/tools/annotation/CircleROITool.js.map +1 -1
  18. package/dist/cjs/tools/annotation/EllipticalROITool.js +1 -1
  19. package/dist/cjs/tools/annotation/EllipticalROITool.js.map +1 -1
  20. package/dist/cjs/tools/displayTools/Labelmap/addLabelmapToElement.d.ts +2 -1
  21. package/dist/cjs/tools/displayTools/Labelmap/addLabelmapToElement.js +23 -10
  22. package/dist/cjs/tools/displayTools/Labelmap/addLabelmapToElement.js.map +1 -1
  23. package/dist/cjs/tools/displayTools/Labelmap/labelmapDisplay.d.ts +1 -1
  24. package/dist/cjs/tools/displayTools/Labelmap/labelmapDisplay.js +36 -22
  25. package/dist/cjs/tools/displayTools/Labelmap/labelmapDisplay.js.map +1 -1
  26. package/dist/cjs/tools/displayTools/Labelmap/validateRepresentationData.js +6 -5
  27. package/dist/cjs/tools/displayTools/Labelmap/validateRepresentationData.js.map +1 -1
  28. package/dist/cjs/tools/segmentation/BrushTool.js +40 -45
  29. package/dist/cjs/tools/segmentation/BrushTool.js.map +1 -1
  30. package/dist/cjs/tools/segmentation/CircleScissorsTool.d.ts +4 -2
  31. package/dist/cjs/tools/segmentation/CircleScissorsTool.js +18 -17
  32. package/dist/cjs/tools/segmentation/CircleScissorsTool.js.map +1 -1
  33. package/dist/cjs/tools/segmentation/PaintFillTool.js +28 -5
  34. package/dist/cjs/tools/segmentation/PaintFillTool.js.map +1 -1
  35. package/dist/cjs/tools/segmentation/RectangleScissorsTool.d.ts +3 -1
  36. package/dist/cjs/tools/segmentation/RectangleScissorsTool.js +15 -16
  37. package/dist/cjs/tools/segmentation/RectangleScissorsTool.js.map +1 -1
  38. package/dist/cjs/tools/segmentation/SphereScissorsTool.d.ts +4 -2
  39. package/dist/cjs/tools/segmentation/SphereScissorsTool.js +20 -20
  40. package/dist/cjs/tools/segmentation/SphereScissorsTool.js.map +1 -1
  41. package/dist/cjs/tools/segmentation/strategies/eraseCircle.d.ts +2 -10
  42. package/dist/cjs/tools/segmentation/strategies/eraseCircle.js.map +1 -1
  43. package/dist/cjs/tools/segmentation/strategies/eraseRectangle.d.ts +4 -8
  44. package/dist/cjs/tools/segmentation/strategies/eraseRectangle.js +4 -20
  45. package/dist/cjs/tools/segmentation/strategies/eraseRectangle.js.map +1 -1
  46. package/dist/cjs/tools/segmentation/strategies/eraseSphere.d.ts +2 -10
  47. package/dist/cjs/tools/segmentation/strategies/eraseSphere.js.map +1 -1
  48. package/dist/cjs/tools/segmentation/strategies/fillCircle.d.ts +3 -11
  49. package/dist/cjs/tools/segmentation/strategies/fillCircle.js +57 -32
  50. package/dist/cjs/tools/segmentation/strategies/fillCircle.js.map +1 -1
  51. package/dist/cjs/tools/segmentation/strategies/fillRectangle.d.ts +2 -7
  52. package/dist/cjs/tools/segmentation/strategies/fillRectangle.js +16 -8
  53. package/dist/cjs/tools/segmentation/strategies/fillRectangle.js.map +1 -1
  54. package/dist/cjs/tools/segmentation/strategies/fillSphere.d.ts +2 -10
  55. package/dist/cjs/tools/segmentation/strategies/fillSphere.js +31 -17
  56. package/dist/cjs/tools/segmentation/strategies/fillSphere.js.map +1 -1
  57. package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.d.ts +9 -0
  58. package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.js +43 -0
  59. package/dist/cjs/tools/segmentation/strategies/utils/getStrategyData.js.map +1 -0
  60. package/dist/cjs/tools/segmentation/strategies/utils/isWithinThreshold.d.ts +2 -2
  61. package/dist/cjs/tools/segmentation/strategies/utils/isWithinThreshold.js +2 -2
  62. package/dist/cjs/tools/segmentation/strategies/utils/isWithinThreshold.js.map +1 -1
  63. package/dist/cjs/tools/segmentation/strategies/utils/stackVolumeCheck.d.ts +5 -0
  64. package/dist/cjs/tools/segmentation/strategies/utils/stackVolumeCheck.js +13 -0
  65. package/dist/cjs/tools/segmentation/strategies/utils/stackVolumeCheck.js.map +1 -0
  66. package/dist/cjs/types/LabelmapToolOperationData.d.ts +14 -0
  67. package/dist/cjs/types/LabelmapToolOperationData.js +3 -0
  68. package/dist/cjs/types/LabelmapToolOperationData.js.map +1 -0
  69. package/dist/cjs/types/LabelmapTypes.d.ts +5 -1
  70. package/dist/cjs/types/index.d.ts +2 -1
  71. package/dist/cjs/utilities/math/ellipse/pointInEllipse.d.ts +7 -9
  72. package/dist/cjs/utilities/math/ellipse/pointInEllipse.js +19 -11
  73. package/dist/cjs/utilities/math/ellipse/pointInEllipse.js.map +1 -1
  74. package/dist/esm/eventListeners/index.js +2 -2
  75. package/dist/esm/eventListeners/index.js.map +1 -1
  76. package/dist/esm/eventListeners/segmentation/imageChangeEventListener.js +115 -0
  77. package/dist/esm/eventListeners/segmentation/imageChangeEventListener.js.map +1 -0
  78. package/dist/esm/eventListeners/segmentation/index.js +2 -1
  79. package/dist/esm/eventListeners/segmentation/index.js.map +1 -1
  80. package/dist/esm/eventListeners/segmentation/segmentationDataModifiedEventListener.js +32 -6
  81. package/dist/esm/eventListeners/segmentation/segmentationDataModifiedEventListener.js.map +1 -1
  82. package/dist/esm/store/addEnabledElement.js +2 -1
  83. package/dist/esm/store/addEnabledElement.js.map +1 -1
  84. package/dist/esm/store/removeEnabledElement.js +2 -0
  85. package/dist/esm/store/removeEnabledElement.js.map +1 -1
  86. package/dist/esm/tools/annotation/CircleROITool.js +4 -2
  87. package/dist/esm/tools/annotation/CircleROITool.js.map +1 -1
  88. package/dist/esm/tools/annotation/EllipticalROITool.js +1 -1
  89. package/dist/esm/tools/annotation/EllipticalROITool.js.map +1 -1
  90. package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js +24 -11
  91. package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js.map +1 -1
  92. package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js +36 -22
  93. package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js.map +1 -1
  94. package/dist/esm/tools/displayTools/Labelmap/validateRepresentationData.js +6 -5
  95. package/dist/esm/tools/displayTools/Labelmap/validateRepresentationData.js.map +1 -1
  96. package/dist/esm/tools/segmentation/BrushTool.js +38 -29
  97. package/dist/esm/tools/segmentation/BrushTool.js.map +1 -1
  98. package/dist/esm/tools/segmentation/CircleScissorsTool.js +27 -15
  99. package/dist/esm/tools/segmentation/CircleScissorsTool.js.map +1 -1
  100. package/dist/esm/tools/segmentation/PaintFillTool.js +28 -5
  101. package/dist/esm/tools/segmentation/PaintFillTool.js.map +1 -1
  102. package/dist/esm/tools/segmentation/RectangleScissorsTool.js +26 -17
  103. package/dist/esm/tools/segmentation/RectangleScissorsTool.js.map +1 -1
  104. package/dist/esm/tools/segmentation/SphereScissorsTool.js +28 -17
  105. package/dist/esm/tools/segmentation/SphereScissorsTool.js.map +1 -1
  106. package/dist/esm/tools/segmentation/strategies/eraseCircle.js.map +1 -1
  107. package/dist/esm/tools/segmentation/strategies/eraseRectangle.js +4 -20
  108. package/dist/esm/tools/segmentation/strategies/eraseRectangle.js.map +1 -1
  109. package/dist/esm/tools/segmentation/strategies/eraseSphere.js.map +1 -1
  110. package/dist/esm/tools/segmentation/strategies/fillCircle.js +56 -31
  111. package/dist/esm/tools/segmentation/strategies/fillCircle.js.map +1 -1
  112. package/dist/esm/tools/segmentation/strategies/fillRectangle.js +16 -8
  113. package/dist/esm/tools/segmentation/strategies/fillRectangle.js.map +1 -1
  114. package/dist/esm/tools/segmentation/strategies/fillSphere.js +32 -18
  115. package/dist/esm/tools/segmentation/strategies/fillSphere.js.map +1 -1
  116. package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js +40 -0
  117. package/dist/esm/tools/segmentation/strategies/utils/getStrategyData.js.map +1 -0
  118. package/dist/esm/tools/segmentation/strategies/utils/isWithinThreshold.js +2 -2
  119. package/dist/esm/tools/segmentation/strategies/utils/isWithinThreshold.js.map +1 -1
  120. package/dist/esm/tools/segmentation/strategies/utils/stackVolumeCheck.js +9 -0
  121. package/dist/esm/tools/segmentation/strategies/utils/stackVolumeCheck.js.map +1 -0
  122. package/dist/esm/types/LabelmapToolOperationData.js +2 -0
  123. package/dist/esm/types/LabelmapToolOperationData.js.map +1 -0
  124. package/dist/esm/utilities/math/ellipse/pointInEllipse.js +19 -11
  125. package/dist/esm/utilities/math/ellipse/pointInEllipse.js.map +1 -1
  126. package/dist/types/eventListeners/index.d.ts +2 -2
  127. package/dist/types/eventListeners/index.d.ts.map +1 -1
  128. package/dist/types/eventListeners/segmentation/imageChangeEventListener.d.ts +6 -0
  129. package/dist/types/eventListeners/segmentation/imageChangeEventListener.d.ts.map +1 -0
  130. package/dist/types/eventListeners/segmentation/index.d.ts +2 -1
  131. package/dist/types/eventListeners/segmentation/index.d.ts.map +1 -1
  132. package/dist/types/eventListeners/segmentation/segmentationDataModifiedEventListener.d.ts.map +1 -1
  133. package/dist/types/store/addEnabledElement.d.ts.map +1 -1
  134. package/dist/types/store/removeEnabledElement.d.ts.map +1 -1
  135. package/dist/types/tools/annotation/CircleROITool.d.ts.map +1 -1
  136. package/dist/types/tools/displayTools/Labelmap/addLabelmapToElement.d.ts +2 -1
  137. package/dist/types/tools/displayTools/Labelmap/addLabelmapToElement.d.ts.map +1 -1
  138. package/dist/types/tools/displayTools/Labelmap/labelmapDisplay.d.ts +1 -1
  139. package/dist/types/tools/displayTools/Labelmap/labelmapDisplay.d.ts.map +1 -1
  140. package/dist/types/tools/displayTools/Labelmap/validateRepresentationData.d.ts.map +1 -1
  141. package/dist/types/tools/segmentation/BrushTool.d.ts.map +1 -1
  142. package/dist/types/tools/segmentation/CircleScissorsTool.d.ts +4 -2
  143. package/dist/types/tools/segmentation/CircleScissorsTool.d.ts.map +1 -1
  144. package/dist/types/tools/segmentation/PaintFillTool.d.ts.map +1 -1
  145. package/dist/types/tools/segmentation/RectangleScissorsTool.d.ts +3 -1
  146. package/dist/types/tools/segmentation/RectangleScissorsTool.d.ts.map +1 -1
  147. package/dist/types/tools/segmentation/SphereScissorsTool.d.ts +4 -2
  148. package/dist/types/tools/segmentation/SphereScissorsTool.d.ts.map +1 -1
  149. package/dist/types/tools/segmentation/strategies/eraseCircle.d.ts +2 -10
  150. package/dist/types/tools/segmentation/strategies/eraseCircle.d.ts.map +1 -1
  151. package/dist/types/tools/segmentation/strategies/eraseRectangle.d.ts +4 -8
  152. package/dist/types/tools/segmentation/strategies/eraseRectangle.d.ts.map +1 -1
  153. package/dist/types/tools/segmentation/strategies/eraseSphere.d.ts +2 -10
  154. package/dist/types/tools/segmentation/strategies/eraseSphere.d.ts.map +1 -1
  155. package/dist/types/tools/segmentation/strategies/fillCircle.d.ts +3 -11
  156. package/dist/types/tools/segmentation/strategies/fillCircle.d.ts.map +1 -1
  157. package/dist/types/tools/segmentation/strategies/fillRectangle.d.ts +2 -7
  158. package/dist/types/tools/segmentation/strategies/fillRectangle.d.ts.map +1 -1
  159. package/dist/types/tools/segmentation/strategies/fillSphere.d.ts +2 -10
  160. package/dist/types/tools/segmentation/strategies/fillSphere.d.ts.map +1 -1
  161. package/dist/types/tools/segmentation/strategies/utils/getStrategyData.d.ts +10 -0
  162. package/dist/types/tools/segmentation/strategies/utils/getStrategyData.d.ts.map +1 -0
  163. package/dist/types/tools/segmentation/strategies/utils/isWithinThreshold.d.ts +2 -2
  164. package/dist/types/tools/segmentation/strategies/utils/isWithinThreshold.d.ts.map +1 -1
  165. package/dist/types/tools/segmentation/strategies/utils/stackVolumeCheck.d.ts +6 -0
  166. package/dist/types/tools/segmentation/strategies/utils/stackVolumeCheck.d.ts.map +1 -0
  167. package/dist/types/types/LabelmapToolOperationData.d.ts +15 -0
  168. package/dist/types/types/LabelmapToolOperationData.d.ts.map +1 -0
  169. package/dist/types/types/LabelmapTypes.d.ts +5 -1
  170. package/dist/types/types/LabelmapTypes.d.ts.map +1 -1
  171. package/dist/types/types/index.d.ts +2 -1
  172. package/dist/types/types/index.d.ts.map +1 -1
  173. package/dist/types/utilities/math/ellipse/pointInEllipse.d.ts +7 -9
  174. package/dist/types/utilities/math/ellipse/pointInEllipse.d.ts.map +1 -1
  175. package/dist/umd/index.js +1 -1
  176. package/dist/umd/index.js.map +1 -1
  177. package/package.json +3 -3
  178. package/src/eventListeners/index.ts +2 -0
  179. package/src/eventListeners/segmentation/imageChangeEventListener.ts +215 -0
  180. package/src/eventListeners/segmentation/index.ts +2 -0
  181. package/src/eventListeners/segmentation/segmentationDataModifiedEventListener.ts +70 -9
  182. package/src/store/addEnabledElement.ts +2 -0
  183. package/src/store/removeEnabledElement.ts +3 -0
  184. package/src/tools/annotation/CircleROITool.ts +5 -5
  185. package/src/tools/annotation/EllipticalROITool.ts +1 -1
  186. package/src/tools/displayTools/Labelmap/addLabelmapToElement.ts +51 -22
  187. package/src/tools/displayTools/Labelmap/labelmapDisplay.ts +65 -35
  188. package/src/tools/displayTools/Labelmap/validateRepresentationData.ts +17 -11
  189. package/src/tools/segmentation/BrushTool.ts +78 -39
  190. package/src/tools/segmentation/CircleScissorsTool.ts +46 -29
  191. package/src/tools/segmentation/PaintFillTool.ts +45 -8
  192. package/src/tools/segmentation/RectangleScissorsTool.ts +41 -31
  193. package/src/tools/segmentation/SphereScissorsTool.ts +46 -28
  194. package/src/tools/segmentation/strategies/eraseCircle.ts +3 -11
  195. package/src/tools/segmentation/strategies/eraseRectangle.ts +13 -42
  196. package/src/tools/segmentation/strategies/eraseSphere.ts +2 -10
  197. package/src/tools/segmentation/strategies/fillCircle.ts +93 -61
  198. package/src/tools/segmentation/strategies/fillRectangle.ts +31 -22
  199. package/src/tools/segmentation/strategies/fillSphere.ts +51 -41
  200. package/src/tools/segmentation/strategies/utils/getStrategyData.ts +58 -0
  201. package/src/tools/segmentation/strategies/utils/isWithinThreshold.ts +3 -2
  202. package/src/tools/segmentation/strategies/utils/stackVolumeCheck.ts +33 -0
  203. package/src/types/LabelmapToolOperationData.ts +27 -0
  204. package/src/types/LabelmapTypes.ts +16 -1
  205. package/src/types/index.ts +8 -0
  206. package/src/utilities/math/ellipse/pointInEllipse.ts +43 -22
@@ -1,19 +1,16 @@
1
- import { ImageVolume, utilities as csUtils } from '@cornerstonejs/core';
1
+ import { utilities as csUtils } from '@cornerstonejs/core';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
 
4
4
  import { getBoundingBoxAroundShape } from '../../../utilities/boundingBox';
5
5
  import { pointInShapeCallback } from '../../../utilities';
6
6
  import { triggerSegmentationDataModified } from '../../../stateManagement/segmentation/triggerSegmentationEvents';
7
+ import { LabelmapToolOperationData } from '../../../types';
8
+ import { getStrategyData } from './utils/getStrategyData';
7
9
 
8
10
  const { transformWorldToIndex } = csUtils;
9
11
 
10
- type OperationData = {
11
- segmentationId: string;
12
+ type OperationData = LabelmapToolOperationData & {
12
13
  points: [Types.Point3, Types.Point3, Types.Point3, Types.Point3];
13
- volume: ImageVolume;
14
- constraintFn: (x: [number, number, number]) => boolean;
15
- segmentIndex: number;
16
- segmentsLocked: number[];
17
14
  };
18
15
 
19
16
  /**
@@ -30,19 +27,23 @@ function fillRectangle(
30
27
  operationData: OperationData,
31
28
  inside = true
32
29
  ): void {
33
- const {
34
- volume: segmentation,
35
- points,
36
- segmentsLocked,
37
- segmentIndex,
38
- segmentationId,
39
- constraintFn,
40
- } = operationData;
41
- const { imageData, dimensions } = segmentation;
42
- const scalarData = segmentation.getScalarData();
30
+ const { points, segmentsLocked, segmentIndex, segmentationId, constraintFn } =
31
+ operationData;
32
+
33
+ const strategyData = getStrategyData({
34
+ operationData,
35
+ viewport: enabledElement.viewport,
36
+ });
37
+
38
+ if (!strategyData) {
39
+ console.warn('No data found for fillRectangle');
40
+ return;
41
+ }
42
+
43
+ const { segmentationImageData, segmentationScalarData } = strategyData;
43
44
 
44
45
  let rectangleCornersIJK = points.map((world) => {
45
- return transformWorldToIndex(imageData, world);
46
+ return transformWorldToIndex(segmentationImageData, world);
46
47
  });
47
48
 
48
49
  // math round
@@ -52,7 +53,10 @@ function fillRectangle(
52
53
  });
53
54
  });
54
55
 
55
- const boundsIJK = getBoundingBoxAroundShape(rectangleCornersIJK, dimensions);
56
+ const boundsIJK = getBoundingBoxAroundShape(
57
+ rectangleCornersIJK,
58
+ segmentationImageData.getDimensions()
59
+ );
56
60
 
57
61
  // Since always all points inside the boundsIJK is inside the rectangle...
58
62
  const pointInRectangle = () => true;
@@ -63,16 +67,21 @@ function fillRectangle(
63
67
  }
64
68
 
65
69
  if (!constraintFn) {
66
- scalarData[index] = segmentIndex;
70
+ segmentationScalarData[index] = segmentIndex;
67
71
  return;
68
72
  }
69
73
 
70
74
  if (constraintFn(pointIJK)) {
71
- scalarData[index] = segmentIndex;
75
+ segmentationScalarData[index] = segmentIndex;
72
76
  }
73
77
  };
74
78
 
75
- pointInShapeCallback(imageData, pointInRectangle, callback, boundsIJK);
79
+ pointInShapeCallback(
80
+ segmentationImageData,
81
+ pointInRectangle,
82
+ callback,
83
+ boundsIJK
84
+ );
76
85
 
77
86
  triggerSegmentationDataModified(segmentationId);
78
87
  }
@@ -1,21 +1,15 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
- import { utilities as csUtils } from '@cornerstonejs/core';
2
+ import { cache, utilities as csUtils } from '@cornerstonejs/core';
3
3
 
4
4
  import { triggerSegmentationDataModified } from '../../../stateManagement/segmentation/triggerSegmentationEvents';
5
5
  import { pointInSurroundingSphereCallback } from '../../../utilities';
6
6
  import isWithinThreshold from './utils/isWithinThreshold';
7
+ import { LabelmapToolOperationData } from '../../../types';
8
+ import { getStrategyData } from './utils/getStrategyData';
9
+ import { isVolumeSegmentation } from './utils/stackVolumeCheck';
7
10
 
8
- type OperationData = {
11
+ type OperationData = LabelmapToolOperationData & {
9
12
  points: [Types.Point3, Types.Point3, Types.Point3, Types.Point3];
10
- volume: Types.IImageVolume;
11
- imageVolume: Types.IImageVolume;
12
- segmentIndex: number;
13
- segmentationId: string;
14
- segmentsLocked: number[];
15
- viewPlaneNormal: Types.Point3;
16
- viewUp: Types.Point3;
17
- strategySpecificConfiguration: any;
18
- constraintFn: () => boolean;
19
13
  };
20
14
 
21
15
  function fillSphere(
@@ -26,31 +20,36 @@ function fillSphere(
26
20
  ): void {
27
21
  const { viewport } = enabledElement;
28
22
  const {
29
- volume: segmentation,
30
23
  segmentsLocked,
31
24
  segmentIndex,
32
- imageVolume,
33
25
  strategySpecificConfiguration,
34
- segmentationId,
35
26
  points,
36
27
  } = operationData;
37
28
 
38
- const { imageData, dimensions } = segmentation;
39
- const scalarData = segmentation.getScalarData();
29
+ const strategyData = getStrategyData({ operationData, viewport });
30
+
31
+ if (!strategyData) {
32
+ console.warn('No data found for fillSphere');
33
+ return;
34
+ }
35
+
36
+ const { imageScalarData, segmentationImageData, segmentationScalarData } =
37
+ strategyData;
38
+
40
39
  const scalarIndex = [];
41
40
 
42
41
  let callback;
43
42
 
44
43
  if (threshold) {
45
- callback = ({ value, index, pointIJK }) => {
44
+ callback = ({ value, index }) => {
46
45
  if (segmentsLocked.includes(value)) {
47
46
  return;
48
47
  }
49
48
 
50
49
  if (
51
- isWithinThreshold(index, imageVolume, strategySpecificConfiguration)
50
+ isWithinThreshold(index, imageScalarData, strategySpecificConfiguration)
52
51
  ) {
53
- scalarData[index] = segmentIndex;
52
+ segmentationScalarData[index] = segmentIndex;
54
53
  scalarIndex.push(index);
55
54
  }
56
55
  };
@@ -59,30 +58,36 @@ function fillSphere(
59
58
  if (segmentsLocked.includes(value)) {
60
59
  return;
61
60
  }
62
- scalarData[index] = segmentIndex;
61
+ segmentationScalarData[index] = segmentIndex;
63
62
  scalarIndex.push(index);
64
63
  };
65
64
  }
66
65
 
67
66
  pointInSurroundingSphereCallback(
68
- imageData,
67
+ segmentationImageData,
69
68
  [points[0], points[1]],
70
69
  callback,
71
70
  viewport as Types.IVolumeViewport
72
71
  );
73
72
 
74
- // Since the scalar indexes start from the top left corner of the cube, the first
75
- // slice that needs to be rendered can be calculated from the first mask coordinate
76
- // divided by the zMultiple, as well as the last slice for the last coordinate
77
- const zMultiple = dimensions[0] * dimensions[1];
78
- const minSlice = Math.floor(scalarIndex[0] / zMultiple);
79
- const maxSlice = Math.floor(scalarIndex[scalarIndex.length - 1] / zMultiple);
80
- const sliceArray = Array.from(
81
- { length: maxSlice - minSlice + 1 },
82
- (v, k) => k + minSlice
83
- );
73
+ const dimensions = segmentationImageData.getDimensions();
84
74
 
85
- triggerSegmentationDataModified(segmentationId, sliceArray);
75
+ let sliceArray;
76
+ if (isVolumeSegmentation(operationData)) {
77
+ // Since the scalar indexes start from the top left corner of the cube, the first
78
+ // slice that needs to be rendered can be calculated from the first mask coordinate
79
+ // divided by the zMultiple, as well as the last slice for the last coordinate
80
+ const zMultiple = dimensions[0] * dimensions[1];
81
+ const minSlice = Math.floor(scalarIndex[0] / zMultiple);
82
+ const maxSlice = Math.floor(
83
+ scalarIndex[scalarIndex.length - 1] / zMultiple
84
+ );
85
+ sliceArray = Array.from(
86
+ { length: maxSlice - minSlice + 1 },
87
+ (v, k) => k + minSlice
88
+ );
89
+ triggerSegmentationDataModified(operationData.volumeId, sliceArray);
90
+ }
86
91
  }
87
92
 
88
93
  /**
@@ -108,15 +113,20 @@ export function thresholdInsideSphere(
108
113
  enabledElement: Types.IEnabledElement,
109
114
  operationData: OperationData
110
115
  ): void {
111
- const { volume, imageVolume } = operationData;
112
-
113
- if (
114
- !csUtils.isEqual(volume.dimensions, imageVolume.dimensions) ||
115
- !csUtils.isEqual(volume.direction, imageVolume.direction)
116
- ) {
117
- throw new Error(
118
- 'Only source data the same dimensions/size/orientation as the segmentation currently supported.'
119
- );
116
+ if (isVolumeSegmentation(operationData)) {
117
+ const { referencedVolumeId, volumeId } = operationData;
118
+
119
+ const imageVolume = cache.getVolume(referencedVolumeId);
120
+ const segmentation = cache.getVolume(volumeId);
121
+
122
+ if (
123
+ !csUtils.isEqual(segmentation.dimensions, imageVolume.dimensions) ||
124
+ !csUtils.isEqual(segmentation.direction, imageVolume.direction)
125
+ ) {
126
+ throw new Error(
127
+ 'Only source data the same dimensions/size/orientation as the segmentation currently supported.'
128
+ );
129
+ }
120
130
  }
121
131
 
122
132
  fillSphere(enabledElement, operationData, true, true);
@@ -0,0 +1,58 @@
1
+ import { cache } from '@cornerstonejs/core';
2
+ import { isVolumeSegmentation } from './stackVolumeCheck';
3
+ import { LabelmapToolOperationDataStack } from '../../../../types';
4
+
5
+ function getStrategyData({ operationData, viewport }) {
6
+ let segmentationImageData, segmentationScalarData, imageScalarData;
7
+ if (isVolumeSegmentation(operationData)) {
8
+ const { volumeId, referencedVolumeId } = operationData;
9
+
10
+ const segmentationVolume = cache.getVolume(volumeId);
11
+ const imageVolume = cache.getVolume(referencedVolumeId);
12
+
13
+ if (!segmentationVolume || !imageVolume) {
14
+ return;
15
+ }
16
+
17
+ ({ imageData: segmentationImageData } = segmentationVolume);
18
+ segmentationScalarData = segmentationVolume.getScalarData();
19
+ imageScalarData = imageVolume.getScalarData();
20
+ } else {
21
+ const { imageIdReferenceMap, segmentationRepresentationUID } =
22
+ operationData as LabelmapToolOperationDataStack;
23
+
24
+ if (!imageIdReferenceMap) {
25
+ return;
26
+ }
27
+
28
+ const currentImageId = viewport.getCurrentImageId();
29
+ if (!currentImageId) {
30
+ return;
31
+ }
32
+
33
+ // we know that the segmentationRepresentationUID is the name of the actor always
34
+ // and always circle modifies the current imageId which in fact is the imageData
35
+ // of that actor at that moment so we have the imageData already
36
+ const actor = viewport.getActor(segmentationRepresentationUID);
37
+ segmentationImageData = actor.actor.getMapper().getInputData();
38
+ const currentSegmentationImageId = imageIdReferenceMap.get(currentImageId);
39
+
40
+ const segmentationImage = cache.getImage(currentSegmentationImageId);
41
+ segmentationScalarData = segmentationImage.getPixelData();
42
+
43
+ const image = cache.getImage(currentImageId);
44
+
45
+ // VERY IMPORTANT
46
+ // This is the pixel data of the image that is being segmented in the cache
47
+ // and we need to use this to for the modification
48
+ imageScalarData = image.getPixelData();
49
+ }
50
+
51
+ return {
52
+ segmentationImageData,
53
+ segmentationScalarData,
54
+ imageScalarData,
55
+ };
56
+ }
57
+
58
+ export { getStrategyData };
@@ -1,13 +1,14 @@
1
1
  import { Types } from '@cornerstonejs/core';
2
+ import { TypedArray } from '@kitware/vtk.js/types';
2
3
 
3
4
  function isWithinThreshold(
4
5
  index: number,
5
- imageVolume: Types.IImageVolume,
6
+ imageScalarData: TypedArray,
6
7
  strategySpecificConfiguration: any
7
8
  ) {
8
9
  const { THRESHOLD_INSIDE_CIRCLE } = strategySpecificConfiguration;
9
10
 
10
- const voxelValue = imageVolume.getScalarData()[index];
11
+ const voxelValue = imageScalarData[index];
11
12
  const { threshold } = THRESHOLD_INSIDE_CIRCLE;
12
13
 
13
14
  return threshold[0] <= voxelValue && voxelValue <= threshold[1];
@@ -0,0 +1,33 @@
1
+ import {
2
+ LabelmapSegmentationData,
3
+ LabelmapSegmentationDataStack,
4
+ LabelmapSegmentationDataVolume,
5
+ } from '../../../../types/LabelmapTypes';
6
+ import {
7
+ LabelmapToolOperationData,
8
+ LabelmapToolOperationDataStack,
9
+ LabelmapToolOperationDataVolume,
10
+ } from '../../../../types';
11
+
12
+ function isStackSegmentation(
13
+ operationData: LabelmapToolOperationData | LabelmapSegmentationData
14
+ ): operationData is
15
+ | LabelmapToolOperationDataStack
16
+ | LabelmapSegmentationDataStack {
17
+ return (
18
+ (operationData as LabelmapToolOperationDataStack).imageIdReferenceMap !==
19
+ undefined
20
+ );
21
+ }
22
+
23
+ function isVolumeSegmentation(
24
+ operationData: LabelmapToolOperationData | LabelmapSegmentationData
25
+ ): operationData is
26
+ | LabelmapToolOperationDataVolume
27
+ | LabelmapSegmentationDataVolume {
28
+ return (
29
+ (operationData as LabelmapToolOperationDataVolume).volumeId !== undefined
30
+ );
31
+ }
32
+
33
+ export { isStackSegmentation, isVolumeSegmentation };
@@ -0,0 +1,27 @@
1
+ import {
2
+ LabelmapSegmentationDataStack,
3
+ LabelmapSegmentationDataVolume,
4
+ } from './LabelmapTypes';
5
+
6
+ type LabelmapToolOperationData = {
7
+ segmentationId: string;
8
+ segmentIndex: number;
9
+ segmentsLocked: number[];
10
+ viewPlaneNormal: number[];
11
+ viewUp: number[];
12
+ strategySpecificConfiguration: any;
13
+ constraintFn: (pointIJK: number) => boolean;
14
+ segmentationRepresentationUID: string;
15
+ };
16
+
17
+ type LabelmapToolOperationDataStack = LabelmapToolOperationData &
18
+ LabelmapSegmentationDataStack;
19
+
20
+ type LabelmapToolOperationDataVolume = LabelmapToolOperationData &
21
+ LabelmapSegmentationDataVolume;
22
+
23
+ export {
24
+ LabelmapToolOperationData,
25
+ LabelmapToolOperationDataStack,
26
+ LabelmapToolOperationDataVolume,
27
+ };
@@ -35,7 +35,22 @@ export type LabelmapRenderingConfig = {
35
35
  ofun?: vtkPiecewiseFunction;
36
36
  };
37
37
 
38
- export type LabelmapSegmentationData = {
38
+ export type LabelmapSegmentationDataVolume = {
39
39
  volumeId: string;
40
40
  referencedVolumeId?: string;
41
41
  };
42
+
43
+ export type LabelmapSegmentationDataStack = {
44
+ /**
45
+ * This is a Map from referenced imageId to the segmentation (Derived) imageId that
46
+ * has been used to create the derived labelmap.
47
+ * Todo: later I guess we can have it as Record<string, metadata> where metadata
48
+ * can contain a derived image arbitrary information, for use cases such that the labelmap is
49
+ * derived from another image that is irrelevant to the current viewport.
50
+ */
51
+ imageIdReferenceMap: Map<string, string>;
52
+ };
53
+
54
+ export type LabelmapSegmentationData =
55
+ | LabelmapSegmentationDataVolume
56
+ | LabelmapSegmentationDataStack;
@@ -58,6 +58,11 @@ import type { ContourSegmentationData } from './ContourTypes';
58
58
  import type IAnnotationManager from './IAnnotationManager';
59
59
  import type AnnotationGroupSelector from './AnnotationGroupSelector';
60
60
  import type { Statistics } from './CalculatorTypes';
61
+ import {
62
+ LabelmapToolOperationData,
63
+ LabelmapToolOperationDataStack,
64
+ LabelmapToolOperationDataVolume,
65
+ } from './LabelmapToolOperationData';
61
66
 
62
67
  export type {
63
68
  // AnnotationState
@@ -124,4 +129,7 @@ export type {
124
129
  ContourSegmentationData,
125
130
  //Statistics
126
131
  Statistics,
132
+ LabelmapToolOperationData,
133
+ LabelmapToolOperationDataStack,
134
+ LabelmapToolOperationDataVolume,
127
135
  };
@@ -1,39 +1,60 @@
1
- import type { Types } from '@cornerstonejs/core';
2
- import { vec3 } from 'gl-matrix';
3
-
4
- type Ellipse = {
5
- center: Types.Point3;
6
- xRadius: number;
7
- yRadius: number;
8
- zRadius: number;
9
- };
1
+ interface Inverts {
2
+ invXRadiusSq?: number;
3
+ invYRadiusSq?: number;
4
+ invZRadiusSq?: number;
5
+ fast?: boolean;
6
+ }
10
7
 
11
8
  /**
12
9
  * Given an ellipse and a point, return true if the point is inside the ellipse
13
10
  * @param ellipse - The ellipse object to check against.
14
11
  * @param pointLPS - The point in LPS space to test.
12
+ * @param inverts - An object to cache the inverted radius squared values, if you
13
+ * are testing multiple points against the same ellipse then it is recommended to
14
+ * pass in the same object to cache the values. However, there is a simpler way
15
+ * to do this by passing in the fast flag as true, then on the first iteration
16
+ * the values will be cached and on subsequent iterations the cached values will
17
+ * be used.
18
+ *
15
19
  * @returns A boolean value.
16
20
  */
17
21
  export default function pointInEllipse(
18
- ellipse: Ellipse,
19
- pointLPS: vec3
20
- ): boolean {
21
- const { center: circleCenterWorld, xRadius, yRadius, zRadius } = ellipse;
22
- const [x, y, z] = pointLPS;
23
- const [x0, y0, z0] = circleCenterWorld;
22
+ ellipse,
23
+ pointLPS,
24
+ inverts: Inverts = {}
25
+ ) {
26
+ const { center, xRadius, yRadius, zRadius } = ellipse;
24
27
 
25
- let inside = 0;
26
- if (xRadius !== 0) {
27
- inside += ((x - x0) * (x - x0)) / (xRadius * xRadius);
28
+ // This will run only once since we are caching the values in the same
29
+ // object that is passed in.
30
+ if (
31
+ inverts.invXRadiusSq === undefined ||
32
+ inverts.invYRadiusSq === undefined ||
33
+ inverts.invZRadiusSq === undefined
34
+ ) {
35
+ inverts.invXRadiusSq = xRadius !== 0 ? 1 / xRadius ** 2 : 0;
36
+ inverts.invYRadiusSq = yRadius !== 0 ? 1 / yRadius ** 2 : 0;
37
+ inverts.invZRadiusSq = zRadius !== 0 ? 1 / zRadius ** 2 : 0;
28
38
  }
29
39
 
30
- if (yRadius !== 0) {
31
- inside += ((y - y0) * (y - y0)) / (yRadius * yRadius);
40
+ let inside = 0;
41
+
42
+ // Calculate the sum of normalized squared distances
43
+ const dx = pointLPS[0] - center[0];
44
+ inside += dx * dx * inverts.invXRadiusSq;
45
+ if (inside > 1) {
46
+ return false;
32
47
  }
33
48
 
34
- if (zRadius !== 0) {
35
- inside += ((z - z0) * (z - z0)) / (zRadius * zRadius);
49
+ const dy = pointLPS[1] - center[1];
50
+ inside += dy * dy * inverts.invYRadiusSq;
51
+ if (inside > 1) {
52
+ return false;
36
53
  }
37
54
 
55
+ const dz = pointLPS[2] - center[2];
56
+ inside += dz * dz * inverts.invZRadiusSq;
57
+
58
+ // Check if the point is inside the ellipse
38
59
  return inside <= 1;
39
60
  }