refactor: Update generic constraint Point to use GenericPoint

- Changed existing generic constraints that used LocalPoint | GlobalPoint as Point to now use the unified GenericPoint type.
This commit is contained in:
sunub 2025-04-17 13:16:35 +09:00
parent 71e55dba9f
commit 85cb973936
21 changed files with 153 additions and 211 deletions

View file

@ -1,17 +1,14 @@
import {
vectorCross,
vectorFromPoint,
type GlobalPoint,
type LocalPoint,
type GenericPoint,
} from "@excalidraw/math";
import type { Bounds } from "@excalidraw/element/bounds";
export type LineSegment<P extends LocalPoint | GlobalPoint> = [P, P];
export type LineSegment<P extends GenericPoint> = [P, P];
export function getBBox<P extends LocalPoint | GlobalPoint>(
line: LineSegment<P>,
): Bounds {
export function getBBox<P extends GenericPoint>(line: LineSegment<P>): Bounds {
return [
Math.min(line[0][0], line[1][0]),
Math.min(line[0][1], line[1][1]),
@ -26,10 +23,7 @@ export function doBBoxesIntersect(a: Bounds, b: Bounds) {
const EPSILON = 0.000001;
export function isPointOnLine<P extends GlobalPoint | LocalPoint>(
l: LineSegment<P>,
p: P,
) {
export function isPointOnLine<P extends GenericPoint>(l: LineSegment<P>, p: P) {
const p1 = vectorFromPoint(l[1], l[0]);
const p2 = vectorFromPoint(p, l[0]);
@ -38,7 +32,7 @@ export function isPointOnLine<P extends GlobalPoint | LocalPoint>(
return Math.abs(r) < EPSILON;
}
export function isPointRightOfLine<P extends GlobalPoint | LocalPoint>(
export function isPointRightOfLine<P extends GenericPoint>(
l: LineSegment<P>,
p: P,
) {
@ -48,9 +42,10 @@ export function isPointRightOfLine<P extends GlobalPoint | LocalPoint>(
return vectorCross(p1, p2) < 0;
}
export function isLineSegmentTouchingOrCrossingLine<
P extends GlobalPoint | LocalPoint,
>(a: LineSegment<P>, b: LineSegment<P>) {
export function isLineSegmentTouchingOrCrossingLine<P extends GenericPoint>(
a: LineSegment<P>,
b: LineSegment<P>,
) {
return (
isPointOnLine(a, b[0]) ||
isPointOnLine(a, b[1]) ||
@ -61,7 +56,7 @@ export function isLineSegmentTouchingOrCrossingLine<
}
// https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/
export function doLineSegmentsIntersect<P extends GlobalPoint | LocalPoint>(
export function doLineSegmentsIntersect<P extends GenericPoint>(
a: LineSegment<P>,
b: LineSegment<P>,
) {

View file

@ -5,19 +5,17 @@ import {
pointOnLineSegment,
pointOnPolygon,
polygonFromPoints,
type GlobalPoint,
type LocalPoint,
type Polygon,
} from "@excalidraw/math";
import type { Curve } from "@excalidraw/math";
import type { Curve, GenericPoint } from "@excalidraw/math";
import { pointInEllipse, pointOnEllipse } from "./shape";
import type { Polycurve, Polyline, GeometricShape } from "./shape";
// check if the given point is considered on the given shape's border
export const isPointOnShape = <Point extends GlobalPoint | LocalPoint>(
export const isPointOnShape = <Point extends GenericPoint>(
point: Point,
shape: GeometricShape<Point>,
tolerance = 0,
@ -43,7 +41,7 @@ export const isPointOnShape = <Point extends GlobalPoint | LocalPoint>(
};
// check if the given point is considered inside the element's border
export const isPointInShape = <Point extends GlobalPoint | LocalPoint>(
export const isPointInShape = <Point extends GenericPoint>(
point: Point,
shape: GeometricShape<Point>,
) => {
@ -69,14 +67,14 @@ export const isPointInShape = <Point extends GlobalPoint | LocalPoint>(
};
// check if the given element is in the given bounds
export const isPointInBounds = <Point extends GlobalPoint | LocalPoint>(
export const isPointInBounds = <Point extends GenericPoint>(
point: Point,
bounds: Polygon<Point>,
) => {
return polygonIncludesPoint(point, bounds);
};
const pointOnPolycurve = <Point extends LocalPoint | GlobalPoint>(
const pointOnPolycurve = <Point extends GenericPoint>(
point: Point,
polycurve: Polycurve<Point>,
tolerance: number,
@ -84,7 +82,7 @@ const pointOnPolycurve = <Point extends LocalPoint | GlobalPoint>(
return polycurve.some((curve) => pointOnCurve(point, curve, tolerance));
};
const cubicBezierEquation = <Point extends LocalPoint | GlobalPoint>(
const cubicBezierEquation = <Point extends GenericPoint>(
curve: Curve<Point>,
) => {
const [p0, p1, p2, p3] = curve;
@ -96,7 +94,7 @@ const cubicBezierEquation = <Point extends LocalPoint | GlobalPoint>(
p0[idx] * Math.pow(t, 3);
};
const polyLineFromCurve = <Point extends LocalPoint | GlobalPoint>(
const polyLineFromCurve = <Point extends GenericPoint>(
curve: Curve<Point>,
segments = 10,
): Polyline<Point> => {
@ -118,7 +116,7 @@ const polyLineFromCurve = <Point extends LocalPoint | GlobalPoint>(
return lineSegments;
};
export const pointOnCurve = <Point extends LocalPoint | GlobalPoint>(
export const pointOnCurve = <Point extends GenericPoint>(
point: Point,
curve: Curve<Point>,
threshold: number,
@ -126,7 +124,7 @@ export const pointOnCurve = <Point extends LocalPoint | GlobalPoint>(
return pointOnPolyline(point, polyLineFromCurve(curve), threshold);
};
export const pointOnPolyline = <Point extends LocalPoint | GlobalPoint>(
export const pointOnPolyline = <Point extends GenericPoint>(
point: Point,
polyline: Polyline<Point>,
threshold = 10e-5,

View file

@ -30,8 +30,6 @@ import {
vectorAdd,
vectorFromPoint,
vectorScale,
type GlobalPoint,
type LocalPoint,
} from "@excalidraw/math";
import { getElementAbsoluteCoords } from "@excalidraw/element/bounds";
@ -52,31 +50,36 @@ import type {
ExcalidrawSelectionElement,
ExcalidrawTextElement,
} from "@excalidraw/element/types";
import type { Curve, LineSegment, Polygon, Radians } from "@excalidraw/math";
import type {
Curve,
GenericPoint,
LineSegment,
Polygon,
Radians,
} from "@excalidraw/math";
import type { Drawable, Op } from "roughjs/bin/core";
// a polyline (made up term here) is a line consisting of other line segments
// this corresponds to a straight line element in the editor but it could also
// be used to model other elements
export type Polyline<Point extends GlobalPoint | LocalPoint> =
LineSegment<Point>[];
export type Polyline<Point extends GenericPoint> = LineSegment<Point>[];
// a polycurve is a curve consisting of ther curves, this corresponds to a complex
// curve on the canvas
export type Polycurve<Point extends GlobalPoint | LocalPoint> = Curve<Point>[];
export type Polycurve<Point extends GenericPoint> = Curve<Point>[];
// an ellipse is specified by its center, angle, and its major and minor axes
// but for the sake of simplicity, we've used halfWidth and halfHeight instead
// in replace of semi major and semi minor axes
export type Ellipse<Point extends GlobalPoint | LocalPoint> = {
export type Ellipse<Point extends GenericPoint> = {
center: Point;
angle: Radians;
halfWidth: number;
halfHeight: number;
};
export type GeometricShape<Point extends GlobalPoint | LocalPoint> =
export type GeometricShape<Point extends GenericPoint> =
| {
type: "line";
data: LineSegment<Point>;
@ -113,7 +116,7 @@ type RectangularElement =
| ExcalidrawSelectionElement;
// polygon
export const getPolygonShape = <Point extends GlobalPoint | LocalPoint>(
export const getPolygonShape = <Point extends GenericPoint>(
element: RectangularElement,
): GeometricShape<Point> => {
const { angle, width, height, x, y } = element;
@ -148,7 +151,7 @@ export const getPolygonShape = <Point extends GlobalPoint | LocalPoint>(
};
// return the selection box for an element, possibly rotated as well
export const getSelectionBoxShape = <Point extends GlobalPoint | LocalPoint>(
export const getSelectionBoxShape = <Point extends GenericPoint>(
element: ExcalidrawElement,
elementsMap: ElementsMap,
padding = 10,
@ -178,7 +181,7 @@ export const getSelectionBoxShape = <Point extends GlobalPoint | LocalPoint>(
};
// ellipse
export const getEllipseShape = <Point extends GlobalPoint | LocalPoint>(
export const getEllipseShape = <Point extends GenericPoint>(
element: ExcalidrawEllipseElement,
): GeometricShape<Point> => {
const { width, height, angle, x, y } = element;
@ -209,7 +212,7 @@ export const getCurvePathOps = (shape: Drawable): Op[] => {
};
// linear
export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
export const getCurveShape = <Point extends GenericPoint>(
roughShape: Drawable,
startingPoint: Point = pointFrom(0, 0),
angleInRadian: Radians,
@ -247,7 +250,7 @@ export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
};
};
const polylineFromPoints = <Point extends GlobalPoint | LocalPoint>(
const polylineFromPoints = <Point extends GenericPoint>(
points: Point[],
): Polyline<Point> => {
let previousPoint: Point = points[0];
@ -262,7 +265,7 @@ const polylineFromPoints = <Point extends GlobalPoint | LocalPoint>(
return polyline;
};
export const getFreedrawShape = <Point extends GlobalPoint | LocalPoint>(
export const getFreedrawShape = <Point extends GenericPoint>(
element: ExcalidrawFreeDrawElement,
center: Point,
isClosed: boolean = false,
@ -293,7 +296,7 @@ export const getFreedrawShape = <Point extends GlobalPoint | LocalPoint>(
) as GeometricShape<Point>;
};
export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
export const getClosedCurveShape = <Point extends GenericPoint>(
element: ExcalidrawLinearElement,
roughShape: Drawable,
startingPoint: Point = pointFrom<Point>(0, 0),
@ -359,9 +362,7 @@ export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
* @returns An array of intersections
*/
// TODO: Replace with final rounded rectangle code
export const segmentIntersectRectangleElement = <
Point extends LocalPoint | GlobalPoint,
>(
export const segmentIntersectRectangleElement = <Point extends GenericPoint>(
element: ExcalidrawBindableElement,
segment: LineSegment<Point>,
gap: number = 0,
@ -399,7 +400,7 @@ export const segmentIntersectRectangleElement = <
.filter((i): i is Point => !!i);
};
const distanceToEllipse = <Point extends LocalPoint | GlobalPoint>(
const distanceToEllipse = <Point extends GenericPoint>(
p: Point,
ellipse: Ellipse<Point>,
) => {
@ -456,7 +457,7 @@ const distanceToEllipse = <Point extends LocalPoint | GlobalPoint>(
);
};
export const pointOnEllipse = <Point extends LocalPoint | GlobalPoint>(
export const pointOnEllipse = <Point extends GenericPoint>(
point: Point,
ellipse: Ellipse<Point>,
threshold = PRECISION,
@ -464,7 +465,7 @@ export const pointOnEllipse = <Point extends LocalPoint | GlobalPoint>(
return distanceToEllipse(point, ellipse) <= threshold;
};
export const pointInEllipse = <Point extends LocalPoint | GlobalPoint>(
export const pointInEllipse = <Point extends GenericPoint>(
p: Point,
ellipse: Ellipse<Point>,
) => {
@ -486,7 +487,7 @@ export const pointInEllipse = <Point extends LocalPoint | GlobalPoint>(
);
};
export const ellipseAxes = <Point extends LocalPoint | GlobalPoint>(
export const ellipseAxes = <Point extends GenericPoint>(
ellipse: Ellipse<Point>,
) => {
const widthGreaterThanHeight = ellipse.halfWidth > ellipse.halfHeight;
@ -504,7 +505,7 @@ export const ellipseAxes = <Point extends LocalPoint | GlobalPoint>(
};
};
export const ellipseFocusToCenter = <Point extends LocalPoint | GlobalPoint>(
export const ellipseFocusToCenter = <Point extends GenericPoint>(
ellipse: Ellipse<Point>,
) => {
const { majorAxis, minorAxis } = ellipseAxes(ellipse);
@ -512,7 +513,7 @@ export const ellipseFocusToCenter = <Point extends LocalPoint | GlobalPoint>(
return Math.sqrt(majorAxis ** 2 - minorAxis ** 2);
};
export const ellipseExtremes = <Point extends LocalPoint | GlobalPoint>(
export const ellipseExtremes = <Point extends GenericPoint>(
ellipse: Ellipse<Point>,
) => {
const { center, angle } = ellipse;