Spaces:
Sleeping
Sleeping
| 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); | |
| } | |