export type Point = [x: number, y: number, r: number]; export function add([ax, ay, ar]: Point, [bx, by, br]: Point): Point { return [ax + bx, ay + by, ar + br]; } export function sub([ax, ay, ar]: Point, [bx, by, br]: Point): Point { return [ax - bx, ay - by, ar - br]; } export function smul([x, y, r]: Point, s: number): Point { return [x * s, y * s, r * s]; } export function norm([x, y, r]: Point): Point { return [x / Math.sqrt(x ** 2 + y ** 2), y / Math.sqrt(x ** 2 + y ** 2), r]; } export function rot([x, y, r]: Point, rad: number): Point { return [ Math.cos(rad) * x - Math.sin(rad) * y, Math.sin(rad) * x + Math.cos(rad) * y, r, ]; } export function plerp(a: Point, b: Point, t: number): Point { return add(a, smul(sub(b, a), t)); } export function lerp(a: number, b: number, t: number): number { return a + (b - a) * t; } export function angle(p: Point, p1: Point, p2: Point) { return ( Math.atan2(p2[1] - p[1], p2[0] - p[0]) - Math.atan2(p1[1] - p[1], p1[0] - p[0]) ); } export function normAngle(a: number) { return Math.atan2(Math.sin(a), Math.cos(a)); } export function mag([x, y]: Point) { return Math.sqrt(x ** 2 + y ** 2); } export function dist([ax, ay]: Point, [bx, by]: Point): number { return Math.sqrt((bx - ax) ** 2 + (by - ay) ** 2); } export function getCircleAndPerpendicularLineIntersectionsAtPoint( point: Point, direction: Point, radius: number, ): [Point, Point] { return [ add(point, smul(norm(rot(direction, Math.PI / 2)), radius)), add(point, smul(norm(rot(direction, -Math.PI / 2)), radius)), ]; } export function runLength(ps: Point[]): number { if (ps.length < 2) { return 0; } let len = 0; for (let i = 1; i <= ps.length - 1; i++) { len += dist(ps[i - 1], ps[i]); } len += dist(ps[ps.length - 2], ps[ps.length - 1]); return len; } export const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v)); export function distancePointToSegment(p3: Point, p1: Point, p2: Point) { const sMag = dist(p1, p2); if (sMag === 0) { return dist(p3, p1); } const u = clamp( ((p3[0] - p1[0]) * (p2[0] - p1[0]) + (p3[1] - p1[1]) * (p2[1] - p1[1])) / sMag ** 2, 0, 1, ); const pi: Point = [ p1[0] + u * (p2[0] - p1[0]), p1[1] + u * (p2[1] - p1[1]), p3[2], ]; return dist(pi, p3); }