@cornerstonejs/tools 2.0.4 → 2.1.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.
@@ -9,7 +9,7 @@ import * as cursors from './cursors';
9
9
  import * as Types from './types';
10
10
  import * as annotation from './stateManagement/annotation';
11
11
  import * as segmentation from './stateManagement/segmentation';
12
- import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool } from './tools';
12
+ import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool } from './tools';
13
13
  import VideoRedactionTool from './tools/annotation/VideoRedactionTool';
14
14
  import * as Enums from './enums';
15
- export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, SegmentSelectTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, };
15
+ export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, SegmentSelectTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, };
package/dist/esm/index.js CHANGED
@@ -9,7 +9,7 @@ import * as cursors from './cursors';
9
9
  import * as Types from './types';
10
10
  import * as annotation from './stateManagement/annotation';
11
11
  import * as segmentation from './stateManagement/segmentation';
12
- import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, } from './tools';
12
+ import { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, KeyImageTool, CrosshairsTool, ReferenceLinesTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, OverlayGridTool, SegmentationIntersectionTool, EraserTool, SculptorTool, SegmentSelectTool, WindowLevelRegionTool, VolumeRotateTool, } from './tools';
13
13
  import VideoRedactionTool from './tools/annotation/VideoRedactionTool';
14
14
  import * as Enums from './enums';
15
- export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, SegmentSelectTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, };
15
+ export { VideoRedactionTool, init, destroy, addTool, removeTool, cancelActiveManipulations, BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, ZoomTool, StackScrollTool, PlanarRotateTool, MIPJumpToClickTool, LengthTool, HeightTool, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, SplineContourSegmentationTool, BidirectionalTool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, MagnifyTool, AdvancedMagnifyTool, ReferenceCursors, ScaleOverlayTool, SculptorTool, EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, BrushTool, OrientationMarkerTool, SegmentSelectTool, synchronizers, Synchronizer, SynchronizerManager, PaintFillTool, Types, state, ToolGroupManager, Enums, CONSTANTS, drawing, annotation, segmentation, utilities, cursors, VolumeRotateTool, };
@@ -66,6 +66,10 @@ export default class SegmentationStateManager {
66
66
  viewportId: string;
67
67
  representations: SegmentationRepresentation[];
68
68
  }>;
69
+ getSegmentationRepresentationsBySegmentationId(segmentationId: string): {
70
+ viewportId: string;
71
+ representations: SegmentationRepresentation[];
72
+ }[];
69
73
  }
70
74
  declare function internalComputeVolumeLabelmapFromStack({ imageIds, options, }: {
71
75
  imageIds: string[];
@@ -424,6 +424,16 @@ export default class SegmentationStateManager {
424
424
  representations,
425
425
  }));
426
426
  }
427
+ getSegmentationRepresentationsBySegmentationId(segmentationId) {
428
+ const result = [];
429
+ Object.entries(this.state.viewportSegRepresentations).forEach(([viewportId, viewportReps]) => {
430
+ const filteredReps = viewportReps.filter((representation) => representation.segmentationId === segmentationId);
431
+ if (filteredReps.length > 0) {
432
+ result.push({ viewportId, representations: filteredReps });
433
+ }
434
+ });
435
+ return result;
436
+ }
427
437
  }
428
438
  async function internalComputeVolumeLabelmapFromStack({ imageIds, options, }) {
429
439
  const segmentationImageIds = imageIds;
@@ -8,3 +8,7 @@ export declare function getSegmentationRepresentation(viewportId: string, specif
8
8
  segmentationId: string;
9
9
  type: SegmentationRepresentations;
10
10
  }): SegmentationRepresentation | undefined;
11
+ export declare function getSegmentationRepresentationsBySegmentationId(segmentationId: string): {
12
+ viewportId: string;
13
+ representations: SegmentationRepresentation[];
14
+ }[];
@@ -11,3 +11,7 @@ export function getSegmentationRepresentation(viewportId, specifier) {
11
11
  const representations = segmentationStateManager.getSegmentationRepresentations(viewportId, specifier);
12
12
  return representations?.[0];
13
13
  }
14
+ export function getSegmentationRepresentationsBySegmentationId(segmentationId) {
15
+ const segmentationStateManager = defaultSegmentationStateManager;
16
+ return segmentationStateManager.getSegmentationRepresentationsBySegmentationId(segmentationId);
17
+ }
@@ -12,6 +12,6 @@ import { getViewportIdsWithSegmentation } from './getViewportIdsWithSegmentation
12
12
  import { getCurrentLabelmapImageIdForViewport } from './getCurrentLabelmapImageIdForViewport';
13
13
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
14
14
  import { getStackSegmentationImageIdsForViewport } from './getStackSegmentationImageIdsForViewport';
15
- import { getSegmentationRepresentation, getSegmentationRepresentations } from './getSegmentationRepresentation';
15
+ import { getSegmentationRepresentation, getSegmentationRepresentations, getSegmentationRepresentationsBySegmentationId } from './getSegmentationRepresentation';
16
16
  declare function destroy(): void;
17
- export { getColorLUT, getCurrentLabelmapImageIdForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, destroy, };
17
+ export { getColorLUT, getCurrentLabelmapImageIdForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
@@ -12,9 +12,9 @@ import { getViewportIdsWithSegmentation } from './getViewportIdsWithSegmentation
12
12
  import { getCurrentLabelmapImageIdForViewport } from './getCurrentLabelmapImageIdForViewport';
13
13
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
14
14
  import { getStackSegmentationImageIdsForViewport } from './getStackSegmentationImageIdsForViewport';
15
- import { getSegmentationRepresentation, getSegmentationRepresentations, } from './getSegmentationRepresentation';
15
+ import { getSegmentationRepresentation, getSegmentationRepresentations, getSegmentationRepresentationsBySegmentationId, } from './getSegmentationRepresentation';
16
16
  import { defaultSegmentationStateManager } from './SegmentationStateManager';
17
17
  function destroy() {
18
18
  defaultSegmentationStateManager.resetState();
19
19
  }
20
- export { getColorLUT, getCurrentLabelmapImageIdForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, destroy, };
20
+ export { getColorLUT, getCurrentLabelmapImageIdForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
@@ -0,0 +1,41 @@
1
+ import { AnnotationTool } from '../base';
2
+ import type { Types } from '@cornerstonejs/core';
3
+ import type { EventTypes, PublicToolProps, ToolProps, SVGDrawingHelper } from '../../types';
4
+ import type { Annotation } from '../../types/AnnotationTypes';
5
+ export interface ETDRSGridAnnotation extends Annotation {
6
+ data: {
7
+ handles: {
8
+ points: [Types.Point3];
9
+ };
10
+ };
11
+ }
12
+ declare class ETDRSGridTool extends AnnotationTool {
13
+ static toolName: any;
14
+ touchDragCallback: unknown;
15
+ mouseDragCallback: unknown;
16
+ editData: {
17
+ annotation: Annotation;
18
+ viewportIdsToRender: Array<string>;
19
+ newAnnotation?: boolean;
20
+ hasMoved?: boolean;
21
+ } | null;
22
+ isDrawing: boolean;
23
+ isHandleOutsideImage: boolean;
24
+ constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
25
+ addNewAnnotation: (evt: EventTypes.InteractionEventType) => ETDRSGridAnnotation;
26
+ worldMeasureToCanvas(measurement: any, viewport: any): number;
27
+ isPointNearTool: (element: HTMLDivElement, annotation: ETDRSGridAnnotation, canvasCoords: Types.Point2, proximity: number) => boolean;
28
+ toolSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: ETDRSGridAnnotation) => void;
29
+ handleSelectedCallback: (evt: EventTypes.InteractionEventType, annotation: ETDRSGridAnnotation) => void;
30
+ _endCallback: (evt: EventTypes.InteractionEventType) => void;
31
+ _dragDrawCallback: (evt: EventTypes.InteractionEventType) => void;
32
+ _dragModifyCallback: (evt: EventTypes.InteractionEventType) => void;
33
+ _dragHandle: (evt: EventTypes.InteractionEventType) => void;
34
+ cancel: (element: HTMLDivElement) => string;
35
+ _activateModify: (element: any) => void;
36
+ _deactivateModify: (element: any) => void;
37
+ _activateDraw: (element: any) => void;
38
+ _deactivateDraw: (element: any) => void;
39
+ renderAnnotation: (enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
40
+ }
41
+ export default ETDRSGridTool;
@@ -0,0 +1,354 @@
1
+ import { AnnotationTool } from '../base';
2
+ import { getEnabledElement } from '@cornerstonejs/core';
3
+ import { addAnnotation, getAnnotations, removeAnnotation, } from '../../stateManagement/annotation/annotationState';
4
+ import { isAnnotationVisible } from '../../stateManagement/annotation/annotationVisibility';
5
+ import { triggerAnnotationCompleted } from '../../stateManagement/annotation/helpers/state';
6
+ import { drawCircle as drawCircleSvg, drawLine } from '../../drawingSvg';
7
+ import { state } from '../../store/state';
8
+ import { Events } from '../../enums';
9
+ import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
10
+ import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
11
+ import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
12
+ import { getCanvasCircleRadius } from '../../utilities/math/circle';
13
+ import { vec3 } from 'gl-matrix';
14
+ const CROSSHAIR_SIZE = 5;
15
+ class ETDRSGridTool extends AnnotationTool {
16
+ constructor(toolProps = {}, defaultToolProps = {
17
+ supportedInteractionTypes: ['Mouse', 'Touch'],
18
+ configuration: {
19
+ shadow: true,
20
+ preventHandleOutsideImage: false,
21
+ degrees: [45, 135, 225, 315],
22
+ diameters: [10, 30, 60],
23
+ },
24
+ }) {
25
+ super(toolProps, defaultToolProps);
26
+ this.isHandleOutsideImage = false;
27
+ this.addNewAnnotation = (evt) => {
28
+ const eventDetail = evt.detail;
29
+ const { currentPoints, element } = eventDetail;
30
+ const worldPos = currentPoints.world;
31
+ const enabledElement = getEnabledElement(element);
32
+ const { viewport, renderingEngine } = enabledElement;
33
+ this.isDrawing = true;
34
+ const camera = viewport.getCamera();
35
+ const { viewPlaneNormal, viewUp } = camera;
36
+ const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
37
+ const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
38
+ const annotation = {
39
+ highlighted: true,
40
+ invalidated: true,
41
+ metadata: {
42
+ toolName: this.getToolName(),
43
+ viewPlaneNormal: [...viewPlaneNormal],
44
+ viewUp: [...viewUp],
45
+ FrameOfReferenceUID,
46
+ referencedImageId,
47
+ ...viewport.getViewReference({ points: [worldPos] }),
48
+ },
49
+ data: {
50
+ label: '',
51
+ handles: {
52
+ points: [[...worldPos]],
53
+ },
54
+ },
55
+ };
56
+ addAnnotation(annotation, element);
57
+ const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
58
+ this.editData = {
59
+ annotation,
60
+ viewportIdsToRender,
61
+ newAnnotation: true,
62
+ };
63
+ this._activateDraw(element);
64
+ hideElementCursor(element);
65
+ evt.preventDefault();
66
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
67
+ return annotation;
68
+ };
69
+ this.isPointNearTool = (element, annotation, canvasCoords, proximity) => {
70
+ const enabledElement = getEnabledElement(element);
71
+ const { viewport } = enabledElement;
72
+ const { data } = annotation;
73
+ const { points } = data.handles;
74
+ const center = viewport.worldToCanvas(points[0]);
75
+ const radius = getCanvasCircleRadius([center, canvasCoords]);
76
+ if (Math.abs(radius) < proximity) {
77
+ return true;
78
+ }
79
+ return false;
80
+ };
81
+ this.toolSelectedCallback = (evt, annotation) => {
82
+ const eventDetail = evt.detail;
83
+ const { element } = eventDetail;
84
+ annotation.highlighted = true;
85
+ const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
86
+ this.editData = {
87
+ annotation,
88
+ viewportIdsToRender,
89
+ };
90
+ hideElementCursor(element);
91
+ this._activateModify(element);
92
+ const enabledElement = getEnabledElement(element);
93
+ const { renderingEngine } = enabledElement;
94
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
95
+ evt.preventDefault();
96
+ };
97
+ this.handleSelectedCallback = (evt, annotation) => {
98
+ const eventDetail = evt.detail;
99
+ const { element } = eventDetail;
100
+ annotation.highlighted = true;
101
+ const viewportIdsToRender = getViewportIdsWithToolToRender(element, this.getToolName());
102
+ this.editData = {
103
+ annotation,
104
+ viewportIdsToRender,
105
+ };
106
+ this._activateModify(element);
107
+ hideElementCursor(element);
108
+ const enabledElement = getEnabledElement(element);
109
+ const { renderingEngine } = enabledElement;
110
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
111
+ evt.preventDefault();
112
+ };
113
+ this._endCallback = (evt) => {
114
+ const eventDetail = evt.detail;
115
+ const { element } = eventDetail;
116
+ const { annotation, viewportIdsToRender, newAnnotation, hasMoved } = this.editData;
117
+ const { data } = annotation;
118
+ if (newAnnotation && !hasMoved) {
119
+ return;
120
+ }
121
+ annotation.highlighted = false;
122
+ data.handles.activeHandleIndex = null;
123
+ this._deactivateModify(element);
124
+ this._deactivateDraw(element);
125
+ resetElementCursor(element);
126
+ const { renderingEngine } = getEnabledElement(element);
127
+ this.editData = null;
128
+ this.isDrawing = false;
129
+ if (this.isHandleOutsideImage &&
130
+ this.configuration.preventHandleOutsideImage) {
131
+ removeAnnotation(annotation.annotationUID);
132
+ }
133
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
134
+ if (newAnnotation) {
135
+ triggerAnnotationCompleted(annotation);
136
+ }
137
+ };
138
+ this._dragDrawCallback = (evt) => {
139
+ this.isDrawing = true;
140
+ const eventDetail = evt.detail;
141
+ const { element } = eventDetail;
142
+ const { currentPoints } = eventDetail;
143
+ const currentCanvasPoints = currentPoints.canvas;
144
+ const enabledElement = getEnabledElement(element);
145
+ const { renderingEngine, viewport } = enabledElement;
146
+ const { canvasToWorld } = viewport;
147
+ const { annotation, viewportIdsToRender } = this.editData;
148
+ const { data } = annotation;
149
+ data.handles.points = [
150
+ canvasToWorld(currentCanvasPoints),
151
+ canvasToWorld(currentCanvasPoints),
152
+ ];
153
+ annotation.invalidated = true;
154
+ this.editData.hasMoved = true;
155
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
156
+ };
157
+ this._dragModifyCallback = (evt) => {
158
+ this.isDrawing = true;
159
+ const eventDetail = evt.detail;
160
+ const { element } = eventDetail;
161
+ const { annotation, viewportIdsToRender } = this.editData;
162
+ const { data } = annotation;
163
+ const { deltaPoints } = eventDetail;
164
+ const worldPosDelta = deltaPoints.world;
165
+ const points = data.handles.points;
166
+ points.forEach((point) => {
167
+ point[0] += worldPosDelta[0];
168
+ point[1] += worldPosDelta[1];
169
+ point[2] += worldPosDelta[2];
170
+ });
171
+ annotation.invalidated = true;
172
+ const enabledElement = getEnabledElement(element);
173
+ const { renderingEngine } = enabledElement;
174
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
175
+ };
176
+ this._dragHandle = (evt) => {
177
+ const eventDetail = evt.detail;
178
+ const { element } = eventDetail;
179
+ const enabledElement = getEnabledElement(element);
180
+ const { canvasToWorld, worldToCanvas } = enabledElement.viewport;
181
+ const { annotation } = this.editData;
182
+ const { data } = annotation;
183
+ const { points } = data.handles;
184
+ const canvasCoordinates = points.map((p) => worldToCanvas(p));
185
+ const { currentPoints } = eventDetail;
186
+ const currentCanvasPoints = currentPoints.canvas;
187
+ const dXCanvas = currentCanvasPoints[0] - canvasCoordinates[0][0];
188
+ const dYCanvas = currentCanvasPoints[1] - canvasCoordinates[0][1];
189
+ const canvasCenter = currentCanvasPoints;
190
+ const canvasEnd = [
191
+ canvasCoordinates[1][0] + dXCanvas,
192
+ canvasCoordinates[1][1] + dYCanvas,
193
+ ];
194
+ points[0] = canvasToWorld(canvasCenter);
195
+ points[1] = canvasToWorld(canvasEnd);
196
+ };
197
+ this.cancel = (element) => {
198
+ if (this.isDrawing) {
199
+ this.isDrawing = false;
200
+ this._deactivateDraw(element);
201
+ this._deactivateModify(element);
202
+ resetElementCursor(element);
203
+ const { annotation, viewportIdsToRender, newAnnotation } = this.editData;
204
+ const { data } = annotation;
205
+ annotation.highlighted = false;
206
+ data.handles.activeHandleIndex = null;
207
+ const { renderingEngine } = getEnabledElement(element);
208
+ triggerAnnotationRenderForViewportIds(viewportIdsToRender);
209
+ if (newAnnotation) {
210
+ triggerAnnotationCompleted(annotation);
211
+ }
212
+ this.editData = null;
213
+ return annotation.annotationUID;
214
+ }
215
+ };
216
+ this._activateModify = (element) => {
217
+ state.isInteractingWithTool = true;
218
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
219
+ element.addEventListener(Events.MOUSE_DRAG, this._dragModifyCallback);
220
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
221
+ element.addEventListener(Events.TOUCH_END, this._endCallback);
222
+ element.addEventListener(Events.TOUCH_DRAG, this._dragModifyCallback);
223
+ element.addEventListener(Events.TOUCH_TAP, this._endCallback);
224
+ };
225
+ this._deactivateModify = (element) => {
226
+ state.isInteractingWithTool = false;
227
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
228
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragModifyCallback);
229
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
230
+ element.removeEventListener(Events.TOUCH_END, this._endCallback);
231
+ element.removeEventListener(Events.TOUCH_DRAG, this._dragModifyCallback);
232
+ element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
233
+ };
234
+ this._activateDraw = (element) => {
235
+ state.isInteractingWithTool = true;
236
+ element.addEventListener(Events.MOUSE_UP, this._endCallback);
237
+ element.addEventListener(Events.MOUSE_DRAG, this._dragDrawCallback);
238
+ element.addEventListener(Events.MOUSE_MOVE, this._dragDrawCallback);
239
+ element.addEventListener(Events.MOUSE_CLICK, this._endCallback);
240
+ element.addEventListener(Events.TOUCH_END, this._endCallback);
241
+ element.addEventListener(Events.TOUCH_DRAG, this._dragDrawCallback);
242
+ element.addEventListener(Events.TOUCH_TAP, this._endCallback);
243
+ };
244
+ this._deactivateDraw = (element) => {
245
+ state.isInteractingWithTool = false;
246
+ element.removeEventListener(Events.MOUSE_UP, this._endCallback);
247
+ element.removeEventListener(Events.MOUSE_DRAG, this._dragDrawCallback);
248
+ element.removeEventListener(Events.MOUSE_MOVE, this._dragDrawCallback);
249
+ element.removeEventListener(Events.MOUSE_CLICK, this._endCallback);
250
+ element.removeEventListener(Events.TOUCH_END, this._endCallback);
251
+ element.removeEventListener(Events.TOUCH_DRAG, this._dragDrawCallback);
252
+ element.removeEventListener(Events.TOUCH_TAP, this._endCallback);
253
+ };
254
+ this.renderAnnotation = (enabledElement, svgDrawingHelper) => {
255
+ let renderStatus = false;
256
+ const { viewport } = enabledElement;
257
+ const { element } = viewport;
258
+ let annotations = getAnnotations(this.getToolName(), element);
259
+ if (!annotations?.length) {
260
+ return renderStatus;
261
+ }
262
+ annotations = this.filterInteractableAnnotationsForElement(element, annotations);
263
+ if (!annotations?.length) {
264
+ return renderStatus;
265
+ }
266
+ const styleSpecifier = {
267
+ toolGroupId: this.toolGroupId,
268
+ toolName: this.getToolName(),
269
+ viewportId: enabledElement.viewport.id,
270
+ };
271
+ for (let i = 0; i < annotations.length; i++) {
272
+ const annotation = annotations[i];
273
+ const { annotationUID, data } = annotation;
274
+ const { handles } = data;
275
+ const { points } = handles;
276
+ styleSpecifier.annotationUID = annotationUID;
277
+ const { color, lineWidth, lineDash } = this.getAnnotationStyle({
278
+ annotation,
279
+ styleSpecifier,
280
+ });
281
+ const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p));
282
+ const center = canvasCoordinates[0];
283
+ if (!viewport.getRenderingEngine()) {
284
+ console.warn('Rendering Engine has been destroyed');
285
+ return renderStatus;
286
+ }
287
+ if (!isAnnotationVisible(annotationUID)) {
288
+ continue;
289
+ }
290
+ let lineUID = `${annotationUID}-crosshair-vertical`;
291
+ let start = [center[0], center[1] + CROSSHAIR_SIZE];
292
+ let end = [center[0], center[1] - CROSSHAIR_SIZE];
293
+ drawLine(svgDrawingHelper, annotationUID, lineUID, start, end, {
294
+ color,
295
+ lineDash,
296
+ lineWidth,
297
+ });
298
+ lineUID = `${annotationUID}-crosshair-horizontal`;
299
+ start = [center[0] + CROSSHAIR_SIZE, center[1]];
300
+ end = [center[0] - CROSSHAIR_SIZE, center[1]];
301
+ drawLine(svgDrawingHelper, annotationUID, lineUID, start, end, {
302
+ color,
303
+ lineDash,
304
+ lineWidth,
305
+ });
306
+ const diametersCanvas = this.configuration.diameters.map((diameter) => this.worldMeasureToCanvas(diameter, viewport));
307
+ for (let i = 0; i < diametersCanvas.length; i++) {
308
+ const dataId = `${annotationUID}-circle-${i}`;
309
+ const circleUID = `${annotationUID}-circle-${i}`;
310
+ drawCircleSvg(svgDrawingHelper, annotationUID, circleUID, center, diametersCanvas[i] / 2, {
311
+ color,
312
+ lineDash,
313
+ lineWidth,
314
+ }, dataId);
315
+ }
316
+ const degreesRad = (x) => (x * Math.PI) / 180;
317
+ const angleRadians = this.configuration.degrees.map((degree) => degreesRad(degree));
318
+ for (let i = 0; i < angleRadians.length; i++) {
319
+ const lineUID = `${annotationUID}-line-${i}`;
320
+ const start = [
321
+ (Math.cos(angleRadians[i]) * diametersCanvas[0]) / 2 + center[0],
322
+ (Math.sin(angleRadians[i]) * diametersCanvas[0]) / 2 + center[1],
323
+ ];
324
+ const end = [
325
+ (Math.cos(angleRadians[i]) * diametersCanvas[2]) / 2 + center[0],
326
+ (Math.sin(angleRadians[i]) * diametersCanvas[2]) / 2 + center[1],
327
+ ];
328
+ drawLine(svgDrawingHelper, annotationUID, lineUID, start, end, {
329
+ color,
330
+ lineDash,
331
+ lineWidth,
332
+ });
333
+ }
334
+ renderStatus = true;
335
+ }
336
+ return renderStatus;
337
+ };
338
+ }
339
+ worldMeasureToCanvas(measurement, viewport) {
340
+ const p1 = viewport.canvasToWorld([
341
+ viewport.canvas.width / 2,
342
+ viewport.canvas.height / 2,
343
+ ]);
344
+ const { viewUp } = viewport.getCamera();
345
+ const p2 = vec3.scaleAndAdd(vec3.create(), p1, viewUp, measurement);
346
+ const p1Canvas = viewport.worldToCanvas(p1);
347
+ const p2Canvas = viewport.worldToCanvas(p2);
348
+ const distance = Math.sqrt(Math.pow(p2Canvas[0] - p1Canvas[0], 2) +
349
+ Math.pow(p2Canvas[1] - p1Canvas[1], 2));
350
+ return distance;
351
+ }
352
+ }
353
+ ETDRSGridTool.toolName = 'ETDRSGrid';
354
+ export default ETDRSGridTool;
@@ -426,7 +426,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
426
426
  return;
427
427
  }
428
428
  const enabledElement = getEnabledElement(element);
429
- const { viewport, renderingEngine } = enabledElement;
429
+ const { viewport } = enabledElement;
430
430
  const { cachedStats } = data;
431
431
  const { polyline: points } = data.contour;
432
432
  const targetIds = Object.keys(cachedStats);
@@ -555,7 +555,7 @@ class SplineROITool extends ContourSegmentationBaseTool {
555
555
  points: splinePolylineCanvas,
556
556
  closed: data.contour.closed,
557
557
  targetWindingDirection: ContourWindingDirection.Clockwise,
558
- }, viewport);
558
+ }, viewport, { updateWindingDirection: data.contour.closed });
559
559
  });
560
560
  super.renderAnnotationInstance(renderContext);
561
561
  if (!data.cachedStats[targetId] ||
@@ -16,6 +16,8 @@ declare abstract class ContourBaseTool extends AnnotationTool {
16
16
  }, transforms: {
17
17
  canvasToWorld: (point: Types.Point2) => Types.Point3;
18
18
  worldToCanvas: (point: Types.Point3) => Types.Point2;
19
+ }, options?: {
20
+ updateWindingDirection?: boolean;
19
21
  }): void;
20
22
  protected getPolylinePoints(annotation: ContourAnnotation): Types.Point3[];
21
23
  protected renderAnnotationInstance(renderContext: AnnotationRenderContext): boolean;
@@ -112,13 +112,14 @@ class ContourBaseTool extends AnnotationTool {
112
112
  annotation.invalidated = true;
113
113
  getChildAnnotations(annotation).forEach((childAnnotation) => this.moveAnnotation(childAnnotation, worldPosDelta));
114
114
  }
115
- updateContourPolyline(annotation, polylineData, transforms) {
115
+ updateContourPolyline(annotation, polylineData, transforms, options) {
116
116
  const decimateConfig = this.configuration?.decimate || {};
117
117
  updateContourPolyline(annotation, polylineData, transforms, {
118
118
  decimate: {
119
119
  enabled: !!decimateConfig.enabled,
120
120
  epsilon: decimateConfig.epsilon,
121
121
  },
122
+ updateWindingDirection: options?.updateWindingDirection,
122
123
  });
123
124
  }
124
125
  getPolylinePoints(annotation) {
@@ -25,6 +25,7 @@ import DragProbeTool from './annotation/DragProbeTool';
25
25
  import RectangleROITool from './annotation/RectangleROITool';
26
26
  import EllipticalROITool from './annotation/EllipticalROITool';
27
27
  import CircleROITool from './annotation/CircleROITool';
28
+ import ETDRSGridTool from './annotation/ETDRSGridTool';
28
29
  import SplineROITool from './annotation/SplineROITool';
29
30
  import SplineContourSegmentationTool from './annotation/SplineContourSegmentationTool';
30
31
  import PlanarFreehandROITool from './annotation/PlanarFreehandROITool';
@@ -47,4 +48,4 @@ import BrushTool from './segmentation/BrushTool';
47
48
  import PaintFillTool from './segmentation/PaintFillTool';
48
49
  import OrientationMarkerTool from './OrientationMarkerTool';
49
50
  import SegmentSelectTool from './segmentation/SegmentSelectTool';
50
- export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, };
51
+ export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, };
@@ -25,6 +25,7 @@ import DragProbeTool from './annotation/DragProbeTool';
25
25
  import RectangleROITool from './annotation/RectangleROITool';
26
26
  import EllipticalROITool from './annotation/EllipticalROITool';
27
27
  import CircleROITool from './annotation/CircleROITool';
28
+ import ETDRSGridTool from './annotation/ETDRSGridTool';
28
29
  import SplineROITool from './annotation/SplineROITool';
29
30
  import SplineContourSegmentationTool from './annotation/SplineContourSegmentationTool';
30
31
  import PlanarFreehandROITool from './annotation/PlanarFreehandROITool';
@@ -47,4 +48,4 @@ import BrushTool from './segmentation/BrushTool';
47
48
  import PaintFillTool from './segmentation/PaintFillTool';
48
49
  import OrientationMarkerTool from './OrientationMarkerTool';
49
50
  import SegmentSelectTool from './segmentation/SegmentSelectTool';
50
- export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, };
51
+ export { BaseTool, AnnotationTool, AnnotationDisplayTool, PanTool, TrackballRotateTool, DragProbeTool, WindowLevelTool, WindowLevelRegionTool, StackScrollTool, PlanarRotateTool, ZoomTool, MIPJumpToClickTool, ReferenceCursors, CrosshairsTool, ReferenceLinesTool, OverlayGridTool, SegmentationIntersectionTool, BidirectionalTool, LengthTool, HeightTool, ProbeTool, RectangleROITool, EllipticalROITool, CircleROITool, ETDRSGridTool, SplineROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, LivewireContourTool, LivewireContourSegmentationTool, ArrowAnnotateTool, AngleTool, CobbAngleTool, UltrasoundDirectionalTool, KeyImageTool, AnnotationEraserTool as EraserTool, RectangleScissorsTool, CircleScissorsTool, SphereScissorsTool, RectangleROIThresholdTool, RectangleROIStartEndThresholdTool, CircleROIStartEndThresholdTool, SplineContourSegmentationTool, BrushTool, MagnifyTool, AdvancedMagnifyTool, PaintFillTool, ScaleOverlayTool, OrientationMarkerTool, SculptorTool, SegmentSelectTool, VolumeRotateTool, };
@@ -22,10 +22,9 @@ function playClip(element, playClipOptions) {
22
22
  playClipOptions.dynamicCineEnabled =
23
23
  playClipOptions.dynamicCineEnabled ?? true;
24
24
  const { viewport } = enabledElement;
25
- const volume = _getVolumeFromViewport(viewport);
26
25
  const playClipContext = _createCinePlayContext(viewport, playClipOptions);
27
26
  let playClipData = getToolState(element);
28
- const isDynamicCinePlaying = playClipOptions.dynamicCineEnabled && volume?.isDynamicVolume();
27
+ const isDynamicCinePlaying = playClipOptions.dynamicCineEnabled;
29
28
  if (isDynamicCinePlaying) {
30
29
  _stopDynamicVolumeCine(element);
31
30
  }
@@ -97,7 +96,10 @@ function playClip(element, playClipOptions) {
97
96
  }
98
97
  };
99
98
  if (isDynamicCinePlaying) {
100
- dynamicVolumesPlayingMap.set(volume.volumeId, element);
99
+ const volume = _getVolumeFromViewport(viewport);
100
+ if (volume) {
101
+ dynamicVolumesPlayingMap.set(volume.volumeId, element);
102
+ }
101
103
  }
102
104
  if (playClipContext.play) {
103
105
  playClipData.framesPerSecond = playClipContext.play(playClipOptions.framesPerSecond);
@@ -210,10 +212,11 @@ function _stopClipWithData(playClipData) {
210
212
  }
211
213
  }
212
214
  function _getVolumesFromViewport(viewport) {
213
- return viewport
214
- .getActors()
215
- .map((actor) => cache.getVolume(viewport.getVolumeId()))
216
- .filter((volume) => !!volume);
215
+ if (!viewport || !viewport.getVolumeId) {
216
+ return [];
217
+ }
218
+ const volumeId = viewport.getVolumeId();
219
+ return [cache.getVolume(volumeId)];
217
220
  }
218
221
  function _getVolumeFromViewport(viewport) {
219
222
  const volumes = _getVolumesFromViewport(viewport);
@@ -9,6 +9,7 @@ export default function updateContourPolyline(annotation: ContourAnnotation, pol
9
9
  canvasToWorld: (point: Types.Point2) => Types.Point3;
10
10
  worldToCanvas: (point: Types.Point3) => Types.Point2;
11
11
  }, options?: {
12
+ updateWindingDirection?: boolean;
12
13
  decimate?: {
13
14
  enabled?: boolean;
14
15
  epsilon?: number;
@@ -6,6 +6,7 @@ export default function updateContourPolyline(annotation, polylineData, transfor
6
6
  const { data } = annotation;
7
7
  const { targetWindingDirection } = polylineData;
8
8
  let { points: polyline } = polylineData;
9
+ let windingDirection = math.polyline.getWindingDirection(polyline);
9
10
  if (options?.decimate?.enabled) {
10
11
  polyline = math.polyline.decimate(polylineData.points, options?.decimate?.epsilon);
11
12
  }
@@ -22,24 +23,24 @@ export default function updateContourPolyline(annotation, polylineData, transfor
22
23
  }
23
24
  closed = currentClosedState;
24
25
  }
25
- let windingDirection = parentAnnotation
26
- ? parentAnnotation.data.contour.windingDirection * -1
27
- : targetWindingDirection;
28
- if (windingDirection === undefined) {
29
- windingDirection = currentPolylineWindingDirection;
30
- }
31
- if (windingDirection !== currentPolylineWindingDirection) {
32
- polyline.reverse();
33
- }
34
- if (!data.handles?.points?.length) {
35
- return;
36
- }
37
- const handlePoints = data.handles.points.map((p) => worldToCanvas(p));
38
- if (handlePoints.length > 2) {
39
- const currentHandlesWindingDirection = math.polyline.getWindingDirection(handlePoints);
40
- if (currentHandlesWindingDirection !== windingDirection) {
41
- data.handles.points.reverse();
26
+ if (options?.updateWindingDirection !== false) {
27
+ let updatedWindingDirection = parentAnnotation
28
+ ? parentAnnotation.data.contour.windingDirection * -1
29
+ : targetWindingDirection;
30
+ if (updatedWindingDirection === undefined) {
31
+ updatedWindingDirection = windingDirection;
32
+ }
33
+ if (updatedWindingDirection !== windingDirection) {
34
+ polyline.reverse();
35
+ }
36
+ const handlePoints = data.handles.points.map((p) => worldToCanvas(p));
37
+ if (handlePoints.length > 2) {
38
+ const currentHandlesWindingDirection = math.polyline.getWindingDirection(handlePoints);
39
+ if (currentHandlesWindingDirection !== updatedWindingDirection) {
40
+ data.handles.points.reverse();
41
+ }
42
42
  }
43
+ windingDirection = updatedWindingDirection;
43
44
  }
44
45
  for (let i = 0; i < numPoints; i++) {
45
46
  polylineWorldPoints[i] = canvasToWorld(polyline[i]);
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "description": "Cornerstone3D Tools",
5
- "main": "./dist/umd/index.js",
5
+ "main": "./dist/esm/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
7
7
  "module": "./dist/esm/index.js",
8
8
  "repository": "https://github.com/cornerstonejs/cornerstone3D",
@@ -105,7 +105,7 @@
105
105
  "canvas": "^2.11.2"
106
106
  },
107
107
  "peerDependencies": {
108
- "@cornerstonejs/core": "^2.0.4",
108
+ "@cornerstonejs/core": "^2.1.0",
109
109
  "@kitware/vtk.js": "32.1.0",
110
110
  "@types/d3-array": "^3.0.4",
111
111
  "@types/d3-interpolate": "^3.0.1",
@@ -124,5 +124,5 @@
124
124
  "type": "individual",
125
125
  "url": "https://ohif.org/donate"
126
126
  },
127
- "gitHead": "335560c8fafe1ba662ab586d8bb301fa78dac2e6"
127
+ "gitHead": "36016cf1416e1b7faf5ef82ce07f8a973c199da2"
128
128
  }