@cornerstonejs/tools 2.0.0-beta.23 → 2.0.0-beta.25

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 (70) hide show
  1. package/dist/esm/enums/SegmentationRepresentations.d.ts +3 -3
  2. package/dist/esm/enums/SegmentationRepresentations.js +3 -3
  3. package/dist/esm/eventDispatchers/mouseEventHandlers/mouseMove.js +4 -0
  4. package/dist/esm/eventListeners/segmentation/labelmap/onLabelmapSegmentationDataModified.js +27 -23
  5. package/dist/esm/eventListeners/segmentation/segmentationDataModifiedEventListener.js +2 -2
  6. package/dist/esm/stateManagement/index.d.ts +3 -2
  7. package/dist/esm/stateManagement/index.js +2 -2
  8. package/dist/esm/stateManagement/segmentation/SegmentationRenderingEngine.d.ts +1 -2
  9. package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +9 -6
  10. package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +72 -24
  11. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.d.ts +8 -3
  12. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.js +14 -4
  13. package/dist/esm/stateManagement/segmentation/config/segmentationConfig.d.ts +8 -7
  14. package/dist/esm/stateManagement/segmentation/convertVolumeToStackSegmentation.js +1 -1
  15. package/dist/esm/stateManagement/segmentation/getGlobalConfig.d.ts +2 -2
  16. package/dist/esm/stateManagement/segmentation/getPerSegmentConfig.d.ts +2 -2
  17. package/dist/esm/stateManagement/segmentation/getStackSegmentationImageIdsForViewport.d.ts +1 -0
  18. package/dist/esm/stateManagement/segmentation/getStackSegmentationImageIdsForViewport.js +5 -0
  19. package/dist/esm/stateManagement/segmentation/helpers/updateStackSegmentationState.js +5 -5
  20. package/dist/esm/stateManagement/segmentation/index.d.ts +2 -2
  21. package/dist/esm/stateManagement/segmentation/index.js +2 -2
  22. package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.d.ts +3 -0
  23. package/dist/esm/stateManagement/segmentation/{addSegmentationRepresentation.js → internalAddSegmentationRepresentation.js} +4 -3
  24. package/dist/esm/stateManagement/segmentation/polySeg/Contour/contourComputationStrategies.js +4 -4
  25. package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +4 -4
  26. package/dist/esm/stateManagement/segmentation/polySeg/Surface/createAndCacheSurfacesFromRaw.js +1 -1
  27. package/dist/esm/stateManagement/segmentation/polySeg/Surface/surfaceComputationStrategies.js +6 -6
  28. package/dist/esm/stateManagement/segmentation/polySeg/Surface/updateSurfaceData.js +2 -2
  29. package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +2 -2
  30. package/dist/esm/stateManagement/segmentation/segmentationState.js +2 -2
  31. package/dist/esm/stateManagement/segmentation/setGlobalConfig.d.ts +2 -2
  32. package/dist/esm/stateManagement/segmentation/setPerSegmentConfig.d.ts +2 -2
  33. package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +1 -1
  34. package/dist/esm/tools/AdvancedMagnifyTool.js +2 -2
  35. package/dist/esm/tools/ScaleOverlayTool.js +23 -20
  36. package/dist/esm/tools/annotation/LivewireContourTool.d.ts +5 -0
  37. package/dist/esm/tools/annotation/LivewireContourTool.js +156 -8
  38. package/dist/esm/tools/base/BaseTool.d.ts +1 -13
  39. package/dist/esm/tools/base/ContourSegmentationBaseTool.js +1 -1
  40. package/dist/esm/tools/displayTools/Contour/contourHandler/handleContourSegmentation.js +4 -4
  41. package/dist/esm/tools/displayTools/Contour/contourHandler/utils.js +1 -1
  42. package/dist/esm/tools/displayTools/Contour/removeContourFromElement.js +1 -1
  43. package/dist/esm/tools/segmentation/BrushTool.d.ts +38 -0
  44. package/dist/esm/tools/segmentation/BrushTool.js +40 -7
  45. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +23 -15
  46. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +6 -0
  47. package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +10 -5
  48. package/dist/esm/tools/segmentation/strategies/compositions/islandRemoval.js +1 -1
  49. package/dist/esm/tools/segmentation/strategies/compositions/preview.js +2 -2
  50. package/dist/esm/tools/segmentation/strategies/compositions/setValue.js +6 -4
  51. package/dist/esm/tools/segmentation/strategies/fillSphere.js +5 -14
  52. package/dist/esm/types/EventTypes.d.ts +1 -2
  53. package/dist/esm/types/IBaseTool.d.ts +2 -0
  54. package/dist/esm/types/IBaseTool.js +1 -0
  55. package/dist/esm/types/IToolGroup.d.ts +3 -63
  56. package/dist/esm/types/LabelmapToolOperationData.d.ts +5 -0
  57. package/dist/esm/types/SegmentationStateTypes.d.ts +22 -22
  58. package/dist/esm/types/index.d.ts +3 -2
  59. package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js +3 -3
  60. package/dist/esm/utilities/contourSegmentation/removeContourSegmentationAnnotation.js +1 -1
  61. package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.js +7 -7
  62. package/dist/esm/utilities/segmentation/getHoveredContourSegmentationAnnotation.js +1 -1
  63. package/dist/esm/utilities/segmentation/getSegmentIndexAtLabelmapBorder.js +8 -4
  64. package/dist/esm/utilities/segmentation/getSegmentIndexAtWorldPoint.js +2 -2
  65. package/dist/esm/utilities/segmentation/getUniqueSegmentIndices.js +2 -2
  66. package/dist/esm/utilities/segmentation/isLineInSegment.js +3 -3
  67. package/dist/umd/index.js +1 -1
  68. package/dist/umd/index.js.map +1 -1
  69. package/package.json +16 -7
  70. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentation.d.ts +0 -3
@@ -29,7 +29,7 @@ export async function createAndCacheSurfacesFromRaw(segmentationId, rawSurfacesD
29
29
  const geometryId = closedSurface.id;
30
30
  geometryIds.set(segmentIndex, geometryId);
31
31
  return geometryLoader.createAndCacheGeometry(geometryId, {
32
- type: Enums.GeometryType.SURFACE,
32
+ type: Enums.GeometryType.Surface,
33
33
  geometryData: closedSurface,
34
34
  });
35
35
  });
@@ -12,13 +12,13 @@ export async function computeSurfaceData(segmentationId, options = {}) {
12
12
  const segmentation = getSegmentation(segmentationId);
13
13
  const representationData = segmentation.representationData;
14
14
  try {
15
- if (representationData.CONTOUR) {
15
+ if (representationData.Contour) {
16
16
  rawSurfacesData = await computeSurfaceFromContourSegmentation(segmentationId, {
17
17
  segmentIndices,
18
18
  ...options,
19
19
  });
20
20
  }
21
- else if (representationData.LABELMAP) {
21
+ else if (representationData.Labelmap) {
22
22
  rawSurfacesData = await computeSurfaceFromLabelmapSegmentation(segmentation.segmentationId, {
23
23
  segmentIndices,
24
24
  ...options,
@@ -37,12 +37,12 @@ export async function computeSurfaceData(segmentationId, options = {}) {
37
37
  }
38
38
  async function computeSurfaceFromLabelmapSegmentation(segmentationId, options = {}) {
39
39
  const segmentation = getSegmentation(segmentationId);
40
- if (!segmentation?.representationData?.LABELMAP) {
40
+ if (!segmentation?.representationData?.Labelmap) {
41
41
  console.warn('Only support surface update from labelmaps');
42
42
  return;
43
43
  }
44
- const isVolume = isVolumeSegmentation(segmentation.representationData.LABELMAP);
45
- const labelmapRepresentationData = segmentation.representationData.LABELMAP;
44
+ const isVolume = isVolumeSegmentation(segmentation.representationData.Labelmap);
45
+ const labelmapRepresentationData = segmentation.representationData.Labelmap;
46
46
  const segmentIndices = options.segmentIndices || getUniqueSegmentIndices(segmentationId);
47
47
  const promises = segmentIndices.map((index) => {
48
48
  const surface = convertLabelmapToSurface(labelmapRepresentationData, index, isVolume);
@@ -65,7 +65,7 @@ async function computeSurfaceFromLabelmapSegmentation(segmentationId, options =
65
65
  }
66
66
  async function computeSurfaceFromContourSegmentation(segmentationId, options = {}) {
67
67
  const segmentation = getSegmentation(segmentationId);
68
- const contourRepresentationData = segmentation.representationData.CONTOUR;
68
+ const contourRepresentationData = segmentation.representationData.Contour;
69
69
  const segmentIndices = options.segmentIndices || getUniqueSegmentIndices(segmentationId);
70
70
  const promises = segmentIndices.map(async (index) => {
71
71
  const surface = await convertContourToSurface(contourRepresentationData, index);
@@ -13,7 +13,7 @@ export async function updateSurfaceData(segmentationId) {
13
13
  const segmentation = getSegmentation(segmentationId);
14
14
  const indices = getUniqueSegmentIndices(segmentationId);
15
15
  if (!indices.length) {
16
- const geometryIds = segmentation.representationData.SURFACE.geometryIds;
16
+ const geometryIds = segmentation.representationData.Surface.geometryIds;
17
17
  geometryIds.forEach((geometryId) => {
18
18
  const geometry = cache.getGeometry(geometryId);
19
19
  const surface = geometry.data;
@@ -35,7 +35,7 @@ export async function updateSurfaceData(segmentationId) {
35
35
  SegmentationRepresentations.Surface) {
36
36
  return;
37
37
  }
38
- segmentation.representationData.SURFACE.geometryIds.set(segmentIndex, geometryId);
38
+ segmentation.representationData.Surface.geometryIds.set(segmentIndex, geometryId);
39
39
  return createAndCacheSurfacesFromRaw(segmentationId, [{ segmentIndex, data }], {
40
40
  segmentationRepresentationUID: segmentationRepresentation.segmentationRepresentationUID,
41
41
  });
@@ -12,7 +12,6 @@ import { setSegmentationRepresentationConfig } from './setSegmentationRepresenta
12
12
  import { getPerSegmentConfig } from './getPerSegmentConfig';
13
13
  import { setPerSegmentConfig } from './setPerSegmentConfig';
14
14
  import { getSegmentationRepresentations } from './getSegmentationRepresentations';
15
- import { addSegmentationRepresentation } from './addSegmentationRepresentation';
16
15
  import { getSegmentationRepresentationViewportStates } from './getSegmentationRepresentationViewportStates';
17
16
  import { addColorLUT } from './addColorLUT';
18
17
  import { getColorLUT } from './getColorLUT';
@@ -26,4 +25,5 @@ import { getActiveSegmentationRepresentation } from './getActiveSegmentationRepr
26
25
  import { setActiveSegmentationRepresentation } from './setActiveSegmentationRepresentation';
27
26
  import { getCurrentLabelmapImageIdForViewport } from './getCurrentLabelmapImageIdForViewport';
28
27
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
29
- export { getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getAllSegmentationRepresentations, getSegmentationRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getSegmentationRepresentationConfig, setSegmentationRepresentationConfig, getPerSegmentConfig, setPerSegmentConfig, getSegmentationRepresentations, addSegmentationRepresentation, getSegmentationRepresentationViewportStates, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getSegmentationRepresentationsForSegmentation, getSegmentationRepresentationVisibility, setSegmentationRepresentationVisibility, getViewportIdsWithSegmentation, getActiveSegmentationRepresentation, setActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, updateLabelmapSegmentationImageReferences, };
28
+ import { getStackSegmentationImageIdsForViewport } from './getStackSegmentationImageIdsForViewport';
29
+ export { getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getAllSegmentationRepresentations, getSegmentationRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getSegmentationRepresentationConfig, setSegmentationRepresentationConfig, getPerSegmentConfig, setPerSegmentConfig, getSegmentationRepresentations, getSegmentationRepresentationViewportStates, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getSegmentationRepresentationsForSegmentation, getSegmentationRepresentationVisibility, setSegmentationRepresentationVisibility, getViewportIdsWithSegmentation, getActiveSegmentationRepresentation, setActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, updateLabelmapSegmentationImageReferences, getStackSegmentationImageIdsForViewport, };
@@ -12,7 +12,6 @@ import { setSegmentationRepresentationConfig } from './setSegmentationRepresenta
12
12
  import { getPerSegmentConfig } from './getPerSegmentConfig';
13
13
  import { setPerSegmentConfig } from './setPerSegmentConfig';
14
14
  import { getSegmentationRepresentations } from './getSegmentationRepresentations';
15
- import { addSegmentationRepresentation } from './addSegmentationRepresentation';
16
15
  import { getSegmentationRepresentationViewportStates } from './getSegmentationRepresentationViewportStates';
17
16
  import { addColorLUT } from './addColorLUT';
18
17
  import { getColorLUT } from './getColorLUT';
@@ -26,4 +25,5 @@ import { getActiveSegmentationRepresentation } from './getActiveSegmentationRepr
26
25
  import { setActiveSegmentationRepresentation } from './setActiveSegmentationRepresentation';
27
26
  import { getCurrentLabelmapImageIdForViewport } from './getCurrentLabelmapImageIdForViewport';
28
27
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
29
- export { getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getAllSegmentationRepresentations, getSegmentationRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getSegmentationRepresentationConfig, setSegmentationRepresentationConfig, getPerSegmentConfig, setPerSegmentConfig, getSegmentationRepresentations, addSegmentationRepresentation, getSegmentationRepresentationViewportStates, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getSegmentationRepresentationsForSegmentation, getSegmentationRepresentationVisibility, setSegmentationRepresentationVisibility, getViewportIdsWithSegmentation, getActiveSegmentationRepresentation, setActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, updateLabelmapSegmentationImageReferences, };
28
+ import { getStackSegmentationImageIdsForViewport } from './getStackSegmentationImageIdsForViewport';
29
+ export { getSegmentation, getSegmentations, addSegmentation, removeSegmentation, getAllSegmentationRepresentations, getSegmentationRepresentation, removeRepresentation, getGlobalConfig, setGlobalConfig, getSegmentationRepresentationConfig, setSegmentationRepresentationConfig, getPerSegmentConfig, setPerSegmentConfig, getSegmentationRepresentations, getSegmentationRepresentationViewportStates, addColorLUT, getColorLUT, getNextColorLUTIndex, removeColorLUT, getSegmentationRepresentationsForSegmentation, getSegmentationRepresentationVisibility, setSegmentationRepresentationVisibility, getViewportIdsWithSegmentation, getActiveSegmentationRepresentation, setActiveSegmentationRepresentation, getCurrentLabelmapImageIdForViewport, updateLabelmapSegmentationImageReferences, getStackSegmentationImageIdsForViewport, };
@@ -1,2 +1,2 @@
1
- import type { SegmentationRepresentationConfig } from '../../types';
2
- export declare function setGlobalConfig(config: SegmentationRepresentationConfig, suppressEvents?: boolean): void;
1
+ import type { GlobalConfig } from '../../types';
2
+ export declare function setGlobalConfig(config: GlobalConfig, suppressEvents?: boolean): void;
@@ -1,2 +1,2 @@
1
- import type { SegmentRepresentationConfig } from '../../types/SegmentationStateTypes';
2
- export declare function setPerSegmentConfig(segmentationRepresentationUID: string, config: SegmentRepresentationConfig, suppressEvents?: boolean): void;
1
+ import type { RepresentationConfig } from '../../types';
2
+ export declare function setPerSegmentConfig(segmentationRepresentationUID: string, config: RepresentationConfig, suppressEvents?: boolean): void;
@@ -2,7 +2,7 @@ import { MouseBindings, ToolModes } from '../../enums';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
  import type { IToolBinding, IToolGroup, SetToolBindingsType, ToolOptionsType, ToolConfiguration } from '../../types';
4
4
  import { MouseCursor } from '../../cursors';
5
- export default class ToolGroup implements IToolGroup {
5
+ export default class ToolGroup {
6
6
  id: string;
7
7
  viewportsInfo: any[];
8
8
  toolOptions: {};
@@ -562,7 +562,7 @@ class AdvancedMagnifyViewportManager {
562
562
  const { viewportId: sourceViewportId } = evt.detail;
563
563
  this._reset(sourceViewportId);
564
564
  };
565
- element.addEventListener(csEvents.STACK_VIEWPORT_NEW_STACK, newStackHandler);
565
+ element.addEventListener(csEvents.VIEWPORT_NEW_IMAGE_SET, newStackHandler);
566
566
  const newVolumeHandler = (evt) => {
567
567
  const { viewportId: sourceViewportId } = evt.detail;
568
568
  this._reset(sourceViewportId);
@@ -575,7 +575,7 @@ class AdvancedMagnifyViewportManager {
575
575
  _removeSourceElementEventListener(element) {
576
576
  element.removeEventListener(csEvents.STACK_NEW_IMAGE, this._newStackImageCallback);
577
577
  element.removeEventListener(csEvents.VOLUME_NEW_IMAGE, this._newVolumeImageCallback);
578
- element.removeEventListener(csEvents.STACK_VIEWPORT_NEW_STACK, element.newStackHandler);
578
+ element.removeEventListener(csEvents.VIEWPORT_NEW_IMAGE_SET, element.newStackHandler);
579
579
  element.removeEventListener(csEvents.VOLUME_VIEWPORT_NEW_VOLUME, element.newVolumeHandler);
580
580
  delete element.newStackHandler;
581
581
  delete element.newVolumeHandler;
@@ -44,27 +44,30 @@ class ScaleOverlayTool extends AnnotationDisplayTool {
44
44
  if (annotations.length) {
45
45
  annotation = annotations.filter((thisAnnotation) => thisAnnotation.data.viewportId == viewport.id)[0];
46
46
  }
47
- if (!viewportsWithAnnotations.includes(viewport.id)) {
48
- const newAnnotation = {
49
- metadata: {
50
- toolName: this.getToolName(),
51
- viewPlaneNormal: [...viewPlaneNormal],
52
- viewUp: [...viewUp],
53
- FrameOfReferenceUID,
54
- referencedImageId: null,
55
- },
56
- data: {
57
- handles: {
58
- points: viewportCanvasCornersInWorld,
47
+ enabledElements.forEach((element) => {
48
+ const { viewport } = element;
49
+ if (!viewportsWithAnnotations.includes(viewport.id)) {
50
+ const newAnnotation = {
51
+ metadata: {
52
+ toolName: this.getToolName(),
53
+ viewPlaneNormal: [...viewPlaneNormal],
54
+ viewUp: [...viewUp],
55
+ FrameOfReferenceUID,
56
+ referencedImageId: null,
59
57
  },
60
- viewportId: viewport.id,
61
- },
62
- };
63
- viewportsWithAnnotations.push(viewport.id);
64
- addAnnotation(newAnnotation, viewport.element);
65
- annotation = newAnnotation;
66
- }
67
- else if (this.editData.annotation &&
58
+ data: {
59
+ handles: {
60
+ points: csUtils.getViewportImageCornersInWorld(viewport),
61
+ },
62
+ viewportId: viewport.id,
63
+ },
64
+ };
65
+ viewportsWithAnnotations.push(viewport.id);
66
+ addAnnotation(newAnnotation, viewport.element);
67
+ annotation = newAnnotation;
68
+ }
69
+ });
70
+ if (this.editData.annotation &&
68
71
  this.editData.annotation.data.viewportId == viewport.id) {
69
72
  this.editData.annotation.data.handles.points =
70
73
  viewportCanvasCornersInWorld;
@@ -10,10 +10,12 @@ declare class LivewireContourTool extends ContourSegmentationBaseTool {
10
10
  static toolName: string;
11
11
  protected scissors: LivewireScissors;
12
12
  protected scissorsNext: LivewireScissors;
13
+ _throttledCalculateCachedStats: Function;
13
14
  editData: {
14
15
  annotation: LivewireContourAnnotation;
15
16
  viewportIdsToRender: Array<string>;
16
17
  handleIndex?: number;
18
+ movingTextBox?: boolean;
17
19
  newAnnotation?: boolean;
18
20
  hasMoved?: boolean;
19
21
  lastCanvasPoint?: Types.Point2;
@@ -57,6 +59,9 @@ declare class LivewireContourTool extends ContourSegmentationBaseTool {
57
59
  annotationStyle: AnnotationStyle;
58
60
  svgDrawingHelper: SVGDrawingHelper;
59
61
  }): boolean;
62
+ private _calculateCachedStats;
63
+ private _renderStats;
64
+ triggerAnnotationModified: (annotation: LivewireContourAnnotation, enabledElement: Types.IEnabledElement, changeType?: ChangeTypes) => void;
60
65
  protected updateAnnotation(livewirePath: LivewirePath): void;
61
66
  }
62
67
  export default LivewireContourTool;
@@ -1,7 +1,7 @@
1
1
  import { vec3 } from 'gl-matrix';
2
- import { getEnabledElement, utilities as csUtils, VolumeViewport, } from '@cornerstonejs/core';
2
+ import { getEnabledElement, utilities as csUtils, VolumeViewport, utilities, triggerEvent, eventTarget, } from '@cornerstonejs/core';
3
3
  import { removeAnnotation } from '../../stateManagement/annotation/annotationState';
4
- import { drawHandles as drawHandlesSvg } from '../../drawingSvg';
4
+ import { drawHandles as drawHandlesSvg, drawLinkedTextBox as drawLinkedTextBoxSvg, } from '../../drawingSvg';
5
5
  import { state } from '../../store/state';
6
6
  import { Events, KeyboardBindings, ChangeTypes } from '../../enums';
7
7
  import { resetElementCursor } from '../../cursors/elementCursor';
@@ -15,11 +15,15 @@ import { LivewireScissors } from '../../utilities/livewire/LivewireScissors';
15
15
  import { LivewirePath } from '../../utilities/livewire/LiveWirePath';
16
16
  import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
17
17
  import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
18
+ import { getTextBoxCoordsCanvas } from '../../utilities/drawing';
19
+ import { getCalibratedLengthUnitsAndScale, throttle } from '../../utilities';
18
20
  const CLICK_CLOSE_CURVE_SQR_DIST = 10 ** 2;
19
21
  class LivewireContourTool extends ContourSegmentationBaseTool {
20
22
  constructor(toolProps = {}, defaultToolProps = {
21
23
  supportedInteractionTypes: ['Mouse', 'Touch'],
22
24
  configuration: {
25
+ getTextLines: defaultGetTextLines,
26
+ calculateStats: true,
23
27
  preventHandleOutsideImage: false,
24
28
  contourHoleAdditionModifierKey: KeyboardBindings.Shift,
25
29
  snapHandleNearby: 2,
@@ -70,6 +74,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
70
74
  this.editData = {
71
75
  annotation,
72
76
  viewportIdsToRender,
77
+ movingTextBox: false,
73
78
  };
74
79
  const enabledElement = getEnabledElement(element);
75
80
  const { renderingEngine } = enabledElement;
@@ -82,13 +87,21 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
82
87
  const { element } = eventDetail;
83
88
  const { data } = annotation;
84
89
  annotation.highlighted = true;
85
- const { points } = data.handles;
86
- const handleIndex = points.findIndex((p) => p === handle);
90
+ let movingTextBox = false;
91
+ let handleIndex;
92
+ if (handle.worldPosition) {
93
+ movingTextBox = true;
94
+ }
95
+ else {
96
+ const { points } = data.handles;
97
+ handleIndex = points.findIndex((p) => p === handle);
98
+ }
87
99
  const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
88
100
  this.editData = {
89
101
  annotation,
90
102
  viewportIdsToRender,
91
103
  handleIndex,
104
+ movingTextBox,
92
105
  };
93
106
  this._activateModify(element);
94
107
  const enabledElement = getEnabledElement(element);
@@ -215,15 +228,27 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
215
228
  this.isDrawing = true;
216
229
  const eventDetail = evt.detail;
217
230
  const { element } = eventDetail;
218
- const { annotation, viewportIdsToRender, handleIndex } = this.editData;
219
- if (handleIndex === undefined) {
220
- console.warn('No drag implemented for livewire');
231
+ const { annotation, viewportIdsToRender, handleIndex, movingTextBox } = this.editData;
232
+ const { data } = annotation;
233
+ if (movingTextBox) {
234
+ const { deltaPoints } = eventDetail;
235
+ const worldPosDelta = deltaPoints.world;
236
+ const { textBox } = data.handles;
237
+ const { worldPosition } = textBox;
238
+ worldPosition[0] += worldPosDelta[0];
239
+ worldPosition[1] += worldPosDelta[1];
240
+ worldPosition[2] += worldPosDelta[2];
241
+ textBox.hasMoved = true;
242
+ }
243
+ else if (handleIndex === undefined) {
244
+ console.warn('Drag annotation not implemented');
221
245
  }
222
246
  else {
223
247
  const { currentPoints } = eventDetail;
224
248
  const worldPos = currentPoints.world;
225
249
  this.editHandle(worldPos, element, annotation, handleIndex);
226
250
  }
251
+ this.editData.hasMoved = true;
227
252
  const enabledElement = getEnabledElement(element);
228
253
  const { renderingEngine } = enabledElement;
229
254
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
@@ -279,6 +304,104 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
279
304
  element.removeEventListener(Events.MOUSE_DOUBLE_CLICK, this._mouseDownCallback);
280
305
  element.removeEventListener(Events.TOUCH_TAP, this._mouseDownCallback);
281
306
  };
307
+ this._calculateCachedStats = (annotation, element) => {
308
+ if (!this.configuration.calculateStats) {
309
+ return;
310
+ }
311
+ const data = annotation.data;
312
+ if (!data.contour.closed) {
313
+ return;
314
+ }
315
+ const enabledElement = getEnabledElement(element);
316
+ const { viewport, renderingEngine } = enabledElement;
317
+ const { cachedStats } = data;
318
+ const { polyline: points } = data.contour;
319
+ const targetIds = Object.keys(cachedStats);
320
+ for (let i = 0; i < targetIds.length; i++) {
321
+ const targetId = targetIds[i];
322
+ const image = this.getTargetIdImage(targetId, renderingEngine);
323
+ if (!image) {
324
+ continue;
325
+ }
326
+ const { metadata } = image;
327
+ const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
328
+ const canvasPoint = canvasCoordinates[0];
329
+ const originalWorldPoint = viewport.canvasToWorld(canvasPoint);
330
+ const deltaXPoint = viewport.canvasToWorld([
331
+ canvasPoint[0] + 1,
332
+ canvasPoint[1],
333
+ ]);
334
+ const deltaYPoint = viewport.canvasToWorld([
335
+ canvasPoint[0],
336
+ canvasPoint[1] + 1,
337
+ ]);
338
+ const deltaInX = vec3.distance(originalWorldPoint, deltaXPoint);
339
+ const deltaInY = vec3.distance(originalWorldPoint, deltaYPoint);
340
+ const { imageData } = image;
341
+ const { scale, areaUnit } = getCalibratedLengthUnitsAndScale(image, () => {
342
+ const { maxX: canvasMaxX, maxY: canvasMaxY, minX: canvasMinX, minY: canvasMinY, } = math.polyline.getAABB(canvasCoordinates);
343
+ const topLeftBBWorld = viewport.canvasToWorld([
344
+ canvasMinX,
345
+ canvasMinY,
346
+ ]);
347
+ const topLeftBBIndex = utilities.transformWorldToIndex(imageData, topLeftBBWorld);
348
+ const bottomRightBBWorld = viewport.canvasToWorld([
349
+ canvasMaxX,
350
+ canvasMaxY,
351
+ ]);
352
+ const bottomRightBBIndex = utilities.transformWorldToIndex(imageData, bottomRightBBWorld);
353
+ return [topLeftBBIndex, bottomRightBBIndex];
354
+ });
355
+ let area = math.polyline.getArea(canvasCoordinates) / scale / scale;
356
+ area *= deltaInX * deltaInY;
357
+ cachedStats[targetId] = {
358
+ Modality: metadata.Modality,
359
+ area,
360
+ areaUnit: areaUnit,
361
+ };
362
+ }
363
+ this.triggerAnnotationModified(annotation, enabledElement, ChangeTypes.StatsUpdated);
364
+ return cachedStats;
365
+ };
366
+ this._renderStats = (annotation, viewport, svgDrawingHelper, textboxStyle) => {
367
+ const data = annotation.data;
368
+ const targetId = this.getTargetId(viewport);
369
+ if (!data.contour.closed || !textboxStyle.visibility) {
370
+ return;
371
+ }
372
+ const textLines = this.configuration.getTextLines(data, targetId);
373
+ if (!textLines || textLines.length === 0) {
374
+ return;
375
+ }
376
+ const canvasCoordinates = data.handles.points.map((p) => viewport.worldToCanvas(p));
377
+ if (!data.handles.textBox.hasMoved) {
378
+ const canvasTextBoxCoords = getTextBoxCoordsCanvas(canvasCoordinates);
379
+ data.handles.textBox.worldPosition =
380
+ viewport.canvasToWorld(canvasTextBoxCoords);
381
+ }
382
+ const textBoxPosition = viewport.worldToCanvas(data.handles.textBox.worldPosition);
383
+ const textBoxUID = 'textBox';
384
+ const boundingBox = drawLinkedTextBoxSvg(svgDrawingHelper, annotation.annotationUID ?? '', textBoxUID, textLines, textBoxPosition, canvasCoordinates, {}, textboxStyle);
385
+ const { x: left, y: top, width, height } = boundingBox;
386
+ data.handles.textBox.worldBoundingBox = {
387
+ topLeft: viewport.canvasToWorld([left, top]),
388
+ topRight: viewport.canvasToWorld([left + width, top]),
389
+ bottomLeft: viewport.canvasToWorld([left, top + height]),
390
+ bottomRight: viewport.canvasToWorld([left + width, top + height]),
391
+ };
392
+ };
393
+ this.triggerAnnotationModified = (annotation, enabledElement, changeType = ChangeTypes.StatsUpdated) => {
394
+ const { viewportId, renderingEngineId } = enabledElement;
395
+ const eventType = Events.ANNOTATION_MODIFIED;
396
+ const eventDetail = {
397
+ annotation,
398
+ viewportId,
399
+ renderingEngineId,
400
+ changeType,
401
+ };
402
+ triggerEvent(eventTarget, eventType, eventDetail);
403
+ };
404
+ this._throttledCalculateCachedStats = throttle(this._calculateCachedStats, 100, { trailing: true });
282
405
  }
283
406
  setupBaseEditData(worldPos, element, annotation, nextPos, contourHoleProcessingEnabled) {
284
407
  const enabledElement = getEnabledElement(element);
@@ -432,6 +555,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
432
555
  editData.currentPath = currentPath;
433
556
  annotation.invalidated = true;
434
557
  editData.hasMoved = true;
558
+ editData.closed = true;
435
559
  }
436
560
  renderAnnotation(enabledElement, svgDrawingHelper) {
437
561
  this.updateAnnotation(this.editData?.currentPath);
@@ -459,8 +583,9 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
459
583
  this._endCallback(evt, true);
460
584
  }
461
585
  renderAnnotationInstance(renderContext) {
462
- const { annotation, enabledElement, svgDrawingHelper, annotationStyle } = renderContext;
586
+ const { annotation, enabledElement, svgDrawingHelper, annotationStyle, targetId, } = renderContext;
463
587
  const { viewport } = enabledElement;
588
+ const { element } = viewport;
464
589
  const { worldToCanvas } = viewport;
465
590
  const { annotationUID, data, highlighted } = annotation;
466
591
  const { handles } = data;
@@ -478,6 +603,19 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
478
603
  });
479
604
  }
480
605
  super.renderAnnotationInstance(renderContext);
606
+ if (!data.cachedStats[targetId] ||
607
+ data.cachedStats[targetId].areaUnit == null) {
608
+ data.cachedStats[targetId] = {
609
+ Modality: null,
610
+ area: null,
611
+ areaUnit: null,
612
+ };
613
+ this._calculateCachedStats(annotation, element);
614
+ }
615
+ else if (annotation.invalidated) {
616
+ this._throttledCalculateCachedStats(annotation, element);
617
+ }
618
+ this._renderStats(annotation, viewport, svgDrawingHelper, annotationStyle.textbox);
481
619
  return true;
482
620
  }
483
621
  updateAnnotation(livewirePath) {
@@ -502,3 +640,13 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
502
640
  }
503
641
  LivewireContourTool.toolName = 'LivewireContour';
504
642
  export default LivewireContourTool;
643
+ function defaultGetTextLines(data, targetId) {
644
+ const cachedVolumeStats = data.cachedStats[targetId];
645
+ const { area, areaUnit } = cachedVolumeStats;
646
+ const textLines = [];
647
+ if (area) {
648
+ const areaLine = `Area: ${csUtils.roundNumber(area)} ${areaUnit}`;
649
+ textLines.push(areaLine);
650
+ }
651
+ return textLines;
652
+ }
@@ -2,19 +2,7 @@ import type { Types } from '@cornerstonejs/core';
2
2
  import ToolModes from '../../enums/ToolModes';
3
3
  import type StrategyCallbacks from '../../enums/StrategyCallbacks';
4
4
  import type { InteractionTypes, ToolProps, PublicToolProps } from '../../types';
5
- export interface IBaseTool {
6
- toolGroupId: string;
7
- supportedInteractionTypes: InteractionTypes[];
8
- mode: ToolModes;
9
- configuration: {
10
- preventHandleOutsideImage?: boolean;
11
- strategies?: Record<string, unknown>;
12
- defaultStrategy?: string;
13
- activeStrategy?: string;
14
- strategyOptions?: Record<string, unknown>;
15
- };
16
- }
17
- declare abstract class BaseTool implements IBaseTool {
5
+ declare abstract class BaseTool {
18
6
  static toolName: any;
19
7
  supportedInteractionTypes: InteractionTypes[];
20
8
  configuration: Record<string, any>;
@@ -128,7 +128,7 @@ class ContourSegmentationBaseTool extends ContourBaseTool {
128
128
  const activeSegRep = getActiveSegmentationRepresentation(viewportId);
129
129
  const isActive = activeSegRep.segmentationRepresentationUID ===
130
130
  segmentationRepresentationUID;
131
- const mergedConfig = Object.assign({}, globalConfig?.representations?.CONTOUR ?? {}, segmentationRepresentationConfig?.CONTOUR ?? {}, segmentConfig?.CONTOUR ?? {});
131
+ const mergedConfig = Object.assign({}, globalConfig?.representations?.Contour ?? {}, segmentationRepresentationConfig ?? {}, segmentConfig ?? {});
132
132
  let lineWidth = 1;
133
133
  let lineDash = undefined;
134
134
  let lineOpacity = 1;
@@ -15,8 +15,8 @@ function handleContourSegmentation(viewport, geometryIds, annotationUIDsMap, con
15
15
  }
16
16
  function updateContourSets(viewport, geometryIds, contourRepresentation) {
17
17
  const { segmentationRepresentationUID, config } = contourRepresentation;
18
- const baseConfig = config?.allSegments?.CONTOUR;
19
- const globalContourConfig = getGlobalConfig().representations.CONTOUR;
18
+ const baseConfig = config?.allSegments;
19
+ const globalContourConfig = getGlobalConfig().representations.Contour;
20
20
  const newContourConfig = utilities.deepMerge(globalContourConfig, baseConfig);
21
21
  const cachedConfig = getConfigCache(segmentationRepresentationUID);
22
22
  const newOutlineWithActive = newContourConfig.outlineWidthActive;
@@ -112,8 +112,8 @@ function addContourSetsToElement(viewport, geometryIds, contourRepresentation) {
112
112
  segmentSpecificMap.set(segmentIndex, segmentSpecificConfig);
113
113
  }
114
114
  });
115
- const baseConfig = contourRepresentation.config?.allSegments.CONTOUR;
116
- const globalContourConfig = getGlobalConfig().representations.CONTOUR;
115
+ const baseConfig = contourRepresentation.config?.allSegments;
116
+ const globalContourConfig = getGlobalConfig().representations.Contour;
117
117
  const newContourConfig = utilities.deepMerge(globalContourConfig, baseConfig);
118
118
  const outlineWidthActive = newContourConfig.outlineWidthActive;
119
119
  const segmentsHidden = getHiddenSegmentIndices(viewport.id, segmentationRepresentationUID);
@@ -7,7 +7,7 @@ export function validateGeometry(geometry) {
7
7
  throw new Error(`No contours found for geometryId ${geometry.id}`);
8
8
  }
9
9
  const geometryId = geometry.id;
10
- if (geometry.type !== Enums.GeometryType.CONTOUR) {
10
+ if (geometry.type !== Enums.GeometryType.Contour) {
11
11
  throw new Error(`Geometry type ${geometry.type} not supported for rendering.`);
12
12
  }
13
13
  if (!geometry.data) {
@@ -4,7 +4,7 @@ function removeContourFromElement(element, segmentationRepresentationUID, remove
4
4
  const segmentationRepresentation = getSegmentationRepresentation(segmentationRepresentationUID);
5
5
  const { segmentationId } = segmentationRepresentation;
6
6
  const segmentation = getSegmentation(segmentationId);
7
- const { annotationUIDsMap } = segmentation.representationData.CONTOUR;
7
+ const { annotationUIDsMap } = segmentation.representationData.Contour;
8
8
  annotationUIDsMap.forEach((annotationSet) => {
9
9
  annotationSet.forEach((annotationUID) => {
10
10
  removeAnnotation(annotationUID);
@@ -1,6 +1,7 @@
1
1
  import type { Types } from '@cornerstonejs/core';
2
2
  import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper } from '../../types';
3
3
  import { BaseTool } from '../base';
4
+ import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
4
5
  export type PreviewData = {
5
6
  preview: unknown;
6
7
  timer?: number;
@@ -24,11 +25,22 @@ declare class BrushTool extends BaseTool {
24
25
  referencedVolumeId: any;
25
26
  segmentsLocked: number[] | [];
26
27
  imageId?: undefined;
28
+ override?: undefined;
27
29
  } | {
28
30
  imageId: string;
29
31
  segmentsLocked: number[] | [];
30
32
  volumeId?: undefined;
31
33
  referencedVolumeId?: undefined;
34
+ override?: undefined;
35
+ } | {
36
+ imageId: string;
37
+ segmentsLocked: number[] | [];
38
+ override: {
39
+ voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
40
+ imageData: vtkImageData;
41
+ };
42
+ volumeId?: undefined;
43
+ referencedVolumeId?: undefined;
32
44
  };
33
45
  preMouseDownCallback: (evt: EventTypes.MouseDownActivateEventType) => boolean;
34
46
  mouseMoveCallback: (evt: EventTypes.InteractionEventType) => void;
@@ -48,8 +60,13 @@ declare class BrushTool extends BaseTool {
48
60
  viewUp: any;
49
61
  strategySpecificConfiguration: any;
50
62
  preview: unknown;
63
+ override: {
64
+ voxelManager: Types.IVoxelManager<number>;
65
+ imageData: vtkImageData;
66
+ };
51
67
  segmentsLocked: number[];
52
68
  imageId?: string;
69
+ imageIds?: string[];
53
70
  volumeId?: string;
54
71
  referencedVolumeId?: string;
55
72
  } | {
@@ -67,6 +84,23 @@ declare class BrushTool extends BaseTool {
67
84
  referencedVolumeId: any;
68
85
  segmentsLocked: number[] | [];
69
86
  imageId?: undefined;
87
+ override?: undefined;
88
+ } | {
89
+ points: any;
90
+ segmentIndex: number;
91
+ previewColors: any;
92
+ viewPlaneNormal: any;
93
+ toolGroupId: string;
94
+ segmentationId: string;
95
+ segmentationRepresentationUID: string;
96
+ viewUp: any;
97
+ strategySpecificConfiguration: any;
98
+ preview: unknown;
99
+ imageId: string;
100
+ segmentsLocked: number[] | [];
101
+ volumeId?: undefined;
102
+ referencedVolumeId?: undefined;
103
+ override?: undefined;
70
104
  } | {
71
105
  points: any;
72
106
  segmentIndex: number;
@@ -80,6 +114,10 @@ declare class BrushTool extends BaseTool {
80
114
  preview: unknown;
81
115
  imageId: string;
82
116
  segmentsLocked: number[] | [];
117
+ override: {
118
+ voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
119
+ imageData: vtkImageData;
120
+ };
83
121
  volumeId?: undefined;
84
122
  referencedVolumeId?: undefined;
85
123
  };