import { ellipseLineIntersectionPoints } from "./ellipse";
import { point, pointCenter, pointRotateRads } from "./point";
import { segmentIncludesPoint } from "./segment";
import type { GenericPoint, Line, Radians, Segment } from "./types";
/**
* Create a line from two points.
*
* @param points The two points lying on the line
* @returns The line on which the points lie
*/
export function line
(a: P, b: P): Line
{
return [a, b] as Line
;
}
/**
* Convenient point creation from an array of two points.
*
* @param param0 The array with the two points to convert to a line
* @returns The created line
*/
export function lineFromPointPair
([a, b]: [
P,
P,
]): Line
{
return line(a, b);
}
/**
* TODO
*
* @param pointArray
* @returns
*/
export function lineFromPointArray
(
pointArray: P[],
): Line
| undefined {
return pointArray.length === 2
? line
(pointArray[0], pointArray[1])
: undefined;
}
// return the coordinates resulting from rotating the given line about an origin by an angle in degrees
// note that when the origin is not given, the midpoint of the given line is used as the origin
export function lineRotate(
l: Line,
angle: Radians,
origin?: Point,
): Line {
return line(
pointRotateRads(l[0], origin || pointCenter(l[0], l[1]), angle),
pointRotateRads(l[1], origin || pointCenter(l[0], l[1]), angle),
);
}
/**
* Returns the intersection point of two infinite lines, if any
*
* @param a One of the line to intersect
* @param b Another line to intersect
* @returns The intersection point
*/
export function lineLineIntersectionPoint(
[[x1, y1], [x2, y2]]: Line,
[[x3, y3], [x4, y4]]: Line,
): Point | null {
const a = x1 * y2 - x2 * y1;
const c = x3 * y4 - x4 * y3;
const den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (den === 0) {
return null;
}
const xnum = a * (x3 - x4) - (x1 - x2) * c;
const ynum = a * (y3 - y4) - (y1 - y2) * c;
return point(xnum / den, ynum / den);
}
/**
* Returns the intersection point of a segment and a line
*
* @param l
* @param s
* @returns
*/
export function lineSegmentIntersectionPoints(
l: Line,
s: Segment,
): Point | null {
const candidate = lineLineIntersectionPoint(l, line(s[0], s[1]));
if (!candidate || !segmentIncludesPoint(candidate, s)) {
return null;
}
return candidate;
}
export const lineInterceptsEllipse = ellipseLineIntersectionPoints;