@cornerstonejs/tools 5.5.1 → 5.6.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 (35) hide show
  1. package/dist/esm/index.d.ts +2 -2
  2. package/dist/esm/index.js +2 -2
  3. package/dist/esm/tools/annotation/BidirectionalTool.js +0 -1
  4. package/dist/esm/tools/annotation/CircleROITool.d.ts +4 -1
  5. package/dist/esm/tools/annotation/CircleROITool.js +34 -34
  6. package/dist/esm/tools/annotation/DragProbeTool.js +1 -1
  7. package/dist/esm/tools/annotation/RectangleROITool.d.ts +2 -2
  8. package/dist/esm/tools/annotation/RectangleROITool.js +23 -49
  9. package/dist/esm/tools/base/AnnotationTool.js +6 -4
  10. package/dist/esm/tools/base/BaseTool.d.ts +15 -4
  11. package/dist/esm/tools/base/BaseTool.js +127 -6
  12. package/dist/esm/tools/base/index.d.ts +3 -1
  13. package/dist/esm/tools/base/index.js +3 -1
  14. package/dist/esm/tools/base/measurementTargetFilters.d.ts +19 -0
  15. package/dist/esm/tools/base/measurementTargetFilters.js +38 -0
  16. package/dist/esm/tools/index.d.ts +2 -2
  17. package/dist/esm/tools/index.js +2 -2
  18. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.d.ts +2 -40
  19. package/dist/esm/tools/segmentation/CircleROIStartEndThresholdTool.js +1 -2
  20. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.d.ts +0 -1
  21. package/dist/esm/tools/segmentation/RectangleROIStartEndThresholdTool.js +0 -1
  22. package/dist/esm/types/AnnotationTypes.d.ts +34 -1
  23. package/dist/esm/types/IBaseTool.d.ts +22 -0
  24. package/dist/esm/types/ToolSpecificAnnotationTypes.d.ts +26 -53
  25. package/dist/esm/types/index.d.ts +2 -2
  26. package/dist/esm/utilities/defaultGetTextLines.d.ts +9 -0
  27. package/dist/esm/utilities/defaultGetTextLines.js +53 -0
  28. package/dist/esm/utilities/getEllipseWorldCoordinates.d.ts +2 -2
  29. package/dist/esm/utilities/getEllipseWorldCoordinates.js +2 -2
  30. package/dist/esm/utilities/index.d.ts +1 -0
  31. package/dist/esm/utilities/index.js +1 -0
  32. package/dist/esm/utilities/planar/filterAnnotationsWithinSlice.js +1 -1
  33. package/dist/esm/version.d.ts +1 -1
  34. package/dist/esm/version.js +1 -1
  35. package/package.json +4 -4
@@ -12,7 +12,7 @@ import * as Types from './types/index.js';
12
12
  import * as annotation from './stateManagement/annotation/index.js';
13
13
  import * as segmentation from './stateManagement/segmentation/index.js';
14
14
  import * as splines from './tools/annotation/splines/index.js';
15
- import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, SegmentBidirectionalTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OrientationControllerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, SegmentLabelTool, LabelMapEditWithContourTool } from './tools/index.js';
15
+ import { BaseTool, AnnotationTool, AnnotationDisplayTool, measurementTargetFilters, PanTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, SegmentBidirectionalTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OrientationControllerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, SegmentLabelTool, LabelMapEditWithContourTool } from './tools/index.js';
16
16
  import VideoRedactionTool from './tools/annotation/VideoRedactionTool.js';
17
17
  import * as Enums from './enums/index.js';
18
- export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, SegmentBidirectionalTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, OrientationControllerTool, SegmentSelectTool, SegmentLabelTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, store, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, LabelMapEditWithContourTool, splines, version, };
18
+ export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, measurementTargetFilters, PanTool, SegmentBidirectionalTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, OrientationControllerTool, SegmentSelectTool, SegmentLabelTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, store, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, LabelMapEditWithContourTool, splines, version, };
package/dist/esm/index.js CHANGED
@@ -12,7 +12,7 @@ import * as Types from './types/index.js';
12
12
  import * as annotation from './stateManagement/annotation/index.js';
13
13
  import * as segmentation from './stateManagement/segmentation/index.js';
14
14
  import * as splines from './tools/annotation/splines/index.js';
15
- import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, SegmentBidirectionalTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OrientationControllerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, SegmentLabelTool, LabelMapEditWithContourTool, } from './tools/index.js';
15
+ import { BaseTool, AnnotationTool, AnnotationDisplayTool, measurementTargetFilters, PanTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, SegmentBidirectionalTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OrientationControllerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, SegmentLabelTool, LabelMapEditWithContourTool, } from './tools/index.js';
16
16
  import VideoRedactionTool from './tools/annotation/VideoRedactionTool.js';
17
17
  import * as Enums from './enums/index.js';
18
- export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, SegmentBidirectionalTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, OrientationControllerTool, SegmentSelectTool, SegmentLabelTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, store, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, LabelMapEditWithContourTool, splines, version, };
18
+ export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, measurementTargetFilters, PanTool, SegmentBidirectionalTool, TrackballRotateTool, VolumeCroppingTool, VolumeCroppingControlTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LabelTool, LengthTool, HeightTool, CrosshairsTool, WorldCrosshairTool, SliceIntersectionTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, UltrasoundPleuraBLineTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, OrientationControllerTool, SegmentSelectTool, SegmentLabelTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, store, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, RegionSegmentPlusTool, RegionSegmentTool, ClickSegmentTool, WholeBodySegmentTool, LabelmapBaseTool, LabelMapEditWithContourTool, splines, version, };
@@ -16,7 +16,6 @@ import * as lineSegment from '../../utilities/math/line/index.js';
16
16
  import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor.js';
17
17
  import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds.js';
18
18
  import { getStyleProperty } from '../../stateManagement/annotation/config/helpers.js';
19
- const { transformWorldToIndex } = csUtils;
20
19
  class BidirectionalTool extends AnnotationTool {
21
20
  constructor(toolProps = {}, defaultToolProps = {
22
21
  supportedInteractionTypes: ['Mouse', 'Touch'],
@@ -2,6 +2,7 @@ import { AnnotationTool } from '../base/index.js';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
  import type { EventTypes, ToolHandle, PublicToolProps, ToolProps, SVGDrawingHelper, Annotation } from '../../types/index.js';
4
4
  import type { CircleROIAnnotation } from '../../types/ToolSpecificAnnotationTypes.js';
5
+ import { type MetricDefinition } from '../../utilities/defaultGetTextLines.js';
5
6
  declare class CircleROITool extends AnnotationTool {
6
7
  static toolName: string;
7
8
  _throttledCalculateCachedStats: Function;
@@ -16,7 +17,7 @@ declare class CircleROITool extends AnnotationTool {
16
17
  isDrawing: boolean;
17
18
  isHandleOutsideImage: boolean;
18
19
  constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
19
- addNewAnnotation: (evt: EventTypes.InteractionEventType) => CircleROIAnnotation;
20
+ addNewAnnotation: (evt: EventTypes.InteractionEventType) => Annotation;
20
21
  isPointNearTool: (element: HTMLDivElement, annotation: CircleROIAnnotation, canvasCoords: Types.Point2, proximity: number) => boolean;
21
22
  _pointInEllipseCanvas(ellipse: any, location: Types.Point2): boolean;
22
23
  toolSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: CircleROIAnnotation) => void;
@@ -39,5 +40,7 @@ declare class CircleROITool extends AnnotationTool {
39
40
  viewplaneNormal?: Types.Point3;
40
41
  viewUp?: Types.Point3;
41
42
  }) => CircleROIAnnotation;
43
+ static readonly CIRCLE_ROI_METRICS: MetricDefinition[];
44
+ static getTextLines: (data: any, targetId: string | string[]) => string[];
42
45
  }
43
46
  export default CircleROITool;
@@ -1,5 +1,5 @@
1
1
  var _a;
2
- import { AnnotationTool, BaseTool } from '../base/index.js';
2
+ import { AnnotationTool, BaseTool, measurementTargetFilters } from '../base/index.js';
3
3
  import { vec2, vec3 } from 'gl-matrix';
4
4
  import { getEnabledElement, VolumeViewport, utilities as csUtils, getEnabledElementByViewportId, EPSILON, } from '@cornerstonejs/core';
5
5
  import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits.js';
@@ -21,6 +21,7 @@ import { getCanvasCircleCorners, getCanvasCircleRadius, } from '../../utilities/
21
21
  import { getCanvasEllipseCorners, pointInEllipse, } from '../../utilities/math/ellipse/index.js';
22
22
  import { BasicStatsCalculator } from '../../utilities/math/basic/index.js';
23
23
  import { getStyleProperty } from '../../stateManagement/annotation/config/helpers.js';
24
+ import { createGetTextLines, } from '../../utilities/defaultGetTextLines.js';
24
25
  import getEllipseWorldCoordinates from '../../utilities/getEllipseWorldCoordinates.js';
25
26
  const { transformWorldToIndex } = csUtils;
26
27
  class CircleROITool extends AnnotationTool {
@@ -35,6 +36,7 @@ class CircleROITool extends AnnotationTool {
35
36
  getTextLines: defaultGetTextLines,
36
37
  statsCalculator: BasicStatsCalculator,
37
38
  simplified: true,
39
+ targetsFilter: measurementTargetFilters.allPixelData,
38
40
  },
39
41
  }) {
40
42
  super(toolProps, defaultToolProps);
@@ -360,7 +362,7 @@ class CircleROITool extends AnnotationTool {
360
362
  const { annotationUID, data } = annotation;
361
363
  const { handles } = data;
362
364
  const { points, activeHandleIndex } = handles;
363
- const targetId = this.getTargetId(viewport, data);
365
+ const targetIds = this.getMeasurementTargets(viewport, data);
364
366
  styleSpecifier.annotationUID = annotationUID;
365
367
  const { color, lineWidth, lineDash } = this.getAnnotationStyle({
366
368
  annotation,
@@ -374,19 +376,7 @@ class CircleROITool extends AnnotationTool {
374
376
  canvasCoordinates[1],
375
377
  ]);
376
378
  const { centerPointRadius } = this.configuration;
377
- if (!data.cachedStats[targetId] ||
378
- data.cachedStats[targetId].areaUnit == null) {
379
- data.cachedStats[targetId] = {
380
- Modality: null,
381
- area: null,
382
- max: null,
383
- mean: null,
384
- stdDev: null,
385
- areaUnit: null,
386
- radius: null,
387
- radiusUnit: null,
388
- perimeter: null,
389
- };
379
+ if (this.ensureCachedStatsTargets(data, targetIds, (stats) => stats.areaUnit == null)) {
390
380
  this._calculateCachedStats(annotation, viewport, renderingEngine, enabledElement);
391
381
  }
392
382
  else if (annotation.invalidated) {
@@ -456,7 +446,7 @@ class CircleROITool extends AnnotationTool {
456
446
  }
457
447
  renderStatus = true;
458
448
  if (this.configuration.calculateStats) {
459
- const textLines = this.configuration.getTextLines(data, targetId);
449
+ const textLines = this.configuration.getTextLines(data, targetIds);
460
450
  if (!textLines || textLines.length === 0) {
461
451
  continue;
462
452
  }
@@ -491,13 +481,19 @@ class CircleROITool extends AnnotationTool {
491
481
  const topLeftWorld = viewport.canvasToWorld(topLeftCanvas);
492
482
  const bottomRightWorld = viewport.canvasToWorld(bottomRightCanvas);
493
483
  const { cachedStats } = data;
484
+ if (wasInvalidated) {
485
+ const currentTargets = this.getMeasurementTargets(viewport, data);
486
+ for (const key of Object.keys(cachedStats)) {
487
+ delete cachedStats[key];
488
+ }
489
+ this.ensureCachedStatsTargets(data, currentTargets);
490
+ }
494
491
  const targetIds = Object.keys(cachedStats);
492
+ let isHandleOutsideAnyTarget = false;
495
493
  for (let i = 0; i < targetIds.length; i++) {
496
494
  const targetId = targetIds[i];
497
495
  const image = this.getTargetImageData(targetId);
498
496
  if (!image) {
499
- console.warn('image not found for stats:', targetId);
500
- delete cachedStats[targetId];
501
497
  continue;
502
498
  }
503
499
  const { dimensions, imageData, metadata, voxelManager } = image;
@@ -539,11 +535,12 @@ class CircleROITool extends AnnotationTool {
539
535
  };
540
536
  const pos1Index = transformWorldToIndex(imageData, topLeftWorld);
541
537
  const pos2Index = transformWorldToIndex(imageData, bottomRightWorld);
542
- this.isHandleOutsideImage = !BaseTool.isInsideVolume(dimensions, [
538
+ const isHandleOutsideTarget = !BaseTool.isInsideVolume(dimensions, [
543
539
  pos1Index,
544
540
  pos2Index,
545
541
  ]);
546
- if (!this.isHandleOutsideImage) {
542
+ isHandleOutsideAnyTarget ||= isHandleOutsideTarget;
543
+ if (!isHandleOutsideTarget) {
547
544
  const iMin = Math.min(pos1Index[0], pos2Index[0]);
548
545
  const iMax = Math.max(pos1Index[0], pos2Index[0]);
549
546
  const jMin = Math.min(pos1Index[1], pos2Index[1]);
@@ -593,6 +590,7 @@ class CircleROITool extends AnnotationTool {
593
590
  };
594
591
  }
595
592
  }
593
+ this.isHandleOutsideImage = isHandleOutsideAnyTarget;
596
594
  annotation.invalidated = false;
597
595
  if (wasInvalidated) {
598
596
  triggerAnnotationModified(annotation, element, ChangeTypes.StatsUpdated);
@@ -660,10 +658,20 @@ CircleROITool.hydrate = (viewportId, points, options) => {
660
658
  addAnnotation(annotation, viewport.element);
661
659
  triggerAnnotationRenderForViewportIds([viewport.id]);
662
660
  };
663
- function defaultGetTextLines(data, targetId) {
664
- const cachedVolumeStats = data.cachedStats[targetId];
665
- const { radius, radiusUnit, area, mean, stdDev, max, min, isEmptyArea, areaUnit, modalityUnit, } = cachedVolumeStats;
661
+ CircleROITool.CIRCLE_ROI_METRICS = [
662
+ { name: 'Mean', attribute: 'mean', unitAttribute: 'modalityUnit' },
663
+ { name: 'Max', attribute: 'max', unitAttribute: 'modalityUnit' },
664
+ { name: 'Min', attribute: 'min', unitAttribute: 'modalityUnit' },
665
+ { name: 'Std Dev', attribute: 'stdDev', unitAttribute: 'modalityUnit' },
666
+ ];
667
+ CircleROITool.getTextLines = createGetTextLines(_a.CIRCLE_ROI_METRICS);
668
+ function defaultGetTextLines(data, targetIds) {
669
+ const cachedVolumeStats = data.cachedStats[targetIds[0]];
666
670
  const textLines = [];
671
+ if (!cachedVolumeStats) {
672
+ return textLines;
673
+ }
674
+ const { radius, radiusUnit, area, isEmptyArea, areaUnit } = cachedVolumeStats;
667
675
  if (csUtils.isNumber(radius)) {
668
676
  const radiusLine = isEmptyArea
669
677
  ? `Radius: Oblique not supported`
@@ -676,17 +684,9 @@ function defaultGetTextLines(data, targetId) {
676
684
  : `Area: ${csUtils.roundNumber(area)} ${areaUnit}`;
677
685
  textLines.push(areaLine);
678
686
  }
679
- if (csUtils.isNumber(mean)) {
680
- textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`);
681
- }
682
- if (csUtils.isNumber(max)) {
683
- textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`);
684
- }
685
- if (csUtils.isNumber(min)) {
686
- textLines.push(`Min: ${csUtils.roundNumber(min)} ${modalityUnit}`);
687
- }
688
- if (csUtils.isNumber(stdDev)) {
689
- textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`);
687
+ const standardTextLines = CircleROITool.getTextLines(data, targetIds);
688
+ if (standardTextLines) {
689
+ textLines.push(...standardTextLines);
690
690
  }
691
691
  return textLines;
692
692
  }
@@ -20,7 +20,7 @@ class DragProbeTool extends ProbeTool {
20
20
  const { currentPoints, element } = eventDetail;
21
21
  const worldPos = currentPoints.world;
22
22
  const enabledElement = getEnabledElement(element);
23
- const { viewport, renderingEngine } = enabledElement;
23
+ const { viewport } = enabledElement;
24
24
  this.isDrawing = true;
25
25
  const camera = getViewportICamera(viewport);
26
26
  const { viewPlaneNormal, viewUp } = camera;
@@ -16,7 +16,7 @@ declare class RectangleROITool extends AnnotationTool {
16
16
  isDrawing: boolean;
17
17
  isHandleOutsideImage: boolean;
18
18
  constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
19
- addNewAnnotation: (evt: EventTypes.InteractionEventType) => RectangleROIAnnotation;
19
+ addNewAnnotation: (evt: EventTypes.InteractionEventType) => Annotation;
20
20
  isPointNearTool: (element: HTMLDivElement, annotation: RectangleROIAnnotation, canvasCoords: Types.Point2, proximity: number) => boolean;
21
21
  toolSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: RectangleROIAnnotation) => void;
22
22
  handleSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: RectangleROIAnnotation, handle: ToolHandle) => void;
@@ -34,7 +34,7 @@ declare class RectangleROITool extends AnnotationTool {
34
34
  width: number;
35
35
  height: number;
36
36
  };
37
- _calculateCachedStats: (annotation: any, viewPlaneNormal: any, viewUp: any, renderingEngine: any, enabledElement: any) => any;
37
+ _calculateCachedStats: (annotation: any, viewPlaneNormal: any, viewUp: any, enabledElement: any) => any;
38
38
  _isInsideVolume: (index1: any, index2: any, dimensions: any) => boolean;
39
39
  static hydrate: (viewportId: string, points: Types.Point3[], options?: {
40
40
  annotationUID?: string;
@@ -1,5 +1,5 @@
1
1
  var _a;
2
- import { AnnotationTool } from '../base/index.js';
2
+ import { AnnotationTool, measurementTargetFilters } from '../base/index.js';
3
3
  import { getEnabledElement, VolumeViewport, utilities as csUtils, getEnabledElementByViewportId, } from '@cornerstonejs/core';
4
4
  import { vec3 } from 'gl-matrix';
5
5
  import { getCalibratedLengthUnitsAndScale } from '../../utilities/getCalibratedUnits.js';
@@ -21,6 +21,7 @@ import { viewportSupportsImageSlices } from '../../utilities/viewportCapabilitie
21
21
  import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled.js';
22
22
  import { BasicStatsCalculator } from '../../utilities/math/basic/index.js';
23
23
  import { getStyleProperty } from '../../stateManagement/annotation/config/helpers.js';
24
+ import { defaultAreaGetTextLines } from '../../utilities/defaultGetTextLines.js';
24
25
  const { transformWorldToIndex, transformWorldToIndexContinuous } = csUtils;
25
26
  class RectangleROITool extends AnnotationTool {
26
27
  constructor(toolProps = {}, defaultToolProps = {
@@ -30,8 +31,9 @@ class RectangleROITool extends AnnotationTool {
30
31
  shadow: true,
31
32
  preventHandleOutsideImage: false,
32
33
  calculateStats: true,
33
- getTextLines: defaultGetTextLines,
34
+ getTextLines: defaultAreaGetTextLines,
34
35
  statsCalculator: BasicStatsCalculator,
36
+ targetsFilter: measurementTargetFilters.allPixelData,
35
37
  },
36
38
  }) {
37
39
  super(toolProps, defaultToolProps);
@@ -112,8 +114,6 @@ class RectangleROITool extends AnnotationTool {
112
114
  };
113
115
  this._activateModify(element);
114
116
  hideElementCursor(element);
115
- const enabledElement = getEnabledElement(element);
116
- const { renderingEngine } = enabledElement;
117
117
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
118
118
  evt.preventDefault();
119
119
  };
@@ -139,8 +139,6 @@ class RectangleROITool extends AnnotationTool {
139
139
  };
140
140
  this._activateModify(element);
141
141
  hideElementCursor(element);
142
- const enabledElement = getEnabledElement(element);
143
- const { renderingEngine } = enabledElement;
144
142
  triggerAnnotationRenderForViewportIds(viewportIdsToRender);
145
143
  evt.preventDefault();
146
144
  };
@@ -329,27 +327,18 @@ class RectangleROITool extends AnnotationTool {
329
327
  const { annotationUID, data } = annotation;
330
328
  const { points, activeHandleIndex } = data.handles;
331
329
  const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
332
- const targetId = this.getTargetId(viewport, data);
330
+ const targetIds = this.getMeasurementTargets(viewport, data);
333
331
  styleSpecifier.annotationUID = annotationUID;
334
332
  const { color, lineWidth, lineDash } = this.getAnnotationStyle({
335
333
  annotation,
336
334
  styleSpecifier,
337
335
  });
338
336
  const { viewPlaneNormal, viewUp } = getViewportICamera(viewport);
339
- if (!data.cachedStats[targetId] ||
340
- data.cachedStats[targetId].areaUnit == null) {
341
- data.cachedStats[targetId] = {
342
- Modality: null,
343
- area: null,
344
- max: null,
345
- mean: null,
346
- stdDev: null,
347
- areaUnit: null,
348
- };
349
- this._calculateCachedStats(annotation, viewPlaneNormal, viewUp, renderingEngine, enabledElement);
337
+ if (this.ensureCachedStatsTargets(data, targetIds, (stats) => stats.areaUnit == null)) {
338
+ this._calculateCachedStats(annotation, viewPlaneNormal, viewUp, enabledElement);
350
339
  }
351
340
  else if (annotation.invalidated) {
352
- this._throttledCalculateCachedStats(annotation, viewPlaneNormal, viewUp, renderingEngine, enabledElement);
341
+ this._throttledCalculateCachedStats(annotation, viewPlaneNormal, viewUp, enabledElement);
353
342
  if (viewport instanceof VolumeViewport) {
354
343
  const { referencedImageId } = annotation.metadata;
355
344
  for (const targetId in data.cachedStats) {
@@ -399,8 +388,8 @@ class RectangleROITool extends AnnotationTool {
399
388
  lineWidth,
400
389
  }, dataId);
401
390
  renderStatus = true;
402
- const textLines = this.configuration.getTextLines(data, targetId);
403
- if (!textLines || textLines.length === 0) {
391
+ const textLines = this.configuration.getTextLines(data, targetIds);
392
+ if (!textLines?.length) {
404
393
  continue;
405
394
  }
406
395
  if (!this.renderLinkedTextBoxAnnotation({
@@ -425,7 +414,7 @@ class RectangleROITool extends AnnotationTool {
425
414
  height: Math.abs(point0[1] - point1[1]),
426
415
  };
427
416
  };
428
- this._calculateCachedStats = (annotation, viewPlaneNormal, viewUp, renderingEngine, enabledElement) => {
417
+ this._calculateCachedStats = (annotation, viewPlaneNormal, viewUp, enabledElement) => {
429
418
  if (!this.configuration.calculateStats) {
430
419
  return;
431
420
  }
@@ -434,7 +423,15 @@ class RectangleROITool extends AnnotationTool {
434
423
  const { element } = viewport;
435
424
  const worldHandles = data.handles.points;
436
425
  const { cachedStats } = data;
426
+ if (annotation.invalidated) {
427
+ const currentTargets = this.getMeasurementTargets(viewport, data);
428
+ for (const key of Object.keys(cachedStats)) {
429
+ delete cachedStats[key];
430
+ }
431
+ this.ensureCachedStatsTargets(data, currentTargets);
432
+ }
437
433
  const targetIds = Object.keys(cachedStats);
434
+ let isHandleOutsideAnyTarget = false;
438
435
  for (let i = 0; i < targetIds.length; i++) {
439
436
  const targetId = targetIds[i];
440
437
  const image = this.getTargetImageData(targetId);
@@ -445,8 +442,9 @@ class RectangleROITool extends AnnotationTool {
445
442
  const continuousIndexHandles = worldHandles.map((worldHandle) => transformWorldToIndexContinuous(imageData, worldHandle));
446
443
  const pos1Index = transformWorldToIndex(imageData, worldHandles[0]);
447
444
  const pos2Index = transformWorldToIndex(imageData, worldHandles[3]);
448
- if (this._isInsideVolume(pos1Index, pos2Index, dimensions)) {
449
- this.isHandleOutsideImage = false;
445
+ const isHandleOutsideTarget = !this._isInsideVolume(pos1Index, pos2Index, dimensions);
446
+ isHandleOutsideAnyTarget ||= isHandleOutsideTarget;
447
+ if (!isHandleOutsideTarget) {
450
448
  const iMin = Math.min(pos1Index[0], pos2Index[0]);
451
449
  const iMax = Math.max(pos1Index[0], pos2Index[0]);
452
450
  const jMin = Math.min(pos1Index[1], pos2Index[1]);
@@ -498,12 +496,12 @@ class RectangleROITool extends AnnotationTool {
498
496
  };
499
497
  }
500
498
  else {
501
- this.isHandleOutsideImage = true;
502
499
  cachedStats[targetId] = {
503
500
  Modality: metadata.Modality,
504
501
  };
505
502
  }
506
503
  }
504
+ this.isHandleOutsideImage = isHandleOutsideAnyTarget;
507
505
  const invalidated = annotation.invalidated;
508
506
  annotation.invalidated = false;
509
507
  if (invalidated) {
@@ -553,28 +551,4 @@ RectangleROITool.hydrate = (viewportId, points, options) => {
553
551
  addAnnotation(annotation, viewport.element);
554
552
  triggerAnnotationRenderForViewportIds([viewport.id]);
555
553
  };
556
- function defaultGetTextLines(data, targetId) {
557
- const cachedVolumeStats = data.cachedStats[targetId];
558
- const { area, mean, max, stdDev, areaUnit, modalityUnit, min } = cachedVolumeStats;
559
- if (mean === undefined || mean === null) {
560
- return;
561
- }
562
- const textLines = [];
563
- if (csUtils.isNumber(area)) {
564
- textLines.push(`Area: ${csUtils.roundNumber(area)} ${areaUnit}`);
565
- }
566
- if (csUtils.isNumber(mean)) {
567
- textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`);
568
- }
569
- if (csUtils.isNumber(max)) {
570
- textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`);
571
- }
572
- if (csUtils.isNumber(min)) {
573
- textLines.push(`Min: ${csUtils.roundNumber(min)} ${modalityUnit}`);
574
- }
575
- if (csUtils.isNumber(stdDev)) {
576
- textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`);
577
- }
578
- return textLines;
579
- }
580
554
  export default RectangleROITool;
@@ -17,7 +17,9 @@ import getViewportICamera from '../../utilities/getViewportICamera.js';
17
17
  const { DefaultHistoryMemo } = csUtils.HistoryMemo;
18
18
  class AnnotationTool extends AnnotationDisplayTool {
19
19
  static createAnnotationForViewport(viewport, ...annotationBaseData) {
20
- return this.createAnnotation({ metadata: viewport.getViewReference() }, ...annotationBaseData);
20
+ const metadata = viewport.getViewReference();
21
+ delete metadata.volumeId;
22
+ return this.createAnnotation({ metadata }, ...annotationBaseData);
21
23
  }
22
24
  static createAndAddAnnotation(viewport, ...annotationBaseData) {
23
25
  const annotation = this.createAnnotationForViewport(viewport, ...annotationBaseData);
@@ -184,9 +186,9 @@ class AnnotationTool extends AnnotationDisplayTool {
184
186
  return true;
185
187
  }
186
188
  static isSuvScaled(viewport, targetId, imageId) {
187
- if (viewport instanceof BaseVolumeViewport) {
188
- const volumeId = csUtils.getVolumeId(targetId);
189
- const volume = cache.getVolume(volumeId);
189
+ const volumeId = csUtils.getVolumeId(targetId);
190
+ const volume = cache.getVolume(volumeId);
191
+ if (volume) {
190
192
  return volume?.scaling?.PT !== undefined;
191
193
  }
192
194
  const scalingModule = imageId && metaData.get('scalingModule', imageId);
@@ -2,7 +2,7 @@ import { utilities as csUtils } from '@cornerstonejs/core';
2
2
  import type { Types } from '@cornerstonejs/core';
3
3
  import ToolModes from '../../enums/ToolModes.js';
4
4
  import type StrategyCallbacks from '../../enums/StrategyCallbacks.js';
5
- import type { InteractionTypes, ToolProps, PublicToolProps, ToolConfiguration } from '../../types/index.js';
5
+ import type { InteractionTypes, ToolProps, PublicToolProps, ToolConfiguration, AnnotationData, MeasurementTargetCandidate } from '../../types/index.js';
6
6
  declare abstract class BaseTool {
7
7
  static toolName: any;
8
8
  static activeCursorTool: any;
@@ -33,9 +33,20 @@ declare abstract class BaseTool {
33
33
  setConfiguration(newConfiguration: Record<string, any>): void;
34
34
  setActiveStrategy(strategyName: string): void;
35
35
  protected getTargetImageData(targetId: string): Types.IImageData | Types.CPUIImageData;
36
- protected getTargetId(viewport: Types.IViewport, data?: unknown & {
37
- cachedStats?: Record<string, unknown>;
38
- }): string | undefined;
36
+ protected getTargetId(viewport: Types.IViewport, data?: AnnotationData): string | undefined;
37
+ protected getMeasurementTargets(viewport: Types.IViewport, data?: AnnotationData): string[];
38
+ protected getMeasurementTargetCandidates(viewport: Types.IViewport, data?: AnnotationData): MeasurementTargetCandidate[];
39
+ protected static getViewportDisplaySets(viewport: Types.IViewport): Array<{
40
+ displaySetUID: string;
41
+ displaySet?: unknown;
42
+ instance?: Record<string, unknown>;
43
+ imageIds?: string[];
44
+ volumeId?: string;
45
+ modality?: string;
46
+ }>;
47
+ protected static getExemplarInstance(imageIds?: string[]): Record<string, unknown> | undefined;
48
+ protected static findCachedStatsTargetId(data: AnnotationData | undefined, referencedId: string): string | undefined;
49
+ protected ensureCachedStatsTargets(data: AnnotationData, targetIds: string[], needsUpdate?: (stats: any) => boolean): boolean;
39
50
  undo(): void;
40
51
  redo(): void;
41
52
  static createZoomPanMemo(viewport: any): {
@@ -1,5 +1,6 @@
1
- import { utilities as csUtils, viewportHasPan, viewportHasZoom, } from '@cornerstonejs/core';
1
+ import { cache, metaData, utilities as csUtils, viewportHasPan, viewportHasZoom, } from '@cornerstonejs/core';
2
2
  import ToolModes from '../../enums/ToolModes.js';
3
+ import measurementTargetFilters from './measurementTargetFilters.js';
3
4
  const { DefaultHistoryMemo } = csUtils.HistoryMemo;
4
5
  class BaseTool {
5
6
  get configurationTyped() {
@@ -71,7 +72,7 @@ class BaseTool {
71
72
  if (!viewports || !viewports.length) {
72
73
  return;
73
74
  }
74
- return viewports[0].getImageData();
75
+ return viewports[0].getImageData(volumeId);
75
76
  }
76
77
  else if (targetId.startsWith('videoId:')) {
77
78
  const imageURI = csUtils.imageIdToURI(targetId);
@@ -86,19 +87,139 @@ class BaseTool {
86
87
  }
87
88
  }
88
89
  getTargetId(viewport, data) {
89
- const { isPreferredTargetId } = this.configurationTyped;
90
+ return this.getMeasurementTargets(viewport, data)[0];
91
+ }
92
+ getMeasurementTargets(viewport, data) {
93
+ const { targetsFilter, isPreferredTargetId } = this.configurationTyped;
90
94
  if (isPreferredTargetId && data?.cachedStats) {
91
95
  for (const [targetId, cachedStat] of Object.entries(data.cachedStats)) {
92
96
  if (isPreferredTargetId(viewport, { targetId, cachedStat })) {
93
- return targetId;
97
+ return [targetId];
94
98
  }
95
99
  }
96
100
  }
101
+ if (targetsFilter) {
102
+ const candidates = this.getMeasurementTargetCandidates(viewport, data);
103
+ const options = {
104
+ viewport,
105
+ configuration: this.configurationTyped,
106
+ data,
107
+ };
108
+ return targetsFilter(candidates, options).map((candidate) => candidate.targetId);
109
+ }
97
110
  const defaultTargetId = viewport.getViewReferenceId?.();
98
111
  if (defaultTargetId) {
99
- return defaultTargetId;
112
+ return [defaultTargetId];
113
+ }
114
+ throw new Error('getMeasurementTargets: viewport must have a getViewReferenceId method');
115
+ }
116
+ getMeasurementTargetCandidates(viewport, data) {
117
+ const candidates = [];
118
+ const displaySets = BaseTool.getViewportDisplaySets(viewport);
119
+ const actors = viewport.getActors?.() || [];
120
+ for (let index = 0; index < actors.length; index++) {
121
+ const { referencedId, representationUID } = actors[index];
122
+ if (!referencedId) {
123
+ continue;
124
+ }
125
+ const volume = cache.getVolume(referencedId);
126
+ if (!volume) {
127
+ continue;
128
+ }
129
+ const targetId = BaseTool.findCachedStatsTargetId(data, referencedId) ||
130
+ viewport.getViewReferenceId?.({ volumeId: referencedId });
131
+ if (!targetId) {
132
+ continue;
133
+ }
134
+ const displaySetInfo = displaySets.find((displaySet) => displaySet.volumeId === referencedId);
135
+ const imageIds = displaySetInfo?.imageIds ??
136
+ (volume.imageIds?.length ? volume.imageIds : undefined);
137
+ const instance = displaySetInfo?.instance ?? BaseTool.getExemplarInstance(imageIds);
138
+ candidates.push({
139
+ targetId,
140
+ referencedId,
141
+ representationUID: representationUID,
142
+ displaySet: displaySetInfo?.displaySet,
143
+ displaySetUID: displaySetInfo?.displaySetUID,
144
+ instance,
145
+ modality: instance?.Modality ?? volume.metadata?.Modality,
146
+ imageIds,
147
+ index,
148
+ });
149
+ }
150
+ if (!candidates.length) {
151
+ const targetId = viewport.getViewReferenceId?.();
152
+ if (targetId) {
153
+ const displaySetInfo = displaySets[0];
154
+ candidates.push({
155
+ targetId,
156
+ index: 0,
157
+ displaySet: displaySetInfo?.displaySet,
158
+ displaySetUID: displaySetInfo?.displaySetUID,
159
+ instance: displaySetInfo?.instance,
160
+ modality: displaySetInfo?.modality,
161
+ imageIds: displaySetInfo?.imageIds,
162
+ });
163
+ }
164
+ }
165
+ return candidates;
166
+ }
167
+ static getViewportDisplaySets(viewport) {
168
+ const displaySets = viewport.getDisplaySets?.();
169
+ if (!displaySets?.length) {
170
+ return [];
171
+ }
172
+ const provider = csUtils.genericViewportDisplaySetMetadataProvider;
173
+ return displaySets.map(({ displaySetId }) => {
174
+ const genericRegistration = provider.get(provider.VIEWPORT_V2_DISPLAY_SET, displaySetId);
175
+ const registeredImageIds = Array.isArray(genericRegistration)
176
+ ? genericRegistration
177
+ : genericRegistration?.imageIds;
178
+ const typedDisplaySet = registeredImageIds
179
+ ?.map((imageId) => metaData.get('displaySetModule', imageId))
180
+ .find((displaySet) => displaySet !== undefined);
181
+ const imageIds = typedDisplaySet?.imageIds?.length
182
+ ? Array.from(typedDisplaySet.imageIds)
183
+ : registeredImageIds;
184
+ const registered = typedDisplaySet ?? genericRegistration;
185
+ const instance = typedDisplaySet?.instances?.[0] ??
186
+ BaseTool.getExemplarInstance(imageIds);
187
+ return {
188
+ displaySetUID: typedDisplaySet?.displaySetId ?? displaySetId,
189
+ displaySet: registered,
190
+ instance,
191
+ imageIds,
192
+ volumeId: genericRegistration?.volumeId,
193
+ modality: instance?.Modality ??
194
+ (imageIds?.length
195
+ ? metaData.get('generalSeriesModule', imageIds[0])?.modality
196
+ : undefined),
197
+ };
198
+ });
199
+ }
200
+ static getExemplarInstance(imageIds) {
201
+ if (!imageIds?.length) {
202
+ return;
203
+ }
204
+ return metaData.get('instance', imageIds[0]);
205
+ }
206
+ static findCachedStatsTargetId(data, referencedId) {
207
+ if (!data?.cachedStats) {
208
+ return;
209
+ }
210
+ return Object.keys(data.cachedStats).find((key) => key.startsWith('volumeId:') && csUtils.getVolumeId(key) === referencedId);
211
+ }
212
+ ensureCachedStatsTargets(data, targetIds, needsUpdate) {
213
+ let missing = false;
214
+ const cachedStats = (data.cachedStats ??= {});
215
+ for (const targetId of targetIds) {
216
+ const stats = cachedStats[targetId];
217
+ if (!stats || needsUpdate?.(stats)) {
218
+ cachedStats[targetId] = {};
219
+ missing = true;
220
+ }
100
221
  }
101
- throw new Error('getTargetId: viewport must have a getViewReferenceId method');
222
+ return missing;
102
223
  }
103
224
  undo() {
104
225
  this.doneEditMemo();
@@ -1,4 +1,6 @@
1
1
  import BaseTool from './BaseTool.js';
2
2
  import AnnotationTool from './AnnotationTool.js';
3
3
  import AnnotationDisplayTool from './AnnotationDisplayTool.js';
4
- export { BaseTool, AnnotationTool, AnnotationDisplayTool };
4
+ import measurementTargetFilters from './measurementTargetFilters.js';
5
+ export { BaseTool, AnnotationTool, AnnotationDisplayTool, measurementTargetFilters, };
6
+ export * from './measurementTargetFilters.js';