chore: Unify math types, utils and functions (#8389)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Márk Tolmács 2024-09-03 00:23:38 +02:00 committed by GitHub
parent e3d1dee9d0
commit f4dd23fc31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
98 changed files with 4291 additions and 3661 deletions

View file

@ -1,20 +1,26 @@
import type { Point, Polygon, GeometricShape } from "./geometry/shape";
import type { Polycurve, Polyline } from "./geometry/shape";
import {
pointInEllipse,
pointInPolygon,
pointOnCurve,
pointOnEllipse,
pointOnLine,
pointOnPolycurve,
type GeometricShape,
} from "./geometry/shape";
import type { Curve } from "../math";
import {
lineSegment,
point,
polygonIncludesPoint,
pointOnLineSegment,
pointOnPolygon,
pointOnPolyline,
close,
} from "./geometry/geometry";
polygonFromPoints,
type GlobalPoint,
type LocalPoint,
type Polygon,
} from "../math";
// check if the given point is considered on the given shape's border
export const isPointOnShape = (
export const isPointOnShape = <Point extends GlobalPoint | LocalPoint>(
point: Point,
shape: GeometricShape,
shape: GeometricShape<Point>,
tolerance = 0,
) => {
// get the distance from the given point to the given element
@ -25,7 +31,7 @@ export const isPointOnShape = (
case "ellipse":
return pointOnEllipse(point, shape.data, tolerance);
case "line":
return pointOnLine(point, shape.data, tolerance);
return pointOnLineSegment(point, shape.data, tolerance);
case "polyline":
return pointOnPolyline(point, shape.data, tolerance);
case "curve":
@ -38,10 +44,13 @@ export const isPointOnShape = (
};
// check if the given point is considered inside the element's border
export const isPointInShape = (point: Point, shape: GeometricShape) => {
export const isPointInShape = <Point extends GlobalPoint | LocalPoint>(
point: Point,
shape: GeometricShape<Point>,
) => {
switch (shape.type) {
case "polygon":
return pointInPolygon(point, shape.data);
return polygonIncludesPoint(point, shape.data);
case "line":
return false;
case "curve":
@ -49,8 +58,8 @@ export const isPointInShape = (point: Point, shape: GeometricShape) => {
case "ellipse":
return pointInEllipse(point, shape.data);
case "polyline": {
const polygon = close(shape.data.flat()) as Polygon;
return pointInPolygon(point, polygon);
const polygon = polygonFromPoints(shape.data.flat());
return polygonIncludesPoint(point, polygon);
}
case "polycurve": {
return false;
@ -61,6 +70,67 @@ export const isPointInShape = (point: Point, shape: GeometricShape) => {
};
// check if the given element is in the given bounds
export const isPointInBounds = (point: Point, bounds: Polygon) => {
return pointInPolygon(point, bounds);
export const isPointInBounds = <Point extends GlobalPoint | LocalPoint>(
point: Point,
bounds: Polygon<Point>,
) => {
return polygonIncludesPoint(point, bounds);
};
const pointOnPolycurve = <Point extends LocalPoint | GlobalPoint>(
point: Point,
polycurve: Polycurve<Point>,
tolerance: number,
) => {
return polycurve.some((curve) => pointOnCurve(point, curve, tolerance));
};
const cubicBezierEquation = <Point extends LocalPoint | GlobalPoint>(
curve: Curve<Point>,
) => {
const [p0, p1, p2, p3] = curve;
// B(t) = p0 * (1-t)^3 + 3p1 * t * (1-t)^2 + 3p2 * t^2 * (1-t) + p3 * t^3
return (t: number, idx: number) =>
Math.pow(1 - t, 3) * p3[idx] +
3 * t * Math.pow(1 - t, 2) * p2[idx] +
3 * Math.pow(t, 2) * (1 - t) * p1[idx] +
p0[idx] * Math.pow(t, 3);
};
const polyLineFromCurve = <Point extends LocalPoint | GlobalPoint>(
curve: Curve<Point>,
segments = 10,
): Polyline<Point> => {
const equation = cubicBezierEquation(curve);
let startingPoint = [equation(0, 0), equation(0, 1)] as Point;
const lineSegments: Polyline<Point> = [];
let t = 0;
const increment = 1 / segments;
for (let i = 0; i < segments; i++) {
t += increment;
if (t <= 1) {
const nextPoint: Point = point(equation(t, 0), equation(t, 1));
lineSegments.push(lineSegment(startingPoint, nextPoint));
startingPoint = nextPoint;
}
}
return lineSegments;
};
export const pointOnCurve = <Point extends LocalPoint | GlobalPoint>(
point: Point,
curve: Curve<Point>,
threshold: number,
) => {
return pointOnPolyline(point, polyLineFromCurve(curve), threshold);
};
export const pointOnPolyline = <Point extends LocalPoint | GlobalPoint>(
point: Point,
polyline: Polyline<Point>,
threshold = 10e-5,
) => {
return polyline.some((line) => pointOnLineSegment(point, line, threshold));
};