import { invariant } from "../excalidraw/utils"; import { line, linesIntersectAt } from "./line"; import { pointFrom } from "./point"; import { distanceToLineSegment, lineSegment, lineSegmentIntersectionPoints, } from "./segment"; import type { GlobalPoint, Line, LineSegment, LocalPoint, Rectangle, } from "./types"; export function rectangle

( topLeft: P, bottomRight: P, ): Rectangle

{ return [topLeft, bottomRight] as Rectangle

; } export function rectangleFromPair

( pair: [a: P, b: P], ): Rectangle

{ return pair as Rectangle

; } export function rectangleFromArray

( pointArray: P[], ): Rectangle

{ invariant( pointArray.length === 4, "Point array contains more or less points to create a rectangle from", ); return pointArray as Rectangle

; } export function rectangleDistanceFromPoint< Point extends GlobalPoint | LocalPoint, >(r: Rectangle, p: Point): number { const sides = [ lineSegment(pointFrom(r[0][0], r[0][1]), pointFrom(r[1][0], r[0][1])), lineSegment(pointFrom(r[1][0], r[0][1]), pointFrom(r[1][0], r[1][1])), lineSegment(pointFrom(r[1][0], r[1][1]), pointFrom(r[0][0], r[1][1])), lineSegment(pointFrom(r[0][0], r[1][1]), pointFrom(r[0][0], r[0][1])), ]; return Math.min(...sides.map((side) => distanceToLineSegment(p, side))); } export function rectangleIntersectLine( r: Rectangle, l: Line, ): Point[] { return [ line(r[0], pointFrom(r[1][0], r[0][1])), line(pointFrom(r[1][0], r[0][1]), r[1]), line(r[1], pointFrom(r[0][0], r[1][1])), line(pointFrom(r[0][0], r[1][1]), r[0]), ] .map((s) => linesIntersectAt(l, s)) .filter((i): i is Point => !!i); } export function rectangleIntersectLineSegment< Point extends LocalPoint | GlobalPoint, >(r: Rectangle, l: LineSegment): Point[] { return [ lineSegment(r[0], pointFrom(r[1][0], r[0][1])), lineSegment(pointFrom(r[1][0], r[0][1]), r[1]), lineSegment(r[1], pointFrom(r[0][0], r[1][1])), lineSegment(pointFrom(r[0][0], r[1][1]), r[0]), ] .map((s) => lineSegmentIntersectionPoints(l, s)) .filter((i): i is Point => !!i); }