@cornerstonejs/tools 1.65.2 → 1.65.4

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 (79) hide show
  1. package/dist/cjs/enums/StrategyCallbacks.d.ts +2 -1
  2. package/dist/cjs/enums/StrategyCallbacks.js +1 -0
  3. package/dist/cjs/enums/StrategyCallbacks.js.map +1 -1
  4. package/dist/cjs/stateManagement/annotation/annotationSelection.js +2 -1
  5. package/dist/cjs/stateManagement/annotation/annotationSelection.js.map +1 -1
  6. package/dist/cjs/tools/MIPJumpToClickTool.js +2 -1
  7. package/dist/cjs/tools/MIPJumpToClickTool.js.map +1 -1
  8. package/dist/cjs/tools/StackScrollToolMouseWheelTool.js +2 -1
  9. package/dist/cjs/tools/StackScrollToolMouseWheelTool.js.map +1 -1
  10. package/dist/cjs/tools/base/AnnotationDisplayTool.js +2 -1
  11. package/dist/cjs/tools/base/AnnotationDisplayTool.js.map +1 -1
  12. package/dist/cjs/tools/base/AnnotationTool.js +2 -1
  13. package/dist/cjs/tools/base/AnnotationTool.js.map +1 -1
  14. package/dist/cjs/tools/base/BaseTool.js +2 -1
  15. package/dist/cjs/tools/base/BaseTool.js.map +1 -1
  16. package/dist/cjs/tools/segmentation/BrushTool.js +16 -4
  17. package/dist/cjs/tools/segmentation/BrushTool.js.map +1 -1
  18. package/dist/cjs/tools/segmentation/strategies/BrushStrategy.d.ts +3 -0
  19. package/dist/cjs/tools/segmentation/strategies/BrushStrategy.js +1 -0
  20. package/dist/cjs/tools/segmentation/strategies/BrushStrategy.js.map +1 -1
  21. package/dist/cjs/tools/segmentation/strategies/compositions/dynamicThreshold.d.ts +1 -0
  22. package/dist/cjs/tools/segmentation/strategies/compositions/dynamicThreshold.js +20 -0
  23. package/dist/cjs/tools/segmentation/strategies/compositions/dynamicThreshold.js.map +1 -1
  24. package/dist/cjs/tools/segmentation/strategies/compositions/index.d.ts +1 -0
  25. package/dist/cjs/utilities/getVolumeId.d.ts +1 -0
  26. package/dist/cjs/utilities/getVolumeId.js +16 -0
  27. package/dist/cjs/utilities/getVolumeId.js.map +1 -0
  28. package/dist/esm/enums/StrategyCallbacks.js +1 -0
  29. package/dist/esm/enums/StrategyCallbacks.js.map +1 -1
  30. package/dist/esm/stateManagement/annotation/annotationSelection.js +1 -1
  31. package/dist/esm/stateManagement/annotation/annotationSelection.js.map +1 -1
  32. package/dist/esm/tools/MIPJumpToClickTool.js +2 -1
  33. package/dist/esm/tools/MIPJumpToClickTool.js.map +1 -1
  34. package/dist/esm/tools/StackScrollToolMouseWheelTool.js +2 -1
  35. package/dist/esm/tools/StackScrollToolMouseWheelTool.js.map +1 -1
  36. package/dist/esm/tools/base/AnnotationDisplayTool.js +2 -1
  37. package/dist/esm/tools/base/AnnotationDisplayTool.js.map +1 -1
  38. package/dist/esm/tools/base/AnnotationTool.js +2 -1
  39. package/dist/esm/tools/base/AnnotationTool.js.map +1 -1
  40. package/dist/esm/tools/base/BaseTool.js +2 -1
  41. package/dist/esm/tools/base/BaseTool.js.map +1 -1
  42. package/dist/esm/tools/segmentation/BrushTool.js +16 -4
  43. package/dist/esm/tools/segmentation/BrushTool.js.map +1 -1
  44. package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +1 -0
  45. package/dist/esm/tools/segmentation/strategies/BrushStrategy.js.map +1 -1
  46. package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js +20 -0
  47. package/dist/esm/tools/segmentation/strategies/compositions/dynamicThreshold.js.map +1 -1
  48. package/dist/esm/utilities/getVolumeId.js +12 -0
  49. package/dist/esm/utilities/getVolumeId.js.map +1 -0
  50. package/dist/types/enums/StrategyCallbacks.d.ts +2 -1
  51. package/dist/types/enums/StrategyCallbacks.d.ts.map +1 -1
  52. package/dist/types/tools/MIPJumpToClickTool.d.ts.map +1 -1
  53. package/dist/types/tools/StackScrollToolMouseWheelTool.d.ts.map +1 -1
  54. package/dist/types/tools/base/AnnotationDisplayTool.d.ts.map +1 -1
  55. package/dist/types/tools/base/AnnotationTool.d.ts.map +1 -1
  56. package/dist/types/tools/base/BaseTool.d.ts.map +1 -1
  57. package/dist/types/tools/segmentation/BrushTool.d.ts.map +1 -1
  58. package/dist/types/tools/segmentation/strategies/BrushStrategy.d.ts +3 -0
  59. package/dist/types/tools/segmentation/strategies/BrushStrategy.d.ts.map +1 -1
  60. package/dist/types/tools/segmentation/strategies/compositions/dynamicThreshold.d.ts +1 -0
  61. package/dist/types/tools/segmentation/strategies/compositions/dynamicThreshold.d.ts.map +1 -1
  62. package/dist/types/tools/segmentation/strategies/compositions/index.d.ts +1 -0
  63. package/dist/types/tools/segmentation/strategies/compositions/index.d.ts.map +1 -1
  64. package/dist/types/utilities/getVolumeId.d.ts +2 -0
  65. package/dist/types/utilities/getVolumeId.d.ts.map +1 -0
  66. package/dist/umd/index.js +1 -1
  67. package/dist/umd/index.js.map +1 -1
  68. package/package.json +3 -3
  69. package/src/enums/StrategyCallbacks.ts +3 -0
  70. package/src/stateManagement/annotation/annotationSelection.ts +1 -1
  71. package/src/tools/MIPJumpToClickTool.ts +2 -1
  72. package/src/tools/StackScrollToolMouseWheelTool.ts +2 -1
  73. package/src/tools/base/AnnotationDisplayTool.ts +2 -1
  74. package/src/tools/base/AnnotationTool.ts +2 -1
  75. package/src/tools/base/BaseTool.ts +2 -1
  76. package/src/tools/segmentation/BrushTool.ts +21 -5
  77. package/src/tools/segmentation/strategies/BrushStrategy.ts +4 -0
  78. package/src/tools/segmentation/strategies/compositions/dynamicThreshold.ts +43 -0
  79. package/src/utilities/getVolumeId.ts +13 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.65.2",
3
+ "version": "1.65.4",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "src/index.ts",
6
6
  "types": "dist/types/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
30
30
  },
31
31
  "dependencies": {
32
- "@cornerstonejs/core": "^1.65.2",
32
+ "@cornerstonejs/core": "^1.65.4",
33
33
  "@icr/polyseg-wasm": "0.4.0",
34
34
  "@types/offscreencanvas": "2019.7.3",
35
35
  "comlink": "^4.4.1",
@@ -59,5 +59,5 @@
59
59
  "type": "individual",
60
60
  "url": "https://ohif.org/donate"
61
61
  },
62
- "gitHead": "be39531d17ce98dba80029a869380f5d845e1f4d"
62
+ "gitHead": "9f0c1e30b8bf4cfca1ca04186f377e2a2f3a2b54"
63
63
  }
@@ -47,6 +47,9 @@ enum StrategyCallbacks {
47
47
 
48
48
  // Internal Details
49
49
  INTERNAL_setValue = 'setValue',
50
+
51
+ /** inner circle size */
52
+ ComputeInnerCircleRadius = 'computeInnerCircleRadius',
50
53
  }
51
54
 
52
55
  export default StrategyCallbacks;
@@ -94,7 +94,7 @@ function getAnnotationsSelected(): Array<string> {
94
94
  function getAnnotationsSelectedByToolName(toolName: string): Array<string> {
95
95
  return getAnnotationsSelected().filter((annotationUID) => {
96
96
  const annotation = getAnnotation(annotationUID);
97
- return annotation.metadata.toolName === toolName;
97
+ return annotation?.metadata?.toolName === toolName;
98
98
  });
99
99
  }
100
100
 
@@ -5,6 +5,7 @@ import { getPointInLineOfSightWithCriteria } from '../utilities/planar';
5
5
  import jumpToWorld from '../utilities/viewport/jumpToWorld';
6
6
  import { PublicToolProps, ToolProps } from '../types';
7
7
  import { getToolGroupForViewport } from '../store/ToolGroupManager';
8
+ import { getVolumeId } from '../utilities/getVolumeId';
8
9
 
9
10
  /**
10
11
  * On a Maximum Intensity Projection (MIP) viewport, MIPJumpToClickTool allows the
@@ -54,7 +55,7 @@ class MIPJumpToClickTool extends BaseTool {
54
55
  );
55
56
  }
56
57
 
57
- const volumeId = targetId.split(/volumeId:|\?/)[1];
58
+ const volumeId = getVolumeId(targetId);
58
59
 
59
60
  // 3. Criteria function to search for the point (maximum intensity)
60
61
  let maxIntensity = -Infinity;
@@ -2,6 +2,7 @@ import { getEnabledElement } from '@cornerstonejs/core';
2
2
  import { BaseTool } from './base';
3
3
  import { MouseWheelEventType } from '../types/EventTypes';
4
4
  import scroll from '../utilities/scroll';
5
+ import { getVolumeId } from '../utilities/getVolumeId';
5
6
 
6
7
  /**
7
8
  * The StackScrollMouseWheelTool is a tool that allows the user to scroll through a
@@ -35,7 +36,7 @@ class StackScrollMouseWheelTool extends BaseTool {
35
36
  const delta = direction * (invert ? -1 : 1);
36
37
 
37
38
  const targetId = this.getTargetId(viewport);
38
- const volumeId = targetId.split(/volumeId:|\?/)[1];
39
+ const volumeId = getVolumeId(targetId);
39
40
 
40
41
  scroll(viewport, {
41
42
  delta,
@@ -15,6 +15,7 @@ import filterAnnotationsForDisplay from '../../utilities/planar/filterAnnotation
15
15
  import { getStyleProperty } from '../../stateManagement/annotation/config/helpers';
16
16
  import { getState } from '../../stateManagement/annotation/config';
17
17
  import { StyleSpecifier } from '../../types/AnnotationStyle';
18
+ import { getVolumeId } from '../../utilities/getVolumeId';
18
19
 
19
20
  /**
20
21
  * Abstract class for tools which create and display annotations on the
@@ -137,7 +138,7 @@ abstract class AnnotationDisplayTool extends BaseTool {
137
138
  } else if (viewport instanceof VideoViewport) {
138
139
  referencedImageId = targetId.split('videoId:')[1];
139
140
  } else {
140
- const volumeId = targetId.split(/volumeId:|\?/)[1];
141
+ const volumeId = getVolumeId(targetId);
141
142
  const imageVolume = cache.getVolume(volumeId);
142
143
 
143
144
  referencedImageId = utilities.getClosestImageId(
@@ -24,6 +24,7 @@ import {
24
24
  import { addAnnotation } from '../../stateManagement/annotation/annotationState';
25
25
  import { StyleSpecifier } from '../../types/AnnotationStyle';
26
26
  import { triggerAnnotationModified } from '../../stateManagement/annotation/helpers/state';
27
+ import { getVolumeId } from '../../utilities/getVolumeId';
27
28
 
28
29
  /**
29
30
  * Abstract class for tools which create and display annotations on the
@@ -368,7 +369,7 @@ abstract class AnnotationTool extends AnnotationDisplayTool {
368
369
  imageId?: string
369
370
  ): boolean {
370
371
  if (viewport instanceof BaseVolumeViewport) {
371
- const volumeId = targetId.split(/volumeId:|\?/)[1];
372
+ const volumeId = getVolumeId(targetId);
372
373
  const volume = cache.getVolume(volumeId);
373
374
  return volume.scaling?.PT !== undefined;
374
375
  }
@@ -3,6 +3,7 @@ import { Types } from '@cornerstonejs/core';
3
3
  import ToolModes from '../../enums/ToolModes';
4
4
  import StrategyCallbacks from '../../enums/StrategyCallbacks';
5
5
  import { InteractionTypes, ToolProps, PublicToolProps } from '../../types';
6
+ import { getVolumeId } from '../../utilities/getVolumeId';
6
7
 
7
8
  export interface IBaseTool {
8
9
  /** ToolGroup ID the tool instance belongs to */
@@ -208,7 +209,7 @@ abstract class BaseTool implements IBaseTool {
208
209
 
209
210
  return viewports[0].getImageData();
210
211
  } else if (targetId.startsWith('volumeId:')) {
211
- const volumeId = targetId.split(/volumeId:|\?/)[1];
212
+ const volumeId = getVolumeId(targetId);
212
213
  const viewports = utilities.getViewportsWithVolumeId(
213
214
  volumeId,
214
215
  renderingEngine.id
@@ -108,6 +108,7 @@ class BrushTool extends BaseTool {
108
108
  strategySpecificConfiguration: {
109
109
  THRESHOLD: {
110
110
  threshold: [-150, -70], // E.g. CT Fat // Only used during threshold strategies.
111
+ dynamicRadius: 0, // in voxel counts in each direction, only used during dynamic threshold strategies.
111
112
  },
112
113
  },
113
114
  defaultStrategy: 'FILL_INSIDE_CIRCLE',
@@ -126,8 +127,6 @@ class BrushTool extends BaseTool {
126
127
  // The time to consider a mouse click a drag when moved less than dragMoveDistance
127
128
  dragTimeMs: 500,
128
129
  },
129
- // Whether to show a center circle/position. Set to null to not show
130
- centerRadius: 2,
131
130
  actions: {
132
131
  [StrategyCallbacks.AcceptPreview]: {
133
132
  method: StrategyCallbacks.AcceptPreview,
@@ -584,6 +583,18 @@ class BrushTool extends BaseTool {
584
583
  rightCursorInWorld,
585
584
  ];
586
585
 
586
+ const activeStrategy = this.configuration.activeStrategy;
587
+ const strategy = this.configuration.strategies[activeStrategy];
588
+
589
+ // Note: i don't think this is the best way to implement this
590
+ // but don't think we have a better way to do it for now
591
+ if (typeof strategy.computeInnerCircleRadius === 'function') {
592
+ strategy.computeInnerCircleRadius({
593
+ configuration: this.configuration,
594
+ viewport,
595
+ });
596
+ }
597
+
587
598
  data.invalidated = false;
588
599
  }
589
600
 
@@ -776,15 +787,20 @@ class BrushTool extends BaseTool {
776
787
  }
777
788
  );
778
789
 
779
- const { centerRadius } = this.configuration;
780
- if (centerRadius >= 0) {
790
+ const activeStrategy = this.configuration.activeStrategy;
791
+ const { dynamicRadiusInCanvas } = this.configuration
792
+ .strategySpecificConfiguration[activeStrategy] || {
793
+ dynamicRadiusInCanvas: 0,
794
+ };
795
+
796
+ if (dynamicRadiusInCanvas) {
781
797
  const circleUID1 = '1';
782
798
  drawCircleSvg(
783
799
  svgDrawingHelper,
784
800
  annotationUID,
785
801
  circleUID1,
786
802
  center as Types.Point2,
787
- 2,
803
+ dynamicRadiusInCanvas,
788
804
  {
789
805
  color,
790
806
  }
@@ -34,6 +34,7 @@ export type InitializedOperationData = LabelmapToolOperationDataAny & {
34
34
  previewSegmentIndex?: number;
35
35
 
36
36
  brushStrategy: BrushStrategy;
37
+ configuration?: Record<string, any>;
37
38
  };
38
39
 
39
40
  export type StrategyFunction = (
@@ -110,6 +111,9 @@ export default class BrushStrategy {
110
111
  StrategyCallbacks.Preview,
111
112
  false
112
113
  ),
114
+ [StrategyCallbacks.ComputeInnerCircleRadius]: addListMethod(
115
+ StrategyCallbacks.ComputeInnerCircleRadius
116
+ ),
113
117
  // Add other exposed fields below
114
118
  // initializers is exposed on the function to allow extension of the composition object
115
119
  compositions: null,
@@ -1,4 +1,5 @@
1
1
  import { vec3 } from 'gl-matrix';
2
+ import type { Types } from '@cornerstonejs/core';
2
3
  import type { InitializedOperationData } from '../BrushStrategy';
3
4
  import type BoundsIJK from '../../../../types/BoundsIJK';
4
5
  import StrategyCallbacks from '../../../../enums/StrategyCallbacks';
@@ -65,4 +66,46 @@ export default {
65
66
  }
66
67
  strategySpecificConfiguration.THRESHOLD.threshold = null;
67
68
  },
69
+ /**
70
+ * It computes the inner circle radius in canvas coordinates and stores it
71
+ * in the strategySpecificConfiguration. This is used to show the user
72
+ * the area that is used to compute the threshold.
73
+ */
74
+ [StrategyCallbacks.ComputeInnerCircleRadius]: (
75
+ operationData: InitializedOperationData
76
+ ) => {
77
+ const { configuration, viewport } = operationData;
78
+ const { THRESHOLD: { dynamicRadius = 0 } = {} } =
79
+ configuration.strategySpecificConfiguration || {};
80
+ const { spacing } = (
81
+ viewport as Types.IStackViewport | Types.IVolumeViewport
82
+ ).getImageData();
83
+ const centerCanvas = [
84
+ viewport.element.clientWidth / 2,
85
+ viewport.element.clientHeight / 2,
86
+ ] as Types.Point2;
87
+ const radiusInWorld = dynamicRadius * spacing[0];
88
+ const centerCursorInWorld = viewport.canvasToWorld(centerCanvas);
89
+
90
+ const offSetCenterInWorld = centerCursorInWorld.map(
91
+ (coord) => coord + radiusInWorld
92
+ ) as Types.Point3;
93
+
94
+ const offSetCenterCanvas = viewport.worldToCanvas(offSetCenterInWorld);
95
+ const dynamicRadiusInCanvas = Math.abs(
96
+ centerCanvas[0] - offSetCenterCanvas[0]
97
+ );
98
+
99
+ // this is a bit of a hack, since we have switched to using THRESHOLD
100
+ // as strategy but really strategy names are CIRCLE_THRESHOLD and SPHERE_THRESHOLD
101
+ // and we can't really change the name of the strategy in the configuration
102
+ const { strategySpecificConfiguration, activeStrategy } = configuration;
103
+
104
+ if (!strategySpecificConfiguration[activeStrategy]) {
105
+ strategySpecificConfiguration[activeStrategy] = {};
106
+ }
107
+
108
+ strategySpecificConfiguration[activeStrategy].dynamicRadiusInCanvas =
109
+ dynamicRadiusInCanvas;
110
+ },
68
111
  };
@@ -0,0 +1,13 @@
1
+ export const getVolumeId = (targetId: string) => {
2
+ const prefix = 'volumeId:';
3
+ const str = targetId.includes(prefix)
4
+ ? targetId.substring(prefix.length)
5
+ : targetId;
6
+
7
+ if (str.startsWith('nifti:')) {
8
+ return str;
9
+ }
10
+
11
+ const index = str.indexOf('?');
12
+ return index === -1 ? str : str.substring(0, index);
13
+ };