mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
chore: Unify math types, utils and functions (#8389)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
e3d1dee9d0
commit
f4dd23fc31
98 changed files with 4291 additions and 3661 deletions
|
@ -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));
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue