@cornerstonejs/tools 2.0.0-beta.24 → 2.0.0-beta.26

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 (55) 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/stateManagement/index.d.ts +3 -2
  5. package/dist/esm/stateManagement/index.js +2 -2
  6. package/dist/esm/stateManagement/segmentation/SegmentationStateManager.d.ts +6 -6
  7. package/dist/esm/stateManagement/segmentation/SegmentationStateManager.js +14 -14
  8. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.d.ts +8 -3
  9. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentations.js +14 -4
  10. package/dist/esm/stateManagement/segmentation/config/segmentationConfig.d.ts +8 -7
  11. package/dist/esm/stateManagement/segmentation/convertVolumeToStackSegmentation.js +1 -1
  12. package/dist/esm/stateManagement/segmentation/getGlobalConfig.d.ts +2 -2
  13. package/dist/esm/stateManagement/segmentation/getPerSegmentConfig.d.ts +2 -2
  14. package/dist/esm/stateManagement/segmentation/helpers/updateStackSegmentationState.js +5 -5
  15. package/dist/esm/stateManagement/segmentation/index.d.ts +2 -2
  16. package/dist/esm/stateManagement/segmentation/index.js +2 -2
  17. package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.d.ts +3 -0
  18. package/dist/esm/stateManagement/segmentation/{addSegmentationRepresentation.js → internalAddSegmentationRepresentation.js} +4 -3
  19. package/dist/esm/stateManagement/segmentation/polySeg/Contour/contourComputationStrategies.js +4 -4
  20. package/dist/esm/stateManagement/segmentation/polySeg/Labelmap/labelmapComputationStrategies.js +4 -4
  21. package/dist/esm/stateManagement/segmentation/polySeg/Surface/createAndCacheSurfacesFromRaw.js +1 -1
  22. package/dist/esm/stateManagement/segmentation/polySeg/Surface/surfaceComputationStrategies.js +6 -6
  23. package/dist/esm/stateManagement/segmentation/polySeg/Surface/updateSurfaceData.js +2 -2
  24. package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +1 -2
  25. package/dist/esm/stateManagement/segmentation/segmentationState.js +1 -2
  26. package/dist/esm/stateManagement/segmentation/setGlobalConfig.d.ts +2 -2
  27. package/dist/esm/stateManagement/segmentation/setPerSegmentConfig.d.ts +2 -2
  28. package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +1 -1
  29. package/dist/esm/tools/AdvancedMagnifyTool.js +2 -2
  30. package/dist/esm/tools/ScaleOverlayTool.js +23 -20
  31. package/dist/esm/tools/annotation/LivewireContourTool.d.ts +5 -0
  32. package/dist/esm/tools/annotation/LivewireContourTool.js +156 -8
  33. package/dist/esm/tools/base/BaseTool.d.ts +1 -13
  34. package/dist/esm/tools/base/ContourSegmentationBaseTool.js +1 -1
  35. package/dist/esm/tools/displayTools/Contour/contourHandler/handleContourSegmentation.js +4 -4
  36. package/dist/esm/tools/displayTools/Contour/contourHandler/utils.js +1 -1
  37. package/dist/esm/tools/displayTools/Contour/removeContourFromElement.js +1 -1
  38. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +23 -15
  39. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +12 -0
  40. package/dist/esm/types/EventTypes.d.ts +1 -2
  41. package/dist/esm/types/IBaseTool.d.ts +2 -0
  42. package/dist/esm/types/IBaseTool.js +1 -0
  43. package/dist/esm/types/IToolGroup.d.ts +3 -63
  44. package/dist/esm/types/SegmentationStateTypes.d.ts +22 -22
  45. package/dist/esm/types/index.d.ts +3 -2
  46. package/dist/esm/utilities/contourSegmentation/addContourSegmentationAnnotation.js +3 -3
  47. package/dist/esm/utilities/contourSegmentation/removeContourSegmentationAnnotation.js +1 -1
  48. package/dist/esm/utilities/segmentation/getHoveredContourSegmentationAnnotation.js +1 -1
  49. package/dist/esm/utilities/segmentation/getSegmentIndexAtLabelmapBorder.js +1 -1
  50. package/dist/esm/utilities/segmentation/getSegmentIndexAtWorldPoint.js +2 -2
  51. package/dist/esm/utilities/segmentation/getUniqueSegmentIndices.js +2 -2
  52. package/dist/umd/index.js +1 -1
  53. package/dist/umd/index.js.map +1 -1
  54. package/package.json +16 -7
  55. package/dist/esm/stateManagement/segmentation/addSegmentationRepresentation.d.ts +0 -3
@@ -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);
@@ -171,30 +171,35 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
171
171
  const canvasCorners = getCanvasCircleCorners(canvasCoordinates);
172
172
  const focalPoint = viewport.getCamera().focalPoint;
173
173
  const viewplaneNormal = viewport.getCamera().viewPlaneNormal;
174
- let startCoord = startCoordinate;
175
- let endCoord = endCoordinate;
174
+ let tempStartCoordinate = startCoordinate;
175
+ let tempEndCoordinate = endCoordinate;
176
176
  if (Array.isArray(startCoordinate)) {
177
- startCoord = this._getCoordinateForViewplaneNormal(startCoord, viewplaneNormal);
177
+ tempStartCoordinate = this._getCoordinateForViewplaneNormal(tempStartCoordinate, viewplaneNormal);
178
+ data.startCoordinate = tempStartCoordinate;
178
179
  }
179
180
  if (Array.isArray(endCoordinate)) {
180
- endCoord = this._getCoordinateForViewplaneNormal(endCoord, viewplaneNormal);
181
+ tempEndCoordinate = this._getCoordinateForViewplaneNormal(tempEndCoordinate, viewplaneNormal);
182
+ data.endCoordinate = tempEndCoordinate;
181
183
  }
182
- const roundedStartCoord = coreUtils.roundToPrecision(startCoord);
183
- const roundedEndCoord = coreUtils.roundToPrecision(endCoord);
184
- const coord = this._getCoordinateForViewplaneNormal(focalPoint, viewplaneNormal);
185
- const roundedCoord = coreUtils.roundToPrecision(coord);
186
- if (roundedCoord < Math.min(roundedStartCoord, roundedEndCoord) ||
187
- roundedCoord > Math.max(roundedStartCoord, roundedEndCoord)) {
184
+ const roundedStartCoordinate = coreUtils.roundToPrecision(data.startCoordinate);
185
+ const roundedEndCoordinate = coreUtils.roundToPrecision(data.endCoordinate);
186
+ const cameraCoordinate = this._getCoordinateForViewplaneNormal(focalPoint, viewplaneNormal);
187
+ const roundedCameraCoordinate = coreUtils.roundToPrecision(cameraCoordinate);
188
+ if (roundedCameraCoordinate <
189
+ Math.min(roundedStartCoordinate, roundedEndCoordinate) ||
190
+ roundedCameraCoordinate >
191
+ Math.max(roundedStartCoordinate, roundedEndCoordinate)) {
188
192
  continue;
189
193
  }
190
- if (annotation.invalidated) {
191
- this._throttledCalculateCachedStats(annotation, enabledElement);
192
- }
193
- const middleCoord = coreUtils.roundToPrecision((startCoord + endCoord) / 2);
194
+ const middleCoordinate = coreUtils.roundToPrecision((data.startCoordinate + data.endCoordinate) / 2);
194
195
  let isMiddleSlice = false;
195
- if (roundedCoord === middleCoord) {
196
+ if (roundedCameraCoordinate === middleCoordinate) {
196
197
  isMiddleSlice = true;
197
198
  }
199
+ data.handles.points[0][this._getIndexOfCoordinatesForViewplaneNormal(viewplaneNormal)] = middleCoordinate;
200
+ if (annotation.invalidated) {
201
+ this._throttledCalculateCachedStats(annotation, enabledElement);
202
+ }
198
203
  if (!viewport.getRenderingEngine()) {
199
204
  console.warn('Rendering Engine has been destroyed');
200
205
  return renderStatus;
@@ -420,6 +425,9 @@ class CircleROIStartEndThresholdTool extends CircleROITool {
420
425
  const targetId = this.getTargetId(viewport);
421
426
  const imageVolume = cache.getVolume(targetId.split(/volumeId:|\?/)[1]);
422
427
  this._computeProjectionPoints(annotation, imageVolume);
428
+ if (this.configuration.calculatePointsInsideVolume) {
429
+ this._computePointsInsideVolume(annotation, imageVolume, targetId, enabledElement);
430
+ }
423
431
  annotation.invalidated = false;
424
432
  triggerAnnotationModified(annotation, viewport.element);
425
433
  return cachedStats;
@@ -172,9 +172,15 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
172
172
  let endCoord = endCoordinate;
173
173
  if (Array.isArray(startCoordinate)) {
174
174
  startCoord = this._getCoordinateForViewplaneNormal(startCoord, viewplaneNormal);
175
+ data.startCoordinate = startCoord;
176
+ data.handles.points[0][this._getIndexOfCoordinatesForViewplaneNormal(viewplaneNormal)] = startCoord;
177
+ data.startCoordinate = startCoord;
178
+ data.handles.points[0][this._getIndexOfCoordinatesForViewplaneNormal(viewplaneNormal)] = startCoord;
175
179
  }
176
180
  if (Array.isArray(endCoordinate)) {
177
181
  endCoord = this._getCoordinateForViewplaneNormal(endCoord, viewplaneNormal);
182
+ data.endCoordinate = endCoord;
183
+ data.endCoordinate = endCoord;
178
184
  }
179
185
  const roundedStartCoord = csUtils.roundToPrecision(startCoord);
180
186
  const roundedEndCoord = csUtils.roundToPrecision(endCoord);
@@ -378,6 +384,12 @@ class RectangleROIStartEndThresholdTool extends RectangleROITool {
378
384
  const targetId = this.getTargetId(viewport);
379
385
  const imageVolume = cache.getVolume(targetId.split(/volumeId:|\?/)[1]);
380
386
  this._computeProjectionPoints(annotation, imageVolume);
387
+ if (this.configuration.calculatePointsInsideVolume) {
388
+ this._computePointsInsideVolume(annotation, targetId, imageVolume, enabledElement);
389
+ }
390
+ if (this.configuration.calculatePointsInsideVolume) {
391
+ this._computePointsInsideVolume(annotation, targetId, imageVolume, enabledElement);
392
+ }
381
393
  annotation.invalidated = false;
382
394
  triggerAnnotationModified(annotation, viewport.element);
383
395
  return cachedStats;
@@ -5,9 +5,8 @@ import type ITouchPoints from './ITouchPoints';
5
5
  import type IDistance from './IDistance';
6
6
  import type { SetToolBindingsType } from './ISetToolModeOptions';
7
7
  import type { Swipe } from '../enums/Touch';
8
- import type { ToolModes } from '../enums';
8
+ import type { ToolModes, ChangeTypes } from '../enums';
9
9
  import type { InterpolationROIAnnotation } from './ToolSpecificAnnotationTypes';
10
- import type { ChangeTypes } from '../enums';
11
10
  type NormalizedInteractionEventDetail = {
12
11
  eventName: string;
13
12
  renderingEngineId: string;
@@ -0,0 +1,2 @@
1
+ import type BaseTool from '../tools/base/BaseTool';
2
+ export type IBaseTool = BaseTool;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,63 +1,3 @@
1
- import type { Types } from '@cornerstonejs/core';
2
- import type { IToolBinding, SetToolBindingsType, ToolOptionsType } from './ISetToolModeOptions';
3
- import type { MouseBindings } from '../enums';
4
- import type { ToolConfiguration } from '../types';
5
- export default interface IToolGroup {
6
- _toolInstances: Record<string, unknown>;
7
- id: string;
8
- viewportsInfo: Array<Types.IViewportId>;
9
- toolOptions: Record<string, unknown>;
10
- getViewportIds: () => string[];
11
- getViewportsInfo: () => Array<Types.IViewportId>;
12
- getToolInstance: {
13
- (toolName: string): unknown;
14
- };
15
- hasTool(toolName: string): boolean;
16
- addTool: {
17
- (toolName: string, toolConfiguration?: ToolConfiguration): void;
18
- };
19
- addToolInstance: {
20
- (toolName: string, parentClassName: string, configuration?: unknown): void;
21
- };
22
- addViewport: {
23
- (viewportId: string, renderingEngineId?: string): void;
24
- };
25
- removeViewports: {
26
- (renderingEngineId: string, viewportId?: string): void;
27
- };
28
- setToolActive: {
29
- (toolName: string, toolBindingsOption?: SetToolBindingsType): void;
30
- };
31
- setToolPassive: {
32
- (toolName: string, options?: {
33
- removeAllBindings?: boolean | IToolBinding[];
34
- }): void;
35
- };
36
- setToolEnabled: {
37
- (toolName: string): void;
38
- };
39
- setToolDisabled: {
40
- (toolName: string): void;
41
- };
42
- getToolOptions: {
43
- (toolName: string): ToolOptionsType;
44
- };
45
- getActivePrimaryMouseButtonTool: {
46
- (): undefined | string;
47
- };
48
- setViewportsCursorByToolName: {
49
- (toolName: string, strategyName?: string): void;
50
- };
51
- setToolConfiguration: {
52
- (toolName: string, configuration: ToolConfiguration, overwrite?: boolean): void;
53
- };
54
- getToolConfiguration: {
55
- (toolName: string, configurationPath?: string): unknown;
56
- };
57
- getDefaultMousePrimary: {
58
- (): MouseBindings;
59
- };
60
- clone: {
61
- (newToolGroupId: string, fnToolFilter: (toolName: string) => boolean): IToolGroup;
62
- };
63
- }
1
+ import type ToolGroup from '../store/ToolGroupManager/ToolGroup';
2
+ type IToolGroup = ToolGroup;
3
+ export type { IToolGroup as default };