mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Refactoring points
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
parent
8ca4cf3260
commit
b4cb314090
40 changed files with 746 additions and 783 deletions
|
@ -4,6 +4,7 @@ import type {
|
|||
LocalPoint,
|
||||
PolarCoords,
|
||||
Radians,
|
||||
ViewportPoint,
|
||||
} from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
|
||||
|
@ -23,10 +24,9 @@ export const normalizeRadians = (angle: Radians): Radians => {
|
|||
* (x, y) for the center point 0,0 where the first number returned is the radius,
|
||||
* the second is the angle in radians.
|
||||
*/
|
||||
export const cartesian2Polar = <P extends GlobalPoint | LocalPoint>([
|
||||
x,
|
||||
y,
|
||||
]: P): PolarCoords => [Math.hypot(x, y), Math.atan2(y, x)];
|
||||
export const cartesian2Polar = <
|
||||
P extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>([x, y]: P): PolarCoords => [Math.hypot(x, y), Math.atan2(y, x)];
|
||||
|
||||
export function degreesToRadians(degrees: Degrees): Radians {
|
||||
return ((degrees * Math.PI) / 180) as Radians;
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import { cartesian2Polar } from "./angle";
|
||||
import type { GlobalPoint, LocalPoint, SymmetricArc } from "./types";
|
||||
import type {
|
||||
GlobalPoint,
|
||||
LocalPoint,
|
||||
SymmetricArc,
|
||||
ViewportPoint,
|
||||
} from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
|
||||
/**
|
||||
* Determines if a cartesian point lies on a symmetric arc, i.e. an arc which
|
||||
* is part of a circle contour centered on 0, 0.
|
||||
*/
|
||||
export const isPointOnSymmetricArc = <P extends GlobalPoint | LocalPoint>(
|
||||
export const isPointOnSymmetricArc = <
|
||||
P extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(
|
||||
{ radius: arcRadius, startAngle, endAngle }: SymmetricArc,
|
||||
point: P,
|
||||
): boolean => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import type {
|
|||
Radians,
|
||||
Degrees,
|
||||
Vector,
|
||||
ViewportPoint,
|
||||
} from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
import { vectorFromPoint, vectorScale } from "./vector";
|
||||
|
@ -16,7 +17,7 @@ import { vectorFromPoint, vectorScale } from "./vector";
|
|||
* @param y The Y coordinate
|
||||
* @returns The branded and created point
|
||||
*/
|
||||
export function point<Point extends GlobalPoint | LocalPoint>(
|
||||
export function point<Point extends GlobalPoint | LocalPoint | ViewportPoint>(
|
||||
x: number,
|
||||
y: number,
|
||||
): Point {
|
||||
|
@ -29,9 +30,9 @@ export function point<Point extends GlobalPoint | LocalPoint>(
|
|||
* @param numberArray The number array to check and to convert to Point
|
||||
* @returns The point instance
|
||||
*/
|
||||
export function pointFromArray<Point extends GlobalPoint | LocalPoint>(
|
||||
numberArray: number[],
|
||||
): Point | undefined {
|
||||
export function pointFromArray<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(numberArray: number[]): Point | undefined {
|
||||
return numberArray.length === 2
|
||||
? point<Point>(numberArray[0], numberArray[1])
|
||||
: undefined;
|
||||
|
@ -43,9 +44,9 @@ export function pointFromArray<Point extends GlobalPoint | LocalPoint>(
|
|||
* @param pair A number pair to convert to Point
|
||||
* @returns The point instance
|
||||
*/
|
||||
export function pointFromPair<Point extends GlobalPoint | LocalPoint>(
|
||||
pair: [number, number],
|
||||
): Point {
|
||||
export function pointFromPair<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(pair: [number, number]): Point {
|
||||
return pair as Point;
|
||||
}
|
||||
|
||||
|
@ -55,9 +56,9 @@ export function pointFromPair<Point extends GlobalPoint | LocalPoint>(
|
|||
* @param v The vector to convert
|
||||
* @returns The point the vector points at with origin 0,0
|
||||
*/
|
||||
export function pointFromVector<P extends GlobalPoint | LocalPoint>(
|
||||
v: Vector,
|
||||
): P {
|
||||
export function pointFromVector<
|
||||
P extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(v: Vector): P {
|
||||
return v as unknown as P;
|
||||
}
|
||||
|
||||
|
@ -67,7 +68,9 @@ export function pointFromVector<P extends GlobalPoint | LocalPoint>(
|
|||
* @param p The value to attempt verification on
|
||||
* @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 LocalPoint | GlobalPoint | ViewportPoint {
|
||||
return (
|
||||
Array.isArray(p) &&
|
||||
p.length === 2 &&
|
||||
|
@ -86,10 +89,9 @@ export function isPoint(p: unknown): p is LocalPoint | GlobalPoint {
|
|||
* @param b Point The second point to compare
|
||||
* @returns TRUE if the points are sufficiently close to each other
|
||||
*/
|
||||
export function pointsEqual<Point extends GlobalPoint | LocalPoint>(
|
||||
a: Point,
|
||||
b: Point,
|
||||
): boolean {
|
||||
export function pointsEqual<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(a: Point, b: Point): boolean {
|
||||
const abs = Math.abs;
|
||||
return abs(a[0] - b[0]) < PRECISION && abs(a[1] - b[1]) < PRECISION;
|
||||
}
|
||||
|
@ -102,11 +104,9 @@ export function pointsEqual<Point extends GlobalPoint | LocalPoint>(
|
|||
* @param angle The radians to rotate the point by
|
||||
* @returns The rotated point
|
||||
*/
|
||||
export function pointRotateRads<Point extends GlobalPoint | LocalPoint>(
|
||||
[x, y]: Point,
|
||||
[cx, cy]: Point,
|
||||
angle: Radians,
|
||||
): Point {
|
||||
export function pointRotateRads<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>([x, y]: Point, [cx, cy]: Point, angle: Radians): Point {
|
||||
return point(
|
||||
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
|
||||
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy,
|
||||
|
@ -121,11 +121,9 @@ export function pointRotateRads<Point extends GlobalPoint | LocalPoint>(
|
|||
* @param angle The degree to rotate the point by
|
||||
* @returns The rotated point
|
||||
*/
|
||||
export function pointRotateDegs<Point extends GlobalPoint | LocalPoint>(
|
||||
point: Point,
|
||||
center: Point,
|
||||
angle: Degrees,
|
||||
): Point {
|
||||
export function pointRotateDegs<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(point: Point, center: Point, angle: Degrees): Point {
|
||||
return pointRotateRads(point, center, degreesToRadians(angle));
|
||||
}
|
||||
|
||||
|
@ -143,8 +141,8 @@ export function pointRotateDegs<Point extends GlobalPoint | LocalPoint>(
|
|||
*/
|
||||
// TODO 99% of use is translating between global and local coords, which need to be formalized
|
||||
export function pointTranslate<
|
||||
From extends GlobalPoint | LocalPoint,
|
||||
To extends GlobalPoint | LocalPoint,
|
||||
From extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
To extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(p: From, v: Vector = [0, 0] as Vector): To {
|
||||
return point(p[0] + v[0], p[1] + v[1]);
|
||||
}
|
||||
|
@ -156,8 +154,14 @@ export function pointTranslate<
|
|||
* @param b The other point to create the middle point for
|
||||
* @returns The middle point
|
||||
*/
|
||||
export function pointCenter<P extends LocalPoint | GlobalPoint>(a: P, b: P): P {
|
||||
return point((a[0] + b[0]) / 2, (a[1] + b[1]) / 2);
|
||||
export function pointCenter<P extends LocalPoint | GlobalPoint | ViewportPoint>(
|
||||
...p: P[]
|
||||
): P {
|
||||
return pointFromPair(
|
||||
p
|
||||
.reduce((mid, x) => [mid[0] + x[0], mid[1] + x[1]], [0, 0])
|
||||
.map((x) => x / p.length) as [number, number],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,10 +172,9 @@ export function pointCenter<P extends LocalPoint | GlobalPoint>(a: P, b: P): P {
|
|||
* @param b The other point to act like the vector to translate by
|
||||
* @returns
|
||||
*/
|
||||
export function pointAdd<Point extends LocalPoint | GlobalPoint>(
|
||||
a: Point,
|
||||
b: Point,
|
||||
): Point {
|
||||
export function pointAdd<
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(a: Point, b: Point): Point {
|
||||
return point(a[0] + b[0], a[1] + b[1]);
|
||||
}
|
||||
|
||||
|
@ -183,10 +186,9 @@ export function pointAdd<Point extends LocalPoint | GlobalPoint>(
|
|||
* @param b The point which will act like a vector
|
||||
* @returns The resulting point
|
||||
*/
|
||||
export function pointSubtract<Point extends LocalPoint | GlobalPoint>(
|
||||
a: Point,
|
||||
b: Point,
|
||||
): Point {
|
||||
export function pointSubtract<
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(a: Point, b: Point): Point {
|
||||
return point(a[0] - b[0], a[1] - b[1]);
|
||||
}
|
||||
|
||||
|
@ -197,10 +199,9 @@ export function pointSubtract<Point extends LocalPoint | GlobalPoint>(
|
|||
* @param b Second point
|
||||
* @returns The euclidean distance between the two points.
|
||||
*/
|
||||
export function pointDistance<P extends LocalPoint | GlobalPoint>(
|
||||
a: P,
|
||||
b: P,
|
||||
): number {
|
||||
export function pointDistance<
|
||||
P extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(a: P, b: P): number {
|
||||
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
||||
}
|
||||
|
||||
|
@ -213,10 +214,9 @@ export function pointDistance<P extends LocalPoint | GlobalPoint>(
|
|||
* @param b Second point
|
||||
* @returns The euclidean distance between the two points.
|
||||
*/
|
||||
export function pointDistanceSq<P extends LocalPoint | GlobalPoint>(
|
||||
a: P,
|
||||
b: P,
|
||||
): number {
|
||||
export function pointDistanceSq<
|
||||
P extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(a: P, b: P): number {
|
||||
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,9 @@ export function pointDistanceSq<P extends LocalPoint | GlobalPoint>(
|
|||
* @param multiplier The scaling factor
|
||||
* @returns
|
||||
*/
|
||||
export const pointScaleFromOrigin = <P extends GlobalPoint | LocalPoint>(
|
||||
export const pointScaleFromOrigin = <
|
||||
P extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(
|
||||
p: P,
|
||||
mid: P,
|
||||
multiplier: number,
|
||||
|
@ -243,7 +245,9 @@ export const pointScaleFromOrigin = <P extends GlobalPoint | LocalPoint>(
|
|||
* @param r The other point to compare against
|
||||
* @returns TRUE if q is indeed between p and r
|
||||
*/
|
||||
export const isPointWithinBounds = <P extends GlobalPoint | LocalPoint>(
|
||||
export const isPointWithinBounds = <
|
||||
P extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(
|
||||
p: P,
|
||||
q: P,
|
||||
r: P,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { pointsEqual } from "./point";
|
||||
import { lineSegment, pointOnLineSegment } from "./segment";
|
||||
import type { GlobalPoint, LocalPoint, Polygon } from "./types";
|
||||
import type { GlobalPoint, LocalPoint, Polygon, ViewportPoint } from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
|
||||
export function polygon<Point extends GlobalPoint | LocalPoint>(
|
||||
|
@ -9,13 +9,15 @@ export function polygon<Point extends GlobalPoint | LocalPoint>(
|
|||
return polygonClose(points) as Polygon<Point>;
|
||||
}
|
||||
|
||||
export function polygonFromPoints<Point extends GlobalPoint | LocalPoint>(
|
||||
points: Point[],
|
||||
) {
|
||||
export function polygonFromPoints<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(points: Point[]) {
|
||||
return polygonClose(points) as Polygon<Point>;
|
||||
}
|
||||
|
||||
export const polygonIncludesPoint = <Point extends LocalPoint | GlobalPoint>(
|
||||
export const polygonIncludesPoint = <
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(
|
||||
point: Point,
|
||||
polygon: Polygon<Point>,
|
||||
) => {
|
||||
|
@ -40,7 +42,9 @@ export const polygonIncludesPoint = <Point extends LocalPoint | GlobalPoint>(
|
|||
return inside;
|
||||
};
|
||||
|
||||
export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>(
|
||||
export const pointOnPolygon = <
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(
|
||||
p: Point,
|
||||
poly: Polygon<Point>,
|
||||
threshold = PRECISION,
|
||||
|
@ -57,7 +61,7 @@ export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>(
|
|||
return on;
|
||||
};
|
||||
|
||||
function polygonClose<Point extends LocalPoint | GlobalPoint>(
|
||||
function polygonClose<Point extends LocalPoint | GlobalPoint | ViewportPoint>(
|
||||
polygon: Point[],
|
||||
) {
|
||||
return polygonIsClosed(polygon)
|
||||
|
@ -65,8 +69,8 @@ function polygonClose<Point extends LocalPoint | GlobalPoint>(
|
|||
: ([...polygon, polygon[0]] as Polygon<Point>);
|
||||
}
|
||||
|
||||
function polygonIsClosed<Point extends LocalPoint | GlobalPoint>(
|
||||
polygon: Point[],
|
||||
) {
|
||||
function polygonIsClosed<
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(polygon: Point[]) {
|
||||
return pointsEqual(polygon[0], polygon[polygon.length - 1]);
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ export const rangeIntersection = (
|
|||
* Determine if a value is inside a range.
|
||||
*
|
||||
* @param value The value to check
|
||||
* @param range The range
|
||||
* @returns
|
||||
* @param range The range to check
|
||||
* @returns TRUE if the value is in range
|
||||
*/
|
||||
export const rangeIncludesValue = (
|
||||
value: number,
|
||||
|
@ -80,3 +80,13 @@ export const rangeIncludesValue = (
|
|||
): boolean => {
|
||||
return value >= min && value <= max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the distance between the start and end of the range.
|
||||
*
|
||||
* @param range The range of which to measure the extent of
|
||||
* @returns The scalar distance or extent of the start and end of the range
|
||||
*/
|
||||
export function rangeExtent([a, b]: InclusiveRange) {
|
||||
return Math.abs(a - b);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,13 @@ import {
|
|||
pointFromVector,
|
||||
pointRotateRads,
|
||||
} from "./point";
|
||||
import type { GlobalPoint, LineSegment, LocalPoint, Radians } from "./types";
|
||||
import type {
|
||||
GlobalPoint,
|
||||
LineSegment,
|
||||
LocalPoint,
|
||||
Radians,
|
||||
ViewportPoint,
|
||||
} from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
import {
|
||||
vectorAdd,
|
||||
|
@ -20,7 +26,7 @@ import {
|
|||
* @param points The two points delimiting the line segment on each end
|
||||
* @returns The line segment delineated by the points
|
||||
*/
|
||||
export function lineSegment<P extends GlobalPoint | LocalPoint>(
|
||||
export function lineSegment<P extends GlobalPoint | LocalPoint | ViewportPoint>(
|
||||
a: P,
|
||||
b: P,
|
||||
): LineSegment<P> {
|
||||
|
@ -57,7 +63,9 @@ export const isLineSegment = <Point extends GlobalPoint | LocalPoint>(
|
|||
* @param origin
|
||||
* @returns
|
||||
*/
|
||||
export const lineSegmentRotate = <Point extends LocalPoint | GlobalPoint>(
|
||||
export const lineSegmentRotate = <
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(
|
||||
l: LineSegment<Point>,
|
||||
angle: Radians,
|
||||
origin?: Point,
|
||||
|
@ -72,7 +80,9 @@ export const lineSegmentRotate = <Point extends LocalPoint | GlobalPoint>(
|
|||
* Calculates the point two line segments with a definite start and end point
|
||||
* intersect at.
|
||||
*/
|
||||
export const segmentsIntersectAt = <Point extends GlobalPoint | LocalPoint>(
|
||||
export const segmentsIntersectAt = <
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(
|
||||
a: Readonly<LineSegment<Point>>,
|
||||
b: Readonly<LineSegment<Point>>,
|
||||
): Point | null => {
|
||||
|
@ -105,7 +115,9 @@ export const segmentsIntersectAt = <Point extends GlobalPoint | LocalPoint>(
|
|||
return null;
|
||||
};
|
||||
|
||||
export const pointOnLineSegment = <Point extends LocalPoint | GlobalPoint>(
|
||||
export const pointOnLineSegment = <
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(
|
||||
point: Point,
|
||||
line: LineSegment<Point>,
|
||||
threshold = PRECISION,
|
||||
|
@ -119,7 +131,9 @@ export const pointOnLineSegment = <Point extends LocalPoint | GlobalPoint>(
|
|||
return distance < threshold;
|
||||
};
|
||||
|
||||
export const distanceToLineSegment = <Point extends LocalPoint | GlobalPoint>(
|
||||
export const distanceToLineSegment = <
|
||||
Point extends LocalPoint | GlobalPoint | ViewportPoint,
|
||||
>(
|
||||
point: Point,
|
||||
line: LineSegment<Point>,
|
||||
) => {
|
||||
|
|
|
@ -43,6 +43,13 @@ export type LocalPoint = [x: number, y: number] & {
|
|||
_brand: "excalimath__localpoint";
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a 2D position on the browser viewport.
|
||||
*/
|
||||
export type ViewportPoint = [x: number, y: number] & {
|
||||
_brand: "excalimath_viewportpoint";
|
||||
};
|
||||
|
||||
// Line
|
||||
|
||||
/**
|
||||
|
@ -57,7 +64,10 @@ export type Line<P extends GlobalPoint | LocalPoint> = [p: P, q: P] & {
|
|||
* line that is bounded by two distinct end points, and
|
||||
* contains every point on the line that is between its endpoints.
|
||||
*/
|
||||
export type LineSegment<P extends GlobalPoint | LocalPoint> = [a: P, b: P] & {
|
||||
export type LineSegment<P extends GlobalPoint | LocalPoint | ViewportPoint> = [
|
||||
a: P,
|
||||
b: P,
|
||||
] & {
|
||||
_brand: "excalimath_linesegment";
|
||||
};
|
||||
|
||||
|
@ -93,9 +103,10 @@ export type Triangle<P extends GlobalPoint | LocalPoint> = [
|
|||
* A polygon is a closed shape by connecting the given points
|
||||
* rectangles and diamonds are modelled by polygons
|
||||
*/
|
||||
export type Polygon<Point extends GlobalPoint | LocalPoint> = Point[] & {
|
||||
_brand: "excalimath_polygon";
|
||||
};
|
||||
export type Polygon<Point extends GlobalPoint | LocalPoint | ViewportPoint> =
|
||||
Point[] & {
|
||||
_brand: "excalimath_polygon";
|
||||
};
|
||||
|
||||
//
|
||||
// Curve
|
||||
|
@ -104,7 +115,7 @@ export type Polygon<Point extends GlobalPoint | LocalPoint> = Point[] & {
|
|||
/**
|
||||
* Cubic bezier curve with four control points
|
||||
*/
|
||||
export type Curve<Point extends GlobalPoint | LocalPoint> = [
|
||||
export type Curve<Point extends GlobalPoint | LocalPoint | ViewportPoint> = [
|
||||
Point,
|
||||
Point,
|
||||
Point,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { GlobalPoint, LocalPoint, Vector } from "./types";
|
||||
import type { GlobalPoint, LocalPoint, Vector, ViewportPoint } from "./types";
|
||||
|
||||
/**
|
||||
* Create a vector from the x and y coordiante elements.
|
||||
|
@ -23,10 +23,9 @@ export function vector(
|
|||
* @param origin The origin point in a given coordiante system
|
||||
* @returns The created vector from the point and the origin
|
||||
*/
|
||||
export function vectorFromPoint<Point extends GlobalPoint | LocalPoint>(
|
||||
p: Point,
|
||||
origin: Point = [0, 0] as Point,
|
||||
): Vector {
|
||||
export function vectorFromPoint<
|
||||
Point extends GlobalPoint | LocalPoint | ViewportPoint,
|
||||
>(p: Point, origin: Point = [0, 0] as Point): Vector {
|
||||
return vector(p[0] - origin[0], p[1] - origin[1]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue