All files / packages/tools/src/utilities/math/polyline pointCanProjectOnLine.ts

5.26% Statements 1/19
0% Branches 0/8
0% Functions 0/1
5.26% Lines 1/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              1x                                                                                                    
import type { Types } from '@cornerstonejs/core';
import { vec2 } from 'gl-matrix';
 
/**
 * Returns `true` if the point `p` can project onto point (`p1`, `p2`), and if
 * this projected point is less than `proximity` units away.
 */
const pointCanProjectOnLine = (
  p: Types.Point2,
  p1: Types.Point2,
  p2: Types.Point2,
  proximity: number
): boolean => {
  // Perfom checks in order of computational complexity.
  const p1p = [p[0] - p1[0], p[1] - p1[1]];
  const p1p2 = [p2[0] - p1[0], p2[1] - p1[1]];
 
  const dot = p1p[0] * p1p2[0] + p1p[1] * p1p2[1];
 
  // Dot product needs to be positive to be a candidate for projection onto line segment.
  if (dot < 0) {
    return false;
  }
 
  const p1p2Mag = Math.sqrt(p1p2[0] * p1p2[0] + p1p2[1] * p1p2[1]);
 
  if (p1p2Mag === 0) {
    return false;
  }
 
  const projectionVectorMag = dot / p1p2Mag;
  const p1p2UnitVector = [p1p2[0] / p1p2Mag, p1p2[1] / p1p2Mag];
  const projectionVector = [
    p1p2UnitVector[0] * projectionVectorMag,
    p1p2UnitVector[1] * projectionVectorMag,
  ];
  const projectionPoint = <Types.Point2>[
    p1[0] + projectionVector[0],
    p1[1] + projectionVector[1],
  ];
 
  const distance = vec2.distance(p, projectionPoint);
 
  if (distance > proximity) {
    // point is too far away.
    return false;
  }
 
  // Check projects onto line segment.
  if (vec2.distance(p1, projectionPoint) > vec2.distance(p1, p2)) {
    return false;
  }
 
  return true;
};
 
export default pointCanProjectOnLine;