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

75.86% Statements 22/29
41.66% Branches 5/12
100% Functions 1/1
75% Lines 21/28

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                                                                                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;
  },
  options?: {
    decimate?: {
      enabled?: boolean;
      epsilon?: number;
    };
  }
) {
  const { canvasToWorld } = 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 currentWindingDirection = 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 = currentWindingDirection;
  } else Eif (windingDirection !== currentWindingDirection) {
    polyline.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);
}