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

0% Statements 0/37
0% Branches 0/12
0% Functions 0/5
0% Lines 0/32

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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                                                                                                                                                                                                                                             
import type { Types } from '@cornerstonejs/core';
import * as math from '../math';
import {
  checkIntersection,
  cleanupPolylines,
  convertContourPolylineToCanvasSpace,
  removeDuplicatePoints,
} from './sharedOperations';
import arePolylinesIdentical from '../math/polyline/arePolylinesIdentical';
import type { PolylineInfoCanvas } from './polylineInfoTypes';
import type { ContourSegmentationAnnotation } from '../../types';
import { getViewReferenceFromAnnotation } from './getViewReferenceFromAnnotation';
import { areViewReferencesEqual } from './areViewReferencesEqual';
 
/**
 * Subtracts polylines in set2 from set1, returning only those in set1 that are not present in set2.
 * Comparison is done by polyline and viewReference.
 *
 * @param polylinesSetA The minuend set of PolylineInfoCanvas
 * @param polylinesSetB The subtrahend set of PolylineInfoCanvas
 * @returns Array of PolylineInfoCanvas in set1 but not in set2
 */
export function subtractPolylineSets(
  polylinesSetA: PolylineInfoCanvas[],
  polylinesSetB: PolylineInfoCanvas[]
): PolylineInfoCanvas[] {
  const result: PolylineInfoCanvas[] = [];
  for (let i = 0; i < polylinesSetA.length; i++) {
    let currentPolylines = [polylinesSetA[i]];
    for (let j = 0; j < polylinesSetB.length; j++) {
      const polylineB = polylinesSetB[j];
      const newPolylines: PolylineInfoCanvas[] = [];
      for (const currentPolyline of currentPolylines) {
        if (
          !areViewReferencesEqual(
            currentPolyline.viewReference,
            polylineB.viewReference
          )
        ) {
          // If viewReference does not match, keep the polyline for further checks
          newPolylines.push(currentPolyline);
          continue;
        }
        if (
          arePolylinesIdentical(currentPolyline.polyline, polylineB.polyline)
        ) {
          // Polyline is identical, so it is subtracted (not added to newPolylines)
          continue;
        }
        const intersection = checkIntersection(
          currentPolyline.polyline,
          polylineB.polyline
        );
        if (intersection.hasIntersection && !intersection.isContourHole) {
          const subtractedPolylines = cleanupPolylines(
            math.polyline.subtractPolylines(
              currentPolyline.polyline,
              polylineB.polyline
            )
          );
          for (const subtractedPolyline of subtractedPolylines) {
            const cleaned = removeDuplicatePoints(subtractedPolyline);
            if (cleaned.length >= 3) {
              newPolylines.push({
                polyline: cleaned,
                viewReference: currentPolyline.viewReference,
              });
            }
          }
        } else {
          newPolylines.push({
            polyline: currentPolyline.polyline,
            viewReference: currentPolyline.viewReference,
          });
        }
      }
      currentPolylines = newPolylines;
    }
    result.push(...currentPolylines);
  }
  return result;
}
 
/**
 * Subtracts multiple sets of polylines from a base set progressively.
 * Each set is subtracted from the accumulated result from previous operations.
 */
export function subtractMultiplePolylineSets(
  basePolylineSet: PolylineInfoCanvas[],
  subtractorSets: PolylineInfoCanvas[][]
): PolylineInfoCanvas[] {
  if (subtractorSets.length === 0) {
    return [...basePolylineSet];
  }
  let result = [...basePolylineSet];
  for (let i = 0; i < subtractorSets.length; i++) {
    result = subtractPolylineSets(result, subtractorSets[i]);
  }
  return result;
}
 
/**
 * Subtracts polylines from annotations by extracting their polylines and subtracting intersecting ones.
 * This is a convenience function that works directly with annotation data.
 */
export function subtractAnnotationPolylines(
  baseAnnotations: ContourSegmentationAnnotation[],
  subtractorAnnotations: ContourSegmentationAnnotation[],
  viewport: Types.IViewport
): PolylineInfoCanvas[] {
  const basePolylines = baseAnnotations.map((annotation) => ({
    polyline: convertContourPolylineToCanvasSpace(
      annotation.data.contour.polyline,
      viewport
    ),
    viewReference: getViewReferenceFromAnnotation(annotation),
  }));
  const subtractorPolylines = subtractorAnnotations.map((annotation) => ({
    polyline: convertContourPolylineToCanvasSpace(
      annotation.data.contour.polyline,
      viewport
    ),
    viewReference: getViewReferenceFromAnnotation(annotation),
  }));
  return subtractPolylineSets(basePolylines, subtractorPolylines);
}