All files / tools/src/utilities/contourSegmentation getIntersectingAnnotations.ts

0% Statements 0/21
0% Branches 0/8
0% Functions 0/2
0% Lines 0/19

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                                                                                                                                                                                     
import type { Types } from '@cornerstonejs/core';
import type { ContourSegmentationAnnotation } from '../../types/ContourSegmentationAnnotation';
import * as math from '../math';
 
/**
 * Finds all existing contour segmentation annotations that intersect with the
 * `sourcePolyline` or ones that `sourcePolyline` is inside of (potential holes).
 * The comparison is done in canvas space.
 *
 * @param viewport - The viewport context for coordinate conversions.
 * @param sourcePolyline - The polyline of the newly completed contour in canvas space.
 * @param contourSegmentationAnnotations - An array of existing contour segmentations to check against.
 * @returns An array of objects containing the `targetAnnotation`, its `targetPolyline` in canvas space,
 *          and a boolean `isContourHole` indicating if the source polyline is inside the target.
 */
function findAllIntersectingContours(
  viewport: Types.IViewport,
  sourcePolyline: Types.Point2[],
  contourSegmentationAnnotations: ContourSegmentationAnnotation[]
): Array<{
  targetAnnotation: ContourSegmentationAnnotation;
  targetPolyline: Types.Point2[];
  isContourHole: boolean;
}> {
  const intersectingContours: Array<{
    targetAnnotation: ContourSegmentationAnnotation;
    targetPolyline: Types.Point2[];
    isContourHole: boolean;
  }> = [];
 
  const sourceAABB = math.polyline.getAABB(sourcePolyline);
 
  for (let i = 0; i < contourSegmentationAnnotations.length; i++) {
    const targetAnnotation = contourSegmentationAnnotations[i];
    const targetPolyline = convertContourPolylineToCanvasSpace(
      targetAnnotation.data.contour.polyline,
      viewport
    );
 
    const targetAABB = math.polyline.getAABB(targetPolyline);
    const aabbIntersect = math.aabb.intersectAABB(sourceAABB, targetAABB);
 
    if (!aabbIntersect) {
      continue;
    }
 
    const lineSegmentsIntersect = math.polyline.intersectPolyline(
      sourcePolyline,
      targetPolyline
    );
    // A contour hole is when AABBs intersect, polylines don't intersect, and source is inside target.
    const isContourHole =
      !lineSegmentsIntersect &&
      math.polyline.containsPoints(targetPolyline, sourcePolyline);
 
    if (lineSegmentsIntersect || isContourHole) {
      intersectingContours.push({
        targetAnnotation,
        targetPolyline,
        isContourHole,
      });
    }
  }
 
  return intersectingContours;
}
 
/**
 * Converts a 3D polyline (in world coordinates) to a 2D polyline (in canvas space)
 * for a specific viewport.
 *
 * @param polyline - An array of 3D points representing the polyline in world coordinates.
 * @param viewport - The viewport used for projection.
 * @returns An array of 2D points representing the polyline in canvas coordinates.
 */
function convertContourPolylineToCanvasSpace(
  polyline: Types.Point3[],
  viewport: Types.IViewport
): Types.Point2[] {
  const numPoints = polyline.length;
  const projectedPolyline = new Array(numPoints);
 
  for (let i = 0; i < numPoints; i++) {
    projectedPolyline[i] = viewport.worldToCanvas(polyline[i]);
  }
 
  return projectedPolyline;
}
 
export { findAllIntersectingContours };