All files / packages/tools/src/utilities/contours updateContourPolyline.ts

68.57% Statements 24/35
37.5% Branches 6/16
50% Functions 1/2
69.69% Lines 23/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                                                                                  2x 2x 2x 2x     2x             2x 2x 2x   2x 2x   2x                                 2x       2x       2x 2x     2x   2x                 2x 1280x     2x 2x 2x   2x    
import { utilities as csUtils } from '@cornerstonejs/core';
import { Types } from '@cornerstonejs/core';
import type { ContourAnnotation } from '../../types';
import type { ContourWindingDirection } from '../../types/ContourAnnotation';
import * as math from '../math';
import {
  getParentAnnotation,
  invalidateAnnotation,
} from '../../stateManagement';
 
/**
 * Update the contour polyline data
 * @param annotation - Contour annotation
 * @param viewport - Viewport
 * @param polylineData - Polyline data (points, winding direction and closed)
 * @param transforms - Methods to convert points to/from canvas and world spaces
 * @param options - Options
 *   - decimate: allow to set some parameters to decimate the polyline reducing
 *   the amount of points stored which also affects how fast it will draw the
 *   annotation in a viewport, compute the winding direction, append/remove
 *   contours and create holes. A higher `epsilon` value results in a polyline
 *   with less points.
 */
export default function updateContourPolyline(
  annotation: ContourAnnotation,
  polylineData: {
    points: Types.Point2[];
    closed?: boolean;
    targetWindingDirection?: ContourWindingDirection;
  },
  transforms: {
    canvasToWorld: (point: Types.Point2) => Types.Point3;
    worldToCanvas: (point: Types.Point3) => Types.Point2;
  },
  options?: {
    decimate?: {
      enabled?: boolean;
      epsilon?: number;
    };
  }
) {
  const { canvasToWorld, worldToCanvas } = transforms;
  const { data } = annotation;
  const { targetWindingDirection } = polylineData;
  let { points: polyline } = polylineData;
 
  // Decimate the polyline to reduce tha amount of points
  Iif (options?.decimate?.enabled) {
    polyline = math.polyline.decimate(
      polylineData.points,
      options?.decimate?.epsilon
    );
  }
 
  let { closed } = polylineData;
  const numPoints = polyline.length;
  const polylineWorldPoints = new Array(numPoints);
  const currentPolylineWindingDirection =
    math.polyline.getWindingDirection(polyline);
  const parentAnnotation = getParentAnnotation(annotation) as ContourAnnotation;
 
  Iif (closed === undefined) {
    let currentClosedState = false;
 
    // With two points it is just a line and do not make sense to consider it closed
    if (polyline.length > 3) {
      const lastToFirstDist = math.point.distanceToPointSquared(
        polyline[0],
        polyline[numPoints - 1]
      );
 
      currentClosedState = csUtils.isEqual(0, lastToFirstDist);
    }
 
    closed = currentClosedState;
  }
 
  // It must be in the opposite direction if it is a child annotation (hole)
  let windingDirection = parentAnnotation
    ? parentAnnotation.data.contour.windingDirection * -1
    : targetWindingDirection;
 
  Iif (windingDirection === undefined) {
    windingDirection = currentPolylineWindingDirection;
  }
 
  Eif (windingDirection !== currentPolylineWindingDirection) {
    polyline.reverse();
  }
 
  const handlePoints = data.handles.points.map((p) => worldToCanvas(p));
 
  Iif (handlePoints.length > 2) {
    const currentHandlesWindingDirection =
      math.polyline.getWindingDirection(handlePoints);
 
    if (currentHandlesWindingDirection !== windingDirection) {
      data.handles.points.reverse();
    }
  }
 
  for (let i = 0; i < numPoints; i++) {
    polylineWorldPoints[i] = canvasToWorld(polyline[i]);
  }
 
  data.contour.polyline = polylineWorldPoints;
  data.contour.closed = closed;
  data.contour.windingDirection = windingDirection;
 
  invalidateAnnotation(annotation);
}