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,14 +1,9 @@
import { import { type GenericPoint, pointFromPair } from "@excalidraw/math";
pointFromPair, import { pointFrom } from "@excalidraw/math";
type GlobalPoint,
type LocalPoint,
} from "@excalidraw/math";
import type { NullableGridSize } from "@excalidraw/excalidraw/types"; import type { NullableGridSize } from "@excalidraw/excalidraw/types";
export const getSizeFromPoints = ( export const getSizeFromPoints = (points: readonly GenericPoint[]) => {
points: readonly (GlobalPoint | LocalPoint)[],
) => {
const xs = points.map((point) => point[0]); const xs = points.map((point) => point[0]);
const ys = points.map((point) => point[1]); const ys = points.map((point) => point[1]);
return { return {
@ -18,7 +13,7 @@ export const getSizeFromPoints = (
}; };
/** @arg dimension, 0 for rescaling only x, 1 for y */ /** @arg dimension, 0 for rescaling only x, 1 for y */
export const rescalePoints = <Point extends GlobalPoint | LocalPoint>( export const rescalePoints = <Point extends GenericPoint>(
dimension: 0 | 1, dimension: 0 | 1,
newSize: number, newSize: number,
points: readonly Point[], points: readonly Point[],
@ -65,16 +60,16 @@ export const rescalePoints = <Point extends GlobalPoint | LocalPoint>(
}; };
// TODO: Rounding this point causes some shake when free drawing // TODO: Rounding this point causes some shake when free drawing
export const getGridPoint = ( export const getGridPoint = <Point extends GenericPoint>(
x: number, x: number,
y: number, y: number,
gridSize: NullableGridSize, gridSize: NullableGridSize,
): [number, number] => { ): Point => {
if (gridSize) { if (gridSize) {
return [ return pointFrom(
Math.round(x / gridSize) * gridSize, Math.round(x / gridSize) * gridSize,
Math.round(y / gridSize) * gridSize, Math.round(y / gridSize) * gridSize,
]; );
} }
return [x, y]; return pointFrom(x, y);
}; };

View file

@ -19,9 +19,9 @@ import { isPointInShape, isPointOnShape } from "@excalidraw/utils/collision";
import { type GeometricShape, getPolygonShape } from "@excalidraw/utils/shape"; import { type GeometricShape, getPolygonShape } from "@excalidraw/utils/shape";
import type { import type {
GenericPoint,
GlobalPoint, GlobalPoint,
LineSegment, LineSegment,
LocalPoint,
Polygon, Polygon,
Radians, Radians,
} from "@excalidraw/math"; } from "@excalidraw/math";
@ -72,7 +72,7 @@ export const shouldTestInside = (element: ExcalidrawElement) => {
return isDraggableFromInside || isImageElement(element); return isDraggableFromInside || isImageElement(element);
}; };
export type HitTestArgs<Point extends GlobalPoint | LocalPoint> = { export type HitTestArgs<Point extends GenericPoint> = {
x: number; x: number;
y: number; y: number;
element: ExcalidrawElement; element: ExcalidrawElement;
@ -81,7 +81,7 @@ export type HitTestArgs<Point extends GlobalPoint | LocalPoint> = {
frameNameBound?: FrameNameBounds | null; frameNameBound?: FrameNameBounds | null;
}; };
export const hitElementItself = <Point extends GlobalPoint | LocalPoint>({ export const hitElementItself = <Point extends GenericPoint>({
x, x,
y, y,
element, element,
@ -127,9 +127,7 @@ export const hitElementBoundingBox = (
); );
}; };
export const hitElementBoundingBoxOnly = < export const hitElementBoundingBoxOnly = <Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint,
>(
hitArgs: HitTestArgs<Point>, hitArgs: HitTestArgs<Point>,
elementsMap: ElementsMap, elementsMap: ElementsMap,
) => { ) => {
@ -145,7 +143,7 @@ export const hitElementBoundingBoxOnly = <
); );
}; };
export const hitElementBoundText = <Point extends GlobalPoint | LocalPoint>( export const hitElementBoundText = <Point extends GenericPoint>(
x: number, x: number,
y: number, y: number,
textShape: GeometricShape<Point> | null, textShape: GeometricShape<Point> | null,

View file

@ -9,6 +9,7 @@ import {
vectorCross, vectorCross,
vectorFromPoint, vectorFromPoint,
vectorScale, vectorScale,
type GenericPoint,
type GlobalPoint, type GlobalPoint,
type LocalPoint, type LocalPoint,
} from "@excalidraw/math"; } from "@excalidraw/math";
@ -1642,7 +1643,7 @@ const pathTo = (start: Node, node: Node) => {
return path; return path;
}; };
const m_dist = (a: GlobalPoint | LocalPoint, b: GlobalPoint | LocalPoint) => const m_dist = (a: GenericPoint, b: GenericPoint) =>
Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
/** /**
@ -2291,7 +2292,7 @@ const getHoveredElement = (
const gridAddressesEqual = (a: GridAddress, b: GridAddress): boolean => const gridAddressesEqual = (a: GridAddress, b: GridAddress): boolean =>
a[0] === b[0] && a[1] === b[1]; a[0] === b[0] && a[1] === b[1];
export const validateElbowPoints = <P extends GlobalPoint | LocalPoint>( export const validateElbowPoints = <P extends GenericPoint>(
points: readonly P[], points: readonly P[],
tolerance: number = DEDUP_TRESHOLD, tolerance: number = DEDUP_TRESHOLD,
) => ) =>

View file

@ -13,10 +13,10 @@ import {
} from "@excalidraw/math"; } from "@excalidraw/math";
import type { import type {
LocalPoint,
GlobalPoint, GlobalPoint,
Triangle, Triangle,
Vector, Vector,
GenericPoint,
} from "@excalidraw/math"; } from "@excalidraw/math";
import { getCenterForBounds, type Bounds } from "./bounds"; import { getCenterForBounds, type Bounds } from "./bounds";
@ -43,12 +43,10 @@ export const vectorToHeading = (vec: Vector): Heading => {
return HEADING_UP; return HEADING_UP;
}; };
export const headingForPoint = <P extends GlobalPoint | LocalPoint>( export const headingForPoint = <P extends GenericPoint>(p: P, o: P) =>
p: P, vectorToHeading(vectorFromPoint<P>(p, o));
o: P,
) => vectorToHeading(vectorFromPoint<P>(p, o));
export const headingForPointIsHorizontal = <P extends GlobalPoint | LocalPoint>( export const headingForPointIsHorizontal = <P extends GenericPoint>(
p: P, p: P,
o: P, o: P,
) => headingIsHorizontal(headingForPoint<P>(p, o)); ) => headingIsHorizontal(headingForPoint<P>(p, o));

View file

@ -7,7 +7,7 @@ import {
import { SIDE_RESIZING_THRESHOLD } from "@excalidraw/common"; import { SIDE_RESIZING_THRESHOLD } from "@excalidraw/common";
import type { GlobalPoint, LineSegment, LocalPoint } from "@excalidraw/math"; import type { GenericPoint, LineSegment } from "@excalidraw/math";
import type { AppState, Device, Zoom } from "@excalidraw/excalidraw/types"; import type { AppState, Device, Zoom } from "@excalidraw/excalidraw/types";
@ -43,7 +43,7 @@ const isInsideTransformHandle = (
y >= transformHandle[1] && y >= transformHandle[1] &&
y <= transformHandle[1] + transformHandle[3]; y <= transformHandle[1] + transformHandle[3];
export const resizeTest = <Point extends GlobalPoint | LocalPoint>( export const resizeTest = <Point extends GenericPoint>(
element: NonDeletedExcalidrawElement, element: NonDeletedExcalidrawElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,
appState: AppState, appState: AppState,
@ -152,9 +152,7 @@ export const getElementWithTransformHandleType = (
}, null as { element: NonDeletedExcalidrawElement; transformHandleType: MaybeTransformHandleType } | null); }, null as { element: NonDeletedExcalidrawElement; transformHandleType: MaybeTransformHandleType } | null);
}; };
export const getTransformHandleTypeFromCoords = < export const getTransformHandleTypeFromCoords = <Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint,
>(
[x1, y1, x2, y2]: Bounds, [x1, y1, x2, y2]: Bounds,
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
@ -271,7 +269,7 @@ export const getCursorForResizingElement = (resizingElement: {
return cursor ? `${cursor}-resize` : ""; return cursor ? `${cursor}-resize` : "";
}; };
const getSelectionBorders = <Point extends LocalPoint | GlobalPoint>( const getSelectionBorders = <Point extends GenericPoint>(
[x1, y1]: Point, [x1, y1]: Point,
[x2, y2]: Point, [x2, y2]: Point,
center: Point, center: Point,

View file

@ -13,8 +13,7 @@ import {
pointFromPair, pointFromPair,
pointRotateRads, pointRotateRads,
pointsEqual, pointsEqual,
type GlobalPoint, type GenericPoint,
type LocalPoint,
} from "@excalidraw/math"; } from "@excalidraw/math";
import { import {
getClosedCurveShape, getClosedCurveShape,
@ -46,7 +45,7 @@ import type {
* get the pure geometric shape of an excalidraw elementw * get the pure geometric shape of an excalidraw elementw
* which is then used for hit detection * which is then used for hit detection
*/ */
export const getElementShape = <Point extends GlobalPoint | LocalPoint>( export const getElementShape = <Point extends GenericPoint>(
element: ExcalidrawElement, element: ExcalidrawElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,
): GeometricShape<Point> => { ): GeometricShape<Point> => {
@ -98,7 +97,7 @@ export const getElementShape = <Point extends GlobalPoint | LocalPoint>(
} }
}; };
export const getBoundTextShape = <Point extends GlobalPoint | LocalPoint>( export const getBoundTextShape = <Point extends GenericPoint>(
element: ExcalidrawElement, element: ExcalidrawElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,
): GeometricShape<Point> | null => { ): GeometricShape<Point> | null => {
@ -126,9 +125,7 @@ export const getBoundTextShape = <Point extends GlobalPoint | LocalPoint>(
return null; return null;
}; };
export const getControlPointsForBezierCurve = < export const getControlPointsForBezierCurve = <P extends GenericPoint>(
P extends GlobalPoint | LocalPoint,
>(
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
endPoint: P, endPoint: P,
) => { ) => {
@ -170,7 +167,7 @@ export const getControlPointsForBezierCurve = <
return controlPoints; return controlPoints;
}; };
export const getBezierXY = <P extends GlobalPoint | LocalPoint>( export const getBezierXY = <P extends GenericPoint>(
p0: P, p0: P,
p1: P, p1: P,
p2: P, p2: P,
@ -187,7 +184,7 @@ export const getBezierXY = <P extends GlobalPoint | LocalPoint>(
return pointFrom(tx, ty); return pointFrom(tx, ty);
}; };
const getPointsInBezierCurve = <P extends GlobalPoint | LocalPoint>( const getPointsInBezierCurve = <P extends GenericPoint>(
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
endPoint: P, endPoint: P,
) => { ) => {
@ -217,7 +214,7 @@ const getPointsInBezierCurve = <P extends GlobalPoint | LocalPoint>(
return pointsOnCurve; return pointsOnCurve;
}; };
const getBezierCurveArcLengths = <P extends GlobalPoint | LocalPoint>( const getBezierCurveArcLengths = <P extends GenericPoint>(
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
endPoint: P, endPoint: P,
) => { ) => {
@ -236,7 +233,7 @@ const getBezierCurveArcLengths = <P extends GlobalPoint | LocalPoint>(
return arcLengths; return arcLengths;
}; };
export const getBezierCurveLength = <P extends GlobalPoint | LocalPoint>( export const getBezierCurveLength = <P extends GenericPoint>(
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
endPoint: P, endPoint: P,
) => { ) => {
@ -245,7 +242,7 @@ export const getBezierCurveLength = <P extends GlobalPoint | LocalPoint>(
}; };
// This maps interval to actual interval t on the curve so that when t = 0.5, its actually the point at 50% of the length // This maps interval to actual interval t on the curve so that when t = 0.5, its actually the point at 50% of the length
export const mapIntervalToBezierT = <P extends GlobalPoint | LocalPoint>( export const mapIntervalToBezierT = <P extends GenericPoint>(
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
endPoint: P, endPoint: P,
interval: number, // The interval between 0 to 1 for which you want to find the point on the curve, interval: number, // The interval between 0 to 1 for which you want to find the point on the curve,
@ -340,7 +337,7 @@ export const aabbForElement = (
return bounds; return bounds;
}; };
export const pointInsideBounds = <P extends GlobalPoint | LocalPoint>( export const pointInsideBounds = <P extends GenericPoint>(
p: P, p: P,
bounds: Bounds, bounds: Bounds,
): boolean => ): boolean =>

View file

@ -2,8 +2,8 @@ import oc from "open-color";
import { import {
pointFrom, pointFrom,
type GlobalPoint, type GlobalPoint,
type LocalPoint,
type Radians, type Radians,
type GenericPoint,
} from "@excalidraw/math"; } from "@excalidraw/math";
import { import {
@ -144,7 +144,7 @@ const renderLinearElementPointHighlight = (
context.restore(); context.restore();
}; };
const highlightPoint = <Point extends LocalPoint | GlobalPoint>( const highlightPoint = <Point extends GenericPoint>(
point: Point, point: Point,
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
appState: InteractiveCanvasAppState, appState: InteractiveCanvasAppState,
@ -211,7 +211,7 @@ const strokeDiamondWithRotation = (
context.restore(); context.restore();
}; };
const renderSingleLinearPoint = <Point extends GlobalPoint | LocalPoint>( const renderSingleLinearPoint = <Point extends GenericPoint>(
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
appState: InteractiveCanvasAppState, appState: InteractiveCanvasAppState,
point: Point, point: Point,

View file

@ -1,4 +1,4 @@
import { pointFrom, type GlobalPoint, type LocalPoint } from "@excalidraw/math"; import { pointFrom, type GenericPoint } from "@excalidraw/math";
import { THEME } from "@excalidraw/common"; import { THEME } from "@excalidraw/common";
@ -88,7 +88,7 @@ const drawPointerSnapLine = (
} }
}; };
const drawCross = <Point extends LocalPoint | GlobalPoint>( const drawCross = <Point extends GenericPoint>(
[x, y]: Point, [x, y]: Point,
appState: InteractiveCanvasAppState, appState: InteractiveCanvasAppState,
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
@ -109,7 +109,7 @@ const drawCross = <Point extends LocalPoint | GlobalPoint>(
context.restore(); context.restore();
}; };
const drawLine = <Point extends LocalPoint | GlobalPoint>( const drawLine = <Point extends GenericPoint>(
from: Point, from: Point,
to: Point, to: Point,
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
@ -120,7 +120,7 @@ const drawLine = <Point extends LocalPoint | GlobalPoint>(
context.stroke(); context.stroke();
}; };
const drawGapLine = <Point extends LocalPoint | GlobalPoint>( const drawGapLine = <Point extends GenericPoint>(
from: Point, from: Point,
to: Point, to: Point,
direction: "horizontal" | "vertical", direction: "horizontal" | "vertical",

View file

@ -1,12 +1,6 @@
import { PRECISION } from "./utils"; import { PRECISION } from "./utils";
import type { import type { Degrees, GenericPoint, PolarCoords, Radians } from "./types";
Degrees,
GlobalPoint,
LocalPoint,
PolarCoords,
Radians,
} from "./types";
// TODO: Simplify with modulo and fix for angles beyond 4*Math.PI and - 4*Math.PI // TODO: Simplify with modulo and fix for angles beyond 4*Math.PI and - 4*Math.PI
export const normalizeRadians = (angle: Radians): Radians => { export const normalizeRadians = (angle: Radians): Radians => {
@ -24,7 +18,7 @@ export const normalizeRadians = (angle: Radians): Radians => {
* (x, y) for the center point 0,0 where the first number returned is the radius, * (x, y) for the center point 0,0 where the first number returned is the radius,
* the second is the angle in radians. * the second is the angle in radians.
*/ */
export const cartesian2Polar = <P extends GlobalPoint | LocalPoint>([ export const cartesian2Polar = <P extends GenericPoint>([
x, x,
y, y,
]: P): PolarCoords => [ ]: P): PolarCoords => [

View file

@ -3,7 +3,7 @@ import type { Bounds } from "@excalidraw/element/bounds";
import { isPoint, pointDistance, pointFrom } from "./point"; import { isPoint, pointDistance, pointFrom } from "./point";
import { rectangle, rectangleIntersectLineSegment } from "./rectangle"; import { rectangle, rectangleIntersectLineSegment } from "./rectangle";
import type { Curve, GlobalPoint, LineSegment, LocalPoint } from "./types"; import type { Curve, GenericPoint, LineSegment } from "./types";
/** /**
* *
@ -13,7 +13,7 @@ import type { Curve, GlobalPoint, LineSegment, LocalPoint } from "./types";
* @param d * @param d
* @returns * @returns
*/ */
export function curve<Point extends GlobalPoint | LocalPoint>( export function curve<Point extends GenericPoint>(
a: Point, a: Point,
b: Point, b: Point,
c: Point, c: Point,
@ -82,7 +82,7 @@ function solve(
return [t0, s0]; return [t0, s0];
} }
const bezierEquation = <Point extends GlobalPoint | LocalPoint>( const bezierEquation = <Point extends GenericPoint>(
c: Curve<Point>, c: Curve<Point>,
t: number, t: number,
) => ) =>
@ -100,9 +100,10 @@ const bezierEquation = <Point extends GlobalPoint | LocalPoint>(
/** /**
* Computes the intersection between a cubic spline and a line segment. * Computes the intersection between a cubic spline and a line segment.
*/ */
export function curveIntersectLineSegment< export function curveIntersectLineSegment<Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint, c: Curve<Point>,
>(c: Curve<Point>, l: LineSegment<Point>): Point[] { l: LineSegment<Point>,
): Point[] {
// Optimize by doing a cheap bounding box check first // Optimize by doing a cheap bounding box check first
const bounds = curveBounds(c); const bounds = curveBounds(c);
if ( if (
@ -188,7 +189,7 @@ export function curveIntersectLineSegment<
* @param maxLevel * @param maxLevel
* @returns * @returns
*/ */
export function curveClosestPoint<Point extends GlobalPoint | LocalPoint>( export function curveClosestPoint<Point extends GenericPoint>(
c: Curve<Point>, c: Curve<Point>,
p: Point, p: Point,
tolerance: number = 1e-3, tolerance: number = 1e-3,
@ -245,7 +246,7 @@ export function curveClosestPoint<Point extends GlobalPoint | LocalPoint>(
* @param c The curve to test * @param c The curve to test
* @param p The point to measure from * @param p The point to measure from
*/ */
export function curvePointDistance<Point extends GlobalPoint | LocalPoint>( export function curvePointDistance<Point extends GenericPoint>(
c: Curve<Point>, c: Curve<Point>,
p: Point, p: Point,
) { ) {
@ -261,9 +262,7 @@ export function curvePointDistance<Point extends GlobalPoint | LocalPoint>(
/** /**
* Determines if the parameter is a Curve * Determines if the parameter is a Curve
*/ */
export function isCurve<P extends GlobalPoint | LocalPoint>( export function isCurve<P extends GenericPoint>(v: unknown): v is Curve<P> {
v: unknown,
): v is Curve<P> {
return ( return (
Array.isArray(v) && Array.isArray(v) &&
v.length === 4 && v.length === 4 &&
@ -274,9 +273,7 @@ export function isCurve<P extends GlobalPoint | LocalPoint>(
); );
} }
function curveBounds<Point extends GlobalPoint | LocalPoint>( function curveBounds<Point extends GenericPoint>(c: Curve<Point>): Bounds {
c: Curve<Point>,
): Bounds {
const [P0, P1, P2, P3] = c; const [P0, P1, P2, P3] = c;
const x = [P0[0], P1[0], P2[0], P3[0]]; const x = [P0[0], P1[0], P2[0], P3[0]];
const y = [P0[1], P1[1], P2[1], P3[1]]; const y = [P0[1], P1[1], P2[1], P3[1]];

View file

@ -13,13 +13,7 @@ import {
vectorScale, vectorScale,
} from "./vector"; } from "./vector";
import type { import type { Ellipse, GenericPoint, Line, LineSegment } from "./types";
Ellipse,
GlobalPoint,
Line,
LineSegment,
LocalPoint,
} from "./types";
/** /**
* Construct an Ellipse object from the parameters * Construct an Ellipse object from the parameters
@ -30,7 +24,7 @@ import type {
* @param halfHeight Half of the height of a non-slanted version of the ellipse * @param halfHeight Half of the height of a non-slanted version of the ellipse
* @returns The constructed Ellipse object * @returns The constructed Ellipse object
*/ */
export function ellipse<Point extends GlobalPoint | LocalPoint>( export function ellipse<Point extends GenericPoint>(
center: Point, center: Point,
halfWidth: number, halfWidth: number,
halfHeight: number, halfHeight: number,
@ -49,7 +43,7 @@ export function ellipse<Point extends GlobalPoint | LocalPoint>(
* @param ellipse The ellipse to compare against * @param ellipse The ellipse to compare against
* @returns TRUE if the point is inside or on the outline of the ellipse * @returns TRUE if the point is inside or on the outline of the ellipse
*/ */
export const ellipseIncludesPoint = <Point extends GlobalPoint | LocalPoint>( export const ellipseIncludesPoint = <Point extends GenericPoint>(
p: Point, p: Point,
ellipse: Ellipse<Point>, ellipse: Ellipse<Point>,
) => { ) => {
@ -69,7 +63,7 @@ export const ellipseIncludesPoint = <Point extends GlobalPoint | LocalPoint>(
* @param threshold The distance to consider a point close enough to be "on" the outline * @param threshold The distance to consider a point close enough to be "on" the outline
* @returns TRUE if the point is on the ellise outline * @returns TRUE if the point is on the ellise outline
*/ */
export const ellipseTouchesPoint = <Point extends GlobalPoint | LocalPoint>( export const ellipseTouchesPoint = <Point extends GenericPoint>(
point: Point, point: Point,
ellipse: Ellipse<Point>, ellipse: Ellipse<Point>,
threshold = PRECISION, threshold = PRECISION,
@ -85,9 +79,7 @@ export const ellipseTouchesPoint = <Point extends GlobalPoint | LocalPoint>(
* @param ellipse The ellipse to calculate the distance to * @param ellipse The ellipse to calculate the distance to
* @returns The eucledian distance * @returns The eucledian distance
*/ */
export const ellipseDistanceFromPoint = < export const ellipseDistanceFromPoint = <Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint,
>(
p: Point, p: Point,
ellipse: Ellipse<Point>, ellipse: Ellipse<Point>,
): number => { ): number => {
@ -140,9 +132,10 @@ export const ellipseDistanceFromPoint = <
* Calculate a maximum of two intercept points for a line going throug an * Calculate a maximum of two intercept points for a line going throug an
* ellipse. * ellipse.
*/ */
export function ellipseSegmentInterceptPoints< export function ellipseSegmentInterceptPoints<Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint, e: Readonly<Ellipse<Point>>,
>(e: Readonly<Ellipse<Point>>, s: Readonly<LineSegment<Point>>): Point[] { s: Readonly<LineSegment<Point>>,
): Point[] {
const rx = e.halfWidth; const rx = e.halfWidth;
const ry = e.halfHeight; const ry = e.halfHeight;
@ -194,9 +187,7 @@ export function ellipseSegmentInterceptPoints<
return intersections; return intersections;
} }
export function ellipseLineIntersectionPoints< export function ellipseLineIntersectionPoints<Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint,
>(
{ center, halfWidth, halfHeight }: Ellipse<Point>, { center, halfWidth, halfHeight }: Ellipse<Point>,
[g, h]: Line<Point>, [g, h]: Line<Point>,
): Point[] { ): Point[] {

View file

@ -1,6 +1,6 @@
import { pointFrom } from "./point"; import { pointFrom } from "./point";
import type { GlobalPoint, Line, LocalPoint } from "./types"; import type { GenericPoint, Line } from "./types";
/** /**
* Create a line from two points. * Create a line from two points.
@ -8,7 +8,7 @@ import type { GlobalPoint, Line, LocalPoint } from "./types";
* @param points The two points lying on the line * @param points The two points lying on the line
* @returns The line on which the points lie * @returns The line on which the points lie
*/ */
export function line<P extends GlobalPoint | LocalPoint>(a: P, b: P): Line<P> { export function line<P extends GenericPoint>(a: P, b: P): Line<P> {
return [a, b] as Line<P>; return [a, b] as Line<P>;
} }
@ -20,7 +20,7 @@ export function line<P extends GlobalPoint | LocalPoint>(a: P, b: P): Line<P> {
* @param b * @param b
* @returns * @returns
*/ */
export function linesIntersectAt<Point extends GlobalPoint | LocalPoint>( export function linesIntersectAt<Point extends GenericPoint>(
a: Line<Point>, a: Line<Point>,
b: Line<Point>, b: Line<Point>,
): Point | null { ): Point | null {

View file

@ -2,13 +2,7 @@ import { degreesToRadians } from "./angle";
import { PRECISION } from "./utils"; import { PRECISION } from "./utils";
import { vectorFromPoint, vectorScale } from "./vector"; import { vectorFromPoint, vectorScale } from "./vector";
import type { import type { Radians, Degrees, Vector, GenericPoint } from "./types";
LocalPoint,
GlobalPoint,
Radians,
Degrees,
Vector,
} from "./types";
/** /**
* Create a properly typed Point instance from the X and Y coordinates. * Create a properly typed Point instance from the X and Y coordinates.
@ -17,7 +11,7 @@ import type {
* @param y The Y coordinate * @param y The Y coordinate
* @returns The branded and created point * @returns The branded and created point
*/ */
export function pointFrom<Point extends GlobalPoint | LocalPoint>( export function pointFrom<Point extends GenericPoint>(
x: number, x: number,
y: number, y: number,
): Point { ): Point {
@ -30,7 +24,7 @@ export function pointFrom<Point extends GlobalPoint | LocalPoint>(
* @param numberArray The number array to check and to convert to Point * @param numberArray The number array to check and to convert to Point
* @returns The point instance * @returns The point instance
*/ */
export function pointFromArray<Point extends GlobalPoint | LocalPoint>( export function pointFromArray<Point extends GenericPoint>(
numberArray: number[], numberArray: number[],
): Point | undefined { ): Point | undefined {
return numberArray.length === 2 return numberArray.length === 2
@ -44,7 +38,7 @@ export function pointFromArray<Point extends GlobalPoint | LocalPoint>(
* @param pair A number pair to convert to Point * @param pair A number pair to convert to Point
* @returns The point instance * @returns The point instance
*/ */
export function pointFromPair<Point extends GlobalPoint | LocalPoint>( export function pointFromPair<Point extends GenericPoint>(
pair: [number, number], pair: [number, number],
): Point { ): Point {
return pair as Point; return pair as Point;
@ -56,7 +50,7 @@ export function pointFromPair<Point extends GlobalPoint | LocalPoint>(
* @param v The vector to convert * @param v The vector to convert
* @returns The point the vector points at with origin 0,0 * @returns The point the vector points at with origin 0,0
*/ */
export function pointFromVector<P extends GlobalPoint | LocalPoint>( export function pointFromVector<P extends GenericPoint>(
v: Vector, v: Vector,
offset: P = pointFrom(0, 0), offset: P = pointFrom(0, 0),
): P { ): P {
@ -69,7 +63,7 @@ export function pointFromVector<P extends GlobalPoint | LocalPoint>(
* @param p The value to attempt verification on * @param p The value to attempt verification on
* @returns TRUE if the provided value has the shape of a local or global point * @returns TRUE if the provided value has the shape of a local or global point
*/ */
export function isPoint(p: unknown): p is LocalPoint | GlobalPoint { export function isPoint(p: unknown): p is GenericPoint {
return ( return (
Array.isArray(p) && Array.isArray(p) &&
p.length === 2 && p.length === 2 &&
@ -88,7 +82,7 @@ export function isPoint(p: unknown): p is LocalPoint | GlobalPoint {
* @param b Point The second point to compare * @param b Point The second point to compare
* @returns TRUE if the points are sufficiently close to each other * @returns TRUE if the points are sufficiently close to each other
*/ */
export function pointsEqual<Point extends GlobalPoint | LocalPoint>( export function pointsEqual<Point extends GenericPoint>(
a: Point, a: Point,
b: Point, b: Point,
): boolean { ): boolean {
@ -104,7 +98,7 @@ export function pointsEqual<Point extends GlobalPoint | LocalPoint>(
* @param angle The radians to rotate the point by * @param angle The radians to rotate the point by
* @returns The rotated point * @returns The rotated point
*/ */
export function pointRotateRads<Point extends GlobalPoint | LocalPoint>( export function pointRotateRads<Point extends GenericPoint>(
[x, y]: Point, [x, y]: Point,
[cx, cy]: Point, [cx, cy]: Point,
angle: Radians, angle: Radians,
@ -123,7 +117,7 @@ export function pointRotateRads<Point extends GlobalPoint | LocalPoint>(
* @param angle The degree to rotate the point by * @param angle The degree to rotate the point by
* @returns The rotated point * @returns The rotated point
*/ */
export function pointRotateDegs<Point extends GlobalPoint | LocalPoint>( export function pointRotateDegs<Point extends GenericPoint>(
point: Point, point: Point,
center: Point, center: Point,
angle: Degrees, angle: Degrees,
@ -145,8 +139,8 @@ export function pointRotateDegs<Point extends GlobalPoint | LocalPoint>(
*/ */
// TODO 99% of use is translating between global and local coords, which need to be formalized // TODO 99% of use is translating between global and local coords, which need to be formalized
export function pointTranslate< export function pointTranslate<
From extends GlobalPoint | LocalPoint, From extends GenericPoint,
To extends GlobalPoint | LocalPoint, To extends GenericPoint,
>(p: From, v: Vector = [0, 0] as Vector): To { >(p: From, v: Vector = [0, 0] as Vector): To {
return pointFrom(p[0] + v[0], p[1] + v[1]); return pointFrom(p[0] + v[0], p[1] + v[1]);
} }
@ -158,7 +152,7 @@ export function pointTranslate<
* @param b The other point to create the middle point for * @param b The other point to create the middle point for
* @returns The middle point * @returns The middle point
*/ */
export function pointCenter<P extends LocalPoint | GlobalPoint>(a: P, b: P): P { export function pointCenter<P extends GenericPoint>(a: P, b: P): P {
return pointFrom((a[0] + b[0]) / 2, (a[1] + b[1]) / 2); return pointFrom((a[0] + b[0]) / 2, (a[1] + b[1]) / 2);
} }
@ -169,10 +163,7 @@ export function pointCenter<P extends LocalPoint | GlobalPoint>(a: P, b: P): P {
* @param b Second point * @param b Second point
* @returns The euclidean distance between the two points. * @returns The euclidean distance between the two points.
*/ */
export function pointDistance<P extends LocalPoint | GlobalPoint>( export function pointDistance<P extends GenericPoint>(a: P, b: P): number {
a: P,
b: P,
): number {
return Math.hypot(b[0] - a[0], b[1] - a[1]); return Math.hypot(b[0] - a[0], b[1] - a[1]);
} }
@ -185,10 +176,7 @@ export function pointDistance<P extends LocalPoint | GlobalPoint>(
* @param b Second point * @param b Second point
* @returns The euclidean distance between the two points. * @returns The euclidean distance between the two points.
*/ */
export function pointDistanceSq<P extends LocalPoint | GlobalPoint>( export function pointDistanceSq<P extends GenericPoint>(a: P, b: P): number {
a: P,
b: P,
): number {
const xDiff = b[0] - a[0]; const xDiff = b[0] - a[0];
const yDiff = b[1] - a[1]; const yDiff = b[1] - a[1];
@ -203,7 +191,7 @@ export function pointDistanceSq<P extends LocalPoint | GlobalPoint>(
* @param multiplier The scaling factor * @param multiplier The scaling factor
* @returns * @returns
*/ */
export const pointScaleFromOrigin = <P extends GlobalPoint | LocalPoint>( export const pointScaleFromOrigin = <P extends GenericPoint>(
p: P, p: P,
mid: P, mid: P,
multiplier: number, multiplier: number,
@ -218,7 +206,7 @@ export const pointScaleFromOrigin = <P extends GlobalPoint | LocalPoint>(
* @param r The other point to compare against * @param r The other point to compare against
* @returns TRUE if q is indeed between p and r * @returns TRUE if q is indeed between p and r
*/ */
export const isPointWithinBounds = <P extends GlobalPoint | LocalPoint>( export const isPointWithinBounds = <P extends GenericPoint>(
p: P, p: P,
q: P, q: P,
r: P, r: P,

View file

@ -2,21 +2,17 @@ import { pointsEqual } from "./point";
import { lineSegment, pointOnLineSegment } from "./segment"; import { lineSegment, pointOnLineSegment } from "./segment";
import { PRECISION } from "./utils"; import { PRECISION } from "./utils";
import type { GlobalPoint, LocalPoint, Polygon } from "./types"; import type { GenericPoint, Polygon } from "./types";
export function polygon<Point extends GlobalPoint | LocalPoint>( export function polygon<Point extends GenericPoint>(...points: Point[]) {
...points: Point[]
) {
return polygonClose(points) as Polygon<Point>; return polygonClose(points) as Polygon<Point>;
} }
export function polygonFromPoints<Point extends GlobalPoint | LocalPoint>( export function polygonFromPoints<Point extends GenericPoint>(points: Point[]) {
points: Point[],
) {
return polygonClose(points) as Polygon<Point>; return polygonClose(points) as Polygon<Point>;
} }
export const polygonIncludesPoint = <Point extends LocalPoint | GlobalPoint>( export const polygonIncludesPoint = <Point extends GenericPoint>(
point: Point, point: Point,
polygon: Polygon<Point>, polygon: Polygon<Point>,
) => { ) => {
@ -69,7 +65,7 @@ export const polygonIncludesPointNonZero = <Point extends [number, number]>(
return windingNumber !== 0; return windingNumber !== 0;
}; };
export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>( export const pointOnPolygon = <Point extends GenericPoint>(
p: Point, p: Point,
poly: Polygon<Point>, poly: Polygon<Point>,
threshold = PRECISION, threshold = PRECISION,
@ -86,16 +82,12 @@ export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>(
return on; return on;
}; };
function polygonClose<Point extends LocalPoint | GlobalPoint>( function polygonClose<Point extends GenericPoint>(polygon: Point[]) {
polygon: Point[],
) {
return polygonIsClosed(polygon) return polygonIsClosed(polygon)
? polygon ? polygon
: ([...polygon, polygon[0]] as Polygon<Point>); : ([...polygon, polygon[0]] as Polygon<Point>);
} }
function polygonIsClosed<Point extends LocalPoint | GlobalPoint>( function polygonIsClosed<Point extends GenericPoint>(polygon: Point[]) {
polygon: Point[],
) {
return pointsEqual(polygon[0], polygon[polygon.length - 1]); return pointsEqual(polygon[0], polygon[polygon.length - 1]);
} }

View file

@ -1,18 +1,19 @@
import { pointFrom } from "./point"; import { pointFrom } from "./point";
import { lineSegment, lineSegmentIntersectionPoints } from "./segment"; import { lineSegment, lineSegmentIntersectionPoints } from "./segment";
import type { GlobalPoint, LineSegment, LocalPoint, Rectangle } from "./types"; import type { GenericPoint, LineSegment, Rectangle } from "./types";
export function rectangle<P extends GlobalPoint | LocalPoint>( export function rectangle<P extends GenericPoint>(
topLeft: P, topLeft: P,
bottomRight: P, bottomRight: P,
): Rectangle<P> { ): Rectangle<P> {
return [topLeft, bottomRight] as Rectangle<P>; return [topLeft, bottomRight] as Rectangle<P>;
} }
export function rectangleIntersectLineSegment< export function rectangleIntersectLineSegment<Point extends GenericPoint>(
Point extends LocalPoint | GlobalPoint, r: Rectangle<Point>,
>(r: Rectangle<Point>, l: LineSegment<Point>): Point[] { l: LineSegment<Point>,
): Point[] {
return [ return [
lineSegment(r[0], pointFrom(r[1][0], r[0][1])), lineSegment(r[0], pointFrom(r[1][0], r[0][1])),
lineSegment(pointFrom(r[1][0], r[0][1]), r[1]), lineSegment(pointFrom(r[1][0], r[0][1]), r[1]),

View file

@ -14,7 +14,7 @@ import {
vectorSubtract, vectorSubtract,
} from "./vector"; } from "./vector";
import type { GlobalPoint, LineSegment, LocalPoint, Radians } from "./types"; import type { GenericPoint, LineSegment, Radians } from "./types";
/** /**
* Create a line segment from two points. * Create a line segment from two points.
@ -22,7 +22,7 @@ import type { GlobalPoint, LineSegment, LocalPoint, Radians } from "./types";
* @param points The two points delimiting the line segment on each end * @param points The two points delimiting the line segment on each end
* @returns The line segment delineated by the points * @returns The line segment delineated by the points
*/ */
export function lineSegment<P extends GlobalPoint | LocalPoint>( export function lineSegment<P extends GenericPoint>(
a: P, a: P,
b: P, b: P,
): LineSegment<P> { ): LineSegment<P> {
@ -34,7 +34,7 @@ export function lineSegment<P extends GlobalPoint | LocalPoint>(
* @param segment * @param segment
* @returns * @returns
*/ */
export const isLineSegment = <Point extends GlobalPoint | LocalPoint>( export const isLineSegment = <Point extends GenericPoint>(
segment: unknown, segment: unknown,
): segment is LineSegment<Point> => ): segment is LineSegment<Point> =>
Array.isArray(segment) && Array.isArray(segment) &&
@ -51,7 +51,7 @@ export const isLineSegment = <Point extends GlobalPoint | LocalPoint>(
* @param origin * @param origin
* @returns * @returns
*/ */
export const lineSegmentRotate = <Point extends LocalPoint | GlobalPoint>( export const lineSegmentRotate = <Point extends GenericPoint>(
l: LineSegment<Point>, l: LineSegment<Point>,
angle: Radians, angle: Radians,
origin?: Point, origin?: Point,
@ -66,7 +66,7 @@ export const lineSegmentRotate = <Point extends LocalPoint | GlobalPoint>(
* Calculates the point two line segments with a definite start and end point * Calculates the point two line segments with a definite start and end point
* intersect at. * intersect at.
*/ */
export const segmentsIntersectAt = <Point extends GlobalPoint | LocalPoint>( export const segmentsIntersectAt = <Point extends GenericPoint>(
a: Readonly<LineSegment<Point>>, a: Readonly<LineSegment<Point>>,
b: Readonly<LineSegment<Point>>, b: Readonly<LineSegment<Point>>,
): Point | null => { ): Point | null => {
@ -99,7 +99,7 @@ export const segmentsIntersectAt = <Point extends GlobalPoint | LocalPoint>(
return null; return null;
}; };
export const pointOnLineSegment = <Point extends LocalPoint | GlobalPoint>( export const pointOnLineSegment = <Point extends GenericPoint>(
point: Point, point: Point,
line: LineSegment<Point>, line: LineSegment<Point>,
threshold = PRECISION, threshold = PRECISION,
@ -113,7 +113,7 @@ export const pointOnLineSegment = <Point extends LocalPoint | GlobalPoint>(
return distance < threshold; return distance < threshold;
}; };
export const distanceToLineSegment = <Point extends LocalPoint | GlobalPoint>( export const distanceToLineSegment = <Point extends GenericPoint>(
point: Point, point: Point,
line: LineSegment<Point>, line: LineSegment<Point>,
) => { ) => {
@ -158,9 +158,7 @@ export const distanceToLineSegment = <Point extends LocalPoint | GlobalPoint>(
* @param s * @param s
* @returns * @returns
*/ */
export function lineSegmentIntersectionPoints< export function lineSegmentIntersectionPoints<Point extends GenericPoint>(
Point extends GlobalPoint | LocalPoint,
>(
l: LineSegment<Point>, l: LineSegment<Point>,
s: LineSegment<Point>, s: LineSegment<Point>,
threshold?: number, threshold?: number,

View file

@ -1,4 +1,4 @@
import type { GlobalPoint, LocalPoint, Triangle } from "./types"; import type { GenericPoint, Triangle } from "./types";
// Types // Types
@ -11,7 +11,7 @@ import type { GlobalPoint, LocalPoint, Triangle } from "./types";
* @param p The point to test whether is in the triangle * @param p The point to test whether is in the triangle
* @returns TRUE if the point is inside of the triangle * @returns TRUE if the point is inside of the triangle
*/ */
export function triangleIncludesPoint<P extends GlobalPoint | LocalPoint>( export function triangleIncludesPoint<P extends GenericPoint>(
[a, b, c]: Triangle<P>, [a, b, c]: Triangle<P>,
p: P, p: P,
): boolean { ): boolean {

View file

@ -1,4 +1,4 @@
import type { GlobalPoint, LocalPoint, Vector } from "./types"; import type { GenericPoint, Vector } from "./types";
/** /**
* Create a vector from the x and y coordiante elements. * Create a vector from the x and y coordiante elements.
@ -23,7 +23,7 @@ export function vector(
* @param origin The origin point in a given coordiante system * @param origin The origin point in a given coordiante system
* @returns The created vector from the point and the origin * @returns The created vector from the point and the origin
*/ */
export function vectorFromPoint<Point extends GlobalPoint | LocalPoint>( export function vectorFromPoint<Point extends GenericPoint>(
p: Point, p: Point,
origin: Point = [0, 0] as Point, origin: Point = [0, 0] as Point,
): Vector { ): Vector {

View file

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

View file

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

View file

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