refactor: point() -> pointFrom() to fix compiler issue (#8578)

This commit is contained in:
David Luzar 2024-10-01 21:27:17 +02:00 committed by Mark Tolmacs
parent 0c02972695
commit b4d8b04d9e
No known key found for this signature in database
50 changed files with 843 additions and 718 deletions

View file

@ -15,7 +15,7 @@ import { isBindingElement, isLinearElement } from "../element/typeChecks";
import type { AppState } from "../types"; import type { AppState } from "../types";
import { resetCursor } from "../cursor"; import { resetCursor } from "../cursor";
import { StoreAction } from "../store"; import { StoreAction } from "../store";
import { pathIsALoop, point } from "../../math"; import { pathIsALoop, pointFrom } from "../../math";
export const actionFinalize = register({ export const actionFinalize = register({
name: "finalize", name: "finalize",
@ -114,7 +114,7 @@ export const actionFinalize = register({
mutateElement(multiPointElement, { mutateElement(multiPointElement, {
points: linePoints.map((p, index) => points: linePoints.map((p, index) =>
index === linePoints.length - 1 index === linePoints.length - 1
? point(firstPoint[0], firstPoint[1]) ? pointFrom(firstPoint[0], firstPoint[1])
: p, : p,
), ),
}); });

View file

@ -9,7 +9,7 @@ import {
} from "../tests/test-utils"; } from "../tests/test-utils";
import { API } from "../tests/helpers/api"; import { API } from "../tests/helpers/api";
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { point, radians } from "../../math"; import { pointFrom, radians } from "../../math";
import { actionFlipHorizontal, actionFlipVertical } from "./actionFlip"; import { actionFlipHorizontal, actionFlipVertical } from "./actionFlip";
import { Keyboard, Pointer, UI } from "../tests/helpers/ui"; import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
import { vi } from "vitest"; import { vi } from "vitest";
@ -144,9 +144,9 @@ const createLinearElementWithCurveInsideMinMaxPoints = (
link: null, link: null,
locked: false, locked: false,
points: [ points: [
point<LocalPoint>(0, 0), pointFrom<LocalPoint>(0, 0),
point<LocalPoint>(-922.4761962890625, 300.3277587890625), pointFrom<LocalPoint>(-922.4761962890625, 300.3277587890625),
point<LocalPoint>(828.0126953125, 410.51605224609375), pointFrom<LocalPoint>(828.0126953125, 410.51605224609375),
], ],
}); });
}; };
@ -936,11 +936,11 @@ describe("flipping re-centers selection", () => {
startArrowhead: null, startArrowhead: null,
endArrowhead: "arrow", endArrowhead: "arrow",
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(0, -35), pointFrom(0, -35),
point(-90.9, -35), pointFrom(-90.9, -35),
point(-90.9, 204.9), pointFrom(-90.9, 204.9),
point(65.1, 204.9), pointFrom(65.1, 204.9),
], ],
elbowed: true, elbowed: true,
}), }),

View file

@ -111,7 +111,7 @@ import {
import { mutateElbowArrow } from "../element/routing"; import { mutateElbowArrow } from "../element/routing";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { point, vector } from "../../math"; import { pointFrom, vector } from "../../math";
const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1; const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1;
@ -1644,7 +1644,7 @@ export const actionChangeArrowType = register({
elementsMap, elementsMap,
[finalStartPoint, finalEndPoint].map( [finalStartPoint, finalEndPoint].map(
(p): LocalPoint => (p): LocalPoint =>
point(p[0] - newElement.x, p[1] - newElement.y), pointFrom(p[0] - newElement.x, p[1] - newElement.y),
), ),
vector(0, 0), vector(0, 0),
{ {

View file

@ -1,4 +1,4 @@
import { point, radians } from "../math"; import { pointFrom, radians } from "../math";
import { import {
COLOR_PALETTE, COLOR_PALETTE,
DEFAULT_CHART_COLOR_INDEX, DEFAULT_CHART_COLOR_INDEX,
@ -259,7 +259,7 @@ const chartLines = (
x, x,
y, y,
width: chartWidth, width: chartWidth,
points: [point(0, 0), point(chartWidth, 0)], points: [pointFrom(0, 0), pointFrom(chartWidth, 0)],
}); });
const yLine = newLinearElement({ const yLine = newLinearElement({
@ -270,7 +270,7 @@ const chartLines = (
x, x,
y, y,
height: chartHeight, height: chartHeight,
points: [point(0, 0), point(0, -chartHeight)], points: [pointFrom(0, 0), pointFrom(0, -chartHeight)],
}); });
const maxLine = newLinearElement({ const maxLine = newLinearElement({
@ -283,7 +283,7 @@ const chartLines = (
strokeStyle: "dotted", strokeStyle: "dotted",
width: chartWidth, width: chartWidth,
opacity: GRID_OPACITY, opacity: GRID_OPACITY,
points: [point(0, 0), point(chartWidth, 0)], points: [pointFrom(0, 0), pointFrom(chartWidth, 0)],
}); });
return [xLine, yLine, maxLine]; return [xLine, yLine, maxLine];
@ -440,7 +440,7 @@ const chartTypeLine = (
height: cy, height: cy,
strokeStyle: "dotted", strokeStyle: "dotted",
opacity: GRID_OPACITY, opacity: GRID_OPACITY,
points: [point(0, 0), point(0, cy)], points: [pointFrom(0, 0), pointFrom(0, cy)],
}); });
}); });

View file

@ -449,7 +449,7 @@ import type {
} from "../../math"; } from "../../math";
import { import {
pathIsALoop, pathIsALoop,
point, pointFrom,
pointCenter, pointCenter,
pointDistance, pointDistance,
pointSubtract, pointSubtract,
@ -600,7 +600,7 @@ class App extends React.Component<AppProps, AppState> {
lastPointerUpEvent: React.PointerEvent<HTMLElement> | PointerEvent | null = lastPointerUpEvent: React.PointerEvent<HTMLElement> | PointerEvent | null =
null; null;
lastPointerMoveEvent: PointerEvent | null = null; lastPointerMoveEvent: PointerEvent | null = null;
lastViewportPosition = point<ViewportPoint>(0, 0); lastViewportPosition = pointFrom<ViewportPoint>(0, 0);
animationFrameHandler = new AnimationFrameHandler(); animationFrameHandler = new AnimationFrameHandler();
@ -1008,7 +1008,7 @@ class App extends React.Component<AppProps, AppState> {
<> <>
{embeddableElements.map((el) => { {embeddableElements.map((el) => {
const [x, y] = sceneCoordsToViewportCoords( const [x, y] = sceneCoordsToViewportCoords(
point(el.x, el.y), pointFrom(el.x, el.y),
this.state, this.state,
); );
@ -1294,11 +1294,11 @@ class App extends React.Component<AppProps, AppState> {
if (frameNameDiv) { if (frameNameDiv) {
const box = frameNameDiv.getBoundingClientRect(); const box = frameNameDiv.getBoundingClientRect();
const boxSceneTopLeft = viewportCoordsToSceneCoords( const boxSceneTopLeft = viewportCoordsToSceneCoords(
point(box.x, box.y), pointFrom(box.x, box.y),
this.state, this.state,
); );
const boxSceneBottomRight = viewportCoordsToSceneCoords( const boxSceneBottomRight = viewportCoordsToSceneCoords(
point(box.right, box.bottom), pointFrom(box.right, box.bottom),
this.state, this.state,
); );
@ -1354,7 +1354,10 @@ class App extends React.Component<AppProps, AppState> {
return null; return null;
} }
const [x1, y1] = sceneCoordsToViewportCoords(point(f.x, f.y), this.state); const [x1, y1] = sceneCoordsToViewportCoords(
pointFrom(f.x, f.y),
this.state,
);
const FRAME_NAME_EDIT_PADDING = 6; const FRAME_NAME_EDIT_PADDING = 6;
@ -3171,7 +3174,7 @@ class App extends React.Component<AppProps, AppState> {
: this.state.height / 2 + this.state.offsetTop; : this.state.height / 2 + this.state.offsetTop;
const [x, y] = viewportCoordsToSceneCoords( const [x, y] = viewportCoordsToSceneCoords(
point(clientX, clientY), pointFrom(clientX, clientY),
this.state, this.state,
); );
@ -3197,7 +3200,7 @@ class App extends React.Component<AppProps, AppState> {
syncMovedIndices(nextElements, arrayToMap(newElements)); syncMovedIndices(nextElements, arrayToMap(newElements));
const topLayerFrame = this.getTopLayerFrameAtSceneCoords(point(x, y)); const topLayerFrame = this.getTopLayerFrameAtSceneCoords(pointFrom(x, y));
if (topLayerFrame) { if (topLayerFrame) {
const eligibleElements = filterElementsEligibleAsFrameChildren( const eligibleElements = filterElementsEligibleAsFrameChildren(
@ -3407,7 +3410,7 @@ class App extends React.Component<AppProps, AppState> {
const originalText = normalizeText(line).trim(); const originalText = normalizeText(line).trim();
if (originalText.length) { if (originalText.length) {
const topLayerFrame = this.getTopLayerFrameAtSceneCoords( const topLayerFrame = this.getTopLayerFrameAtSceneCoords(
point(x, currentY), pointFrom(x, currentY),
); );
let metrics = measureText(originalText, fontString, lineHeight); let metrics = measureText(originalText, fontString, lineHeight);
@ -3848,7 +3851,7 @@ class App extends React.Component<AppProps, AppState> {
private updateCurrentCursorPosition = withBatchedUpdates( private updateCurrentCursorPosition = withBatchedUpdates(
(event: MouseEvent) => { (event: MouseEvent) => {
this.lastViewportPosition = point(event.clientX, event.clientY); this.lastViewportPosition = pointFrom(event.clientX, event.clientY);
}, },
); );
@ -4679,7 +4682,7 @@ class App extends React.Component<AppProps, AppState> {
canvas: this.canvas, canvas: this.canvas,
getViewportCoords: (x, y) => { getViewportCoords: (x, y) => {
const [viewportX, viewportY] = sceneCoordsToViewportCoords( const [viewportX, viewportY] = sceneCoordsToViewportCoords(
point(x, y), pointFrom(x, y),
this.state, this.state,
); );
return [ return [
@ -5039,7 +5042,7 @@ class App extends React.Component<AppProps, AppState> {
const newHeight = Math.max(container.height, minHeight); const newHeight = Math.max(container.height, minHeight);
const newWidth = Math.max(container.width, minWidth); const newWidth = Math.max(container.width, minWidth);
mutateElement(container, { height: newHeight, width: newWidth }); mutateElement(container, { height: newHeight, width: newWidth });
sceneCoords = point( sceneCoords = pointFrom(
container.x + newWidth / 2, container.x + newWidth / 2,
container.y + newHeight / 2, container.y + newHeight / 2,
); );
@ -5151,7 +5154,7 @@ class App extends React.Component<AppProps, AppState> {
resetCursor(this.interactiveCanvas); resetCursor(this.interactiveCanvas);
let sceneCoords = viewportCoordsToSceneCoords( let sceneCoords = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
@ -5259,11 +5262,14 @@ class App extends React.Component<AppProps, AppState> {
isTouchScreen: boolean, isTouchScreen: boolean,
) => { ) => {
const draggedDistance = pointDistance( const draggedDistance = pointDistance(
point( pointFrom(
this.lastPointerDownEvent!.clientX, this.lastPointerDownEvent!.clientX,
this.lastPointerDownEvent!.clientY, this.lastPointerDownEvent!.clientY,
), ),
point(this.lastPointerUpEvent!.clientX, this.lastPointerUpEvent!.clientY), pointFrom(
this.lastPointerUpEvent!.clientX,
this.lastPointerUpEvent!.clientY,
),
); );
if ( if (
!this.hitLinkElement || !this.hitLinkElement ||
@ -5274,7 +5280,7 @@ class App extends React.Component<AppProps, AppState> {
return; return;
} }
const lastPointerDownCoords = viewportCoordsToSceneCoords( const lastPointerDownCoords = viewportCoordsToSceneCoords(
point( pointFrom(
this.lastPointerDownEvent!.clientX, this.lastPointerDownEvent!.clientX,
this.lastPointerDownEvent!.clientY, this.lastPointerDownEvent!.clientY,
), ),
@ -5289,7 +5295,10 @@ class App extends React.Component<AppProps, AppState> {
this.device.editor.isMobile, this.device.editor.isMobile,
); );
const lastPointerUpCoords = viewportCoordsToSceneCoords( const lastPointerUpCoords = viewportCoordsToSceneCoords(
point(this.lastPointerUpEvent!.clientX, this.lastPointerUpEvent!.clientY), pointFrom(
this.lastPointerUpEvent!.clientX,
this.lastPointerUpEvent!.clientY,
),
this.state, this.state,
); );
const lastPointerUpHittingLinkIcon = isPointHittingLink( const lastPointerUpHittingLinkIcon = isPointHittingLink(
@ -5347,7 +5356,7 @@ class App extends React.Component<AppProps, AppState> {
if (gesture.pointers.has(event.pointerId)) { if (gesture.pointers.has(event.pointerId)) {
gesture.pointers.set( gesture.pointers.set(
event.pointerId, event.pointerId,
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
); );
} }
@ -5429,7 +5438,7 @@ class App extends React.Component<AppProps, AppState> {
} }
const scenePointer = viewportCoordsToSceneCoords( const scenePointer = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
@ -5543,7 +5552,7 @@ class App extends React.Component<AppProps, AppState> {
// threshold, add a point // threshold, add a point
if ( if (
pointDistance( pointDistance(
point(scenePointer[0] - rx, scenePointer[1] - ry), pointFrom(scenePointer[0] - rx, scenePointer[1] - ry),
lastPoint, lastPoint,
) >= LINE_CONFIRM_THRESHOLD ) >= LINE_CONFIRM_THRESHOLD
) { ) {
@ -5552,7 +5561,10 @@ class App extends React.Component<AppProps, AppState> {
{ {
points: [ points: [
...points, ...points,
point<LocalPoint>(scenePointer[0] - rx, scenePointer[1] - ry), pointFrom<LocalPoint>(
scenePointer[0] - rx,
scenePointer[1] - ry,
),
], ],
}, },
false, false,
@ -5566,7 +5578,7 @@ class App extends React.Component<AppProps, AppState> {
points.length > 2 && points.length > 2 &&
lastCommittedPoint && lastCommittedPoint &&
pointDistance( pointDistance(
point(scenePointer[0] - rx, scenePointer[1] - ry), pointFrom(scenePointer[0] - rx, scenePointer[1] - ry),
lastCommittedPoint, lastCommittedPoint,
) < LINE_CONFIRM_THRESHOLD ) < LINE_CONFIRM_THRESHOLD
) { ) {
@ -5616,7 +5628,7 @@ class App extends React.Component<AppProps, AppState> {
this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElementsMap(),
[ [
...points.slice(0, -1), ...points.slice(0, -1),
point<LocalPoint>( pointFrom<LocalPoint>(
lastCommittedX + dxFromLastCommitted, lastCommittedX + dxFromLastCommitted,
lastCommittedY + dyFromLastCommitted, lastCommittedY + dyFromLastCommitted,
), ),
@ -5635,7 +5647,7 @@ class App extends React.Component<AppProps, AppState> {
{ {
points: [ points: [
...points.slice(0, -1), ...points.slice(0, -1),
point<LocalPoint>( pointFrom<LocalPoint>(
lastCommittedX + dxFromLastCommitted, lastCommittedX + dxFromLastCommitted,
lastCommittedY + dyFromLastCommitted, lastCommittedY + dyFromLastCommitted,
), ),
@ -5872,10 +5884,10 @@ class App extends React.Component<AppProps, AppState> {
(1 - distanceRatio) * p[0] + distanceRatio * scenePointer[0]; (1 - distanceRatio) * p[0] + distanceRatio * scenePointer[0];
const nextY = const nextY =
(1 - distanceRatio) * p[1] + distanceRatio * scenePointer[1]; (1 - distanceRatio) * p[1] + distanceRatio * scenePointer[1];
p = point(nextX, nextY); p = pointFrom(nextX, nextY);
} }
pointerDownState.lastCoords = point(scenePointer[0], scenePointer[1]); pointerDownState.lastCoords = pointFrom(scenePointer[0], scenePointer[1]);
if (didChange) { if (didChange) {
for (const element of this.scene.getNonDeletedElements()) { for (const element of this.scene.getNonDeletedElements()) {
@ -6227,7 +6239,7 @@ class App extends React.Component<AppProps, AppState> {
}); });
const sceneCoords = viewportCoordsToSceneCoords( const sceneCoords = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
@ -6315,7 +6327,7 @@ class App extends React.Component<AppProps, AppState> {
this.lastPointerUpEvent = event; this.lastPointerUpEvent = event;
const scenePointer = viewportCoordsToSceneCoords( const scenePointer = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
const clicklength = const clicklength =
@ -6522,7 +6534,10 @@ class App extends React.Component<AppProps, AppState> {
private updateGestureOnPointerDown( private updateGestureOnPointerDown(
event: React.PointerEvent<HTMLElement>, event: React.PointerEvent<HTMLElement>,
): void { ): void {
gesture.pointers.set(event.pointerId, point(event.clientX, event.clientY)); gesture.pointers.set(
event.pointerId,
pointFrom(event.clientX, event.clientY),
);
if (gesture.pointers.size === 2) { if (gesture.pointers.size === 2) {
const [pointer1, pointer2] = Array.from(gesture.pointers.values()); const [pointer1, pointer2] = Array.from(gesture.pointers.values());
@ -6536,7 +6551,7 @@ class App extends React.Component<AppProps, AppState> {
event: React.PointerEvent<HTMLElement>, event: React.PointerEvent<HTMLElement>,
): PointerDownState { ): PointerDownState {
const origin = viewportCoordsToSceneCoords( const origin = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
const selectedElements = this.scene.getSelectedElements(this.state); const selectedElements = this.scene.getSelectedElements(this.state);
@ -6613,7 +6628,7 @@ class App extends React.Component<AppProps, AppState> {
return false; return false;
} }
isDraggingScrollBar = true; isDraggingScrollBar = true;
pointerDownState.lastCoords = point(event.clientX, event.clientY); pointerDownState.lastCoords = pointFrom(event.clientX, event.clientY);
const onPointerMove = withBatchedUpdatesThrottled((event: PointerEvent) => { const onPointerMove = withBatchedUpdatesThrottled((event: PointerEvent) => {
const target = event.target; const target = event.target;
if (!(target instanceof HTMLElement)) { if (!(target instanceof HTMLElement)) {
@ -6977,7 +6992,7 @@ class App extends React.Component<AppProps, AppState> {
if (hasBoundTextElement(element)) { if (hasBoundTextElement(element)) {
container = element as ExcalidrawTextContainer; container = element as ExcalidrawTextContainer;
sceneCoords = point( sceneCoords = pointFrom(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );
@ -7010,7 +7025,7 @@ class App extends React.Component<AppProps, AppState> {
); );
const topLayerFrame = this.getTopLayerFrameAtSceneCoords( const topLayerFrame = this.getTopLayerFrameAtSceneCoords(
point(gridX, gridY), pointFrom(gridX, gridY),
); );
const simulatePressure = event.pressure === 0.5; const simulatePressure = event.pressure === 0.5;
@ -7030,7 +7045,7 @@ class App extends React.Component<AppProps, AppState> {
simulatePressure, simulatePressure,
locked: false, locked: false,
frameId: topLayerFrame ? topLayerFrame.id : null, frameId: topLayerFrame ? topLayerFrame.id : null,
points: [point<LocalPoint>(0, 0)], points: [pointFrom<LocalPoint>(0, 0)],
pressures: simulatePressure ? [] : [event.pressure], pressures: simulatePressure ? [] : [event.pressure],
}); });
@ -7175,7 +7190,7 @@ class App extends React.Component<AppProps, AppState> {
); );
const topLayerFrame = addToFrameUnderCursor const topLayerFrame = addToFrameUnderCursor
? this.getTopLayerFrameAtSceneCoords(point(gridX, gridY)) ? this.getTopLayerFrameAtSceneCoords(pointFrom(gridX, gridY))
: null; : null;
const element = newImageElement({ const element = newImageElement({
@ -7239,7 +7254,7 @@ class App extends React.Component<AppProps, AppState> {
multiElement.points.length > 1 && multiElement.points.length > 1 &&
lastCommittedPoint && lastCommittedPoint &&
pointDistance( pointDistance(
point( pointFrom(
pointerDownState.origin[0] - rx, pointerDownState.origin[0] - rx,
pointerDownState.origin[1] - ry, pointerDownState.origin[1] - ry,
), ),
@ -7273,7 +7288,7 @@ class App extends React.Component<AppProps, AppState> {
); );
const topLayerFrame = this.getTopLayerFrameAtSceneCoords( const topLayerFrame = this.getTopLayerFrameAtSceneCoords(
point(gridX, gridY), pointFrom(gridX, gridY),
); );
/* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads. /* If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads.
@ -7343,7 +7358,7 @@ class App extends React.Component<AppProps, AppState> {
}; };
}); });
mutateElement(element, { mutateElement(element, {
points: [...element.points, point<LocalPoint>(0, 0)], points: [...element.points, pointFrom<LocalPoint>(0, 0)],
}); });
const boundElement = getHoveredElementForBinding( const boundElement = getHoveredElementForBinding(
pointerDownState.origin, pointerDownState.origin,
@ -7392,7 +7407,7 @@ class App extends React.Component<AppProps, AppState> {
); );
const topLayerFrame = this.getTopLayerFrameAtSceneCoords( const topLayerFrame = this.getTopLayerFrameAtSceneCoords(
point(gridX, gridY), pointFrom(gridX, gridY),
); );
const baseElementAttributes = { const baseElementAttributes = {
@ -7568,7 +7583,7 @@ class App extends React.Component<AppProps, AppState> {
} }
const pointerCoords = viewportCoordsToSceneCoords( const pointerCoords = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
@ -7942,7 +7957,7 @@ class App extends React.Component<AppProps, AppState> {
mutateElement( mutateElement(
newElement, newElement,
{ {
points: [...points, point<LocalPoint>(dx, dy)], points: [...points, pointFrom<LocalPoint>(dx, dy)],
pressures, pressures,
}, },
false, false,
@ -7971,7 +7986,7 @@ class App extends React.Component<AppProps, AppState> {
mutateElement( mutateElement(
newElement, newElement,
{ {
points: [...points, point<LocalPoint>(dx, dy)], points: [...points, pointFrom<LocalPoint>(dx, dy)],
}, },
false, false,
); );
@ -7979,7 +7994,7 @@ class App extends React.Component<AppProps, AppState> {
mutateElbowArrow( mutateElbowArrow(
newElement, newElement,
elementsMap, elementsMap,
[...points.slice(0, -1), point<LocalPoint>(dx, dy)], [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
vector(0, 0), vector(0, 0),
undefined, undefined,
{ {
@ -7991,7 +8006,7 @@ class App extends React.Component<AppProps, AppState> {
mutateElement( mutateElement(
newElement, newElement,
{ {
points: [...points.slice(0, -1), point<LocalPoint>(dx, dy)], points: [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
}, },
false, false,
); );
@ -8128,7 +8143,10 @@ class App extends React.Component<AppProps, AppState> {
this.translateCanvas({ this.translateCanvas({
scrollX: this.state.scrollX - dx / this.state.zoom.value, scrollX: this.state.scrollX - dx / this.state.zoom.value,
}); });
pointerDownState.lastCoords = point(x, pointerDownState.lastCoords[1]); pointerDownState.lastCoords = pointFrom(
x,
pointerDownState.lastCoords[1],
);
return true; return true;
} }
@ -8138,7 +8156,10 @@ class App extends React.Component<AppProps, AppState> {
this.translateCanvas({ this.translateCanvas({
scrollY: this.state.scrollY - dy / this.state.zoom.value, scrollY: this.state.scrollY - dy / this.state.zoom.value,
}); });
pointerDownState.lastCoords = point(pointerDownState.lastCoords[0], y); pointerDownState.lastCoords = pointFrom(
pointerDownState.lastCoords[0],
y,
);
return true; return true;
} }
return false; return false;
@ -8280,7 +8301,7 @@ class App extends React.Component<AppProps, AppState> {
if (newElement?.type === "freedraw") { if (newElement?.type === "freedraw") {
const pointerCoords = viewportCoordsToSceneCoords( const pointerCoords = viewportCoordsToSceneCoords(
point(childEvent.clientX, childEvent.clientY), pointFrom(childEvent.clientX, childEvent.clientY),
this.state, this.state,
); );
@ -8299,9 +8320,9 @@ class App extends React.Component<AppProps, AppState> {
: [...newElement.pressures, childEvent.pressure]; : [...newElement.pressures, childEvent.pressure];
mutateElement(newElement, { mutateElement(newElement, {
points: [...points, point<LocalPoint>(dx, dy)], points: [...points, pointFrom<LocalPoint>(dx, dy)],
pressures, pressures,
lastCommittedPoint: point<LocalPoint>(dx, dy), lastCommittedPoint: pointFrom<LocalPoint>(dx, dy),
}); });
this.actionManager.executeAction(actionFinalize); this.actionManager.executeAction(actionFinalize);
@ -8340,7 +8361,7 @@ class App extends React.Component<AppProps, AppState> {
this.store.shouldCaptureIncrement(); this.store.shouldCaptureIncrement();
} }
const pointerCoords = viewportCoordsToSceneCoords( const pointerCoords = viewportCoordsToSceneCoords(
point(childEvent.clientX, childEvent.clientY), pointFrom(childEvent.clientX, childEvent.clientY),
this.state, this.state,
); );
@ -8348,7 +8369,7 @@ class App extends React.Component<AppProps, AppState> {
mutateElement(newElement, { mutateElement(newElement, {
points: [ points: [
...newElement.points, ...newElement.points,
point<LocalPoint>( pointFrom<LocalPoint>(
pointerCoords[0] - newElement.x, pointerCoords[0] - newElement.x,
pointerCoords[1] - newElement.y, pointerCoords[1] - newElement.y,
), ),
@ -8465,7 +8486,7 @@ class App extends React.Component<AppProps, AppState> {
if (pointerDownState.drag.hasOccurred) { if (pointerDownState.drag.hasOccurred) {
const sceneCoords = viewportCoordsToSceneCoords( const sceneCoords = viewportCoordsToSceneCoords(
point(childEvent.clientX, childEvent.clientY), pointFrom(childEvent.clientX, childEvent.clientY),
this.state, this.state,
); );
@ -8665,13 +8686,13 @@ class App extends React.Component<AppProps, AppState> {
this.eraserTrail.endPath(); this.eraserTrail.endPath();
const draggedDistance = pointDistance( const draggedDistance = pointDistance(
point(pointerStart.clientX, pointerStart.clientY), pointFrom(pointerStart.clientX, pointerStart.clientY),
point(pointerEnd.clientX, pointerEnd.clientY), pointFrom(pointerEnd.clientX, pointerEnd.clientY),
); );
if (draggedDistance === 0) { if (draggedDistance === 0) {
const scenePointer = viewportCoordsToSceneCoords( const scenePointer = viewportCoordsToSceneCoords(
point(pointerEnd.clientX, pointerEnd.clientY), pointFrom(pointerEnd.clientX, pointerEnd.clientY),
this.state, this.state,
); );
const hitElements = this.getElementsAtPosition(scenePointer); const hitElements = this.getElementsAtPosition(scenePointer);
@ -9208,7 +9229,7 @@ class App extends React.Component<AppProps, AppState> {
const clientY = this.state.height / 2 + this.state.offsetTop; const clientY = this.state.height / 2 + this.state.offsetTop;
const [x, y] = viewportCoordsToSceneCoords( const [x, y] = viewportCoordsToSceneCoords(
point(clientX, clientY), pointFrom(clientX, clientY),
this.state, this.state,
); );
@ -9500,7 +9521,7 @@ class App extends React.Component<AppProps, AppState> {
// must be retrieved first, in the same frame // must be retrieved first, in the same frame
const { file, fileHandle } = await getFileFromEvent(event); const { file, fileHandle } = await getFileFromEvent(event);
const [sceneX, sceneY] = viewportCoordsToSceneCoords( const [sceneX, sceneY] = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
@ -9693,7 +9714,7 @@ class App extends React.Component<AppProps, AppState> {
} }
const position = viewportCoordsToSceneCoords( const position = viewportCoordsToSceneCoords(
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
this.state, this.state,
); );
const element = this.getElementAtPosition(position, { const element = this.getElementAtPosition(position, {
@ -10168,7 +10189,7 @@ class App extends React.Component<AppProps, AppState> {
container?: ExcalidrawTextContainer | null, container?: ExcalidrawTextContainer | null,
) { ) {
if (container) { if (container) {
let elementCenter = point<GlobalPoint>( let elementCenter = pointFrom<GlobalPoint>(
container.x + container.width / 2, container.x + container.width / 2,
container.y + container.height / 2, container.y + container.height / 2,
); );
@ -10203,7 +10224,7 @@ class App extends React.Component<AppProps, AppState> {
return; return;
} }
const [sceneX, sceneY] = viewportCoordsToSceneCoords( const [sceneX, sceneY] = viewportCoordsToSceneCoords(
point(x, y), pointFrom(x, y),
this.state, this.state,
); );

View file

@ -20,7 +20,7 @@ import { getAtomicUnits, getStepSizedValue, isPropertyEditable } from "./utils";
import { getElementsInAtomicUnit, resizeElement } from "./utils"; import { getElementsInAtomicUnit, resizeElement } from "./utils";
import type { AtomicUnit } from "./utils"; import type { AtomicUnit } from "./utils";
import { MIN_WIDTH_OR_HEIGHT } from "../../constants"; import { MIN_WIDTH_OR_HEIGHT } from "../../constants";
import { point, type GlobalPoint } from "../../../math"; import { pointFrom, type GlobalPoint } from "../../../math";
interface MultiDimensionProps { interface MultiDimensionProps {
property: "width" | "height"; property: "width" | "height";
@ -182,7 +182,7 @@ const handleDimensionChange: DragInputCallbackType<
nextHeight, nextHeight,
initialHeight, initialHeight,
aspectRatio, aspectRatio,
point(x1, y1), pointFrom(x1, y1),
property, property,
latestElements, latestElements,
originalElements, originalElements,
@ -287,7 +287,7 @@ const handleDimensionChange: DragInputCallbackType<
nextHeight, nextHeight,
initialHeight, initialHeight,
aspectRatio, aspectRatio,
point(x1, y1), pointFrom(x1, y1),
property, property,
latestElements, latestElements,
originalElements, originalElements,

View file

@ -13,7 +13,7 @@ import { useMemo } from "react";
import { getElementsInAtomicUnit, moveElement } from "./utils"; import { getElementsInAtomicUnit, moveElement } from "./utils";
import type { AtomicUnit } from "./utils"; import type { AtomicUnit } from "./utils";
import type { AppState } from "../../types"; import type { AppState } from "../../types";
import { point, pointRotateRads } from "../../../math"; import { pointFrom, pointRotateRads } from "../../../math";
interface MultiPositionProps { interface MultiPositionProps {
property: "x" | "y"; property: "x" | "y";
@ -44,8 +44,8 @@ const moveElements = (
origElement.y + origElement.height / 2, origElement.y + origElement.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(origElement.x, origElement.y), pointFrom(origElement.x, origElement.y),
point(cx, cy), pointFrom(cx, cy),
origElement.angle, origElement.angle,
); );
@ -97,8 +97,8 @@ const moveGroupTo = (
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(latestElement.x, latestElement.y), pointFrom(latestElement.x, latestElement.y),
point(cx, cy), pointFrom(cx, cy),
latestElement.angle, latestElement.angle,
); );
@ -171,8 +171,8 @@ const handlePositionChange: DragInputCallbackType<
origElement.y + origElement.height / 2, origElement.y + origElement.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(origElement.x, origElement.y), pointFrom(origElement.x, origElement.y),
point(cx, cy), pointFrom(cx, cy),
origElement.angle, origElement.angle,
); );
@ -241,8 +241,8 @@ const MultiPosition = ({
const [cx, cy] = [el.x + el.width / 2, el.y + el.height / 2]; const [cx, cy] = [el.x + el.width / 2, el.y + el.height / 2];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(el.x, el.y), pointFrom(el.x, el.y),
point(cx, cy), pointFrom(cx, cy),
el.angle, el.angle,
); );

View file

@ -4,7 +4,7 @@ import type { DragInputCallbackType } from "./DragInput";
import { getStepSizedValue, moveElement } from "./utils"; import { getStepSizedValue, moveElement } from "./utils";
import type Scene from "../../scene/Scene"; import type Scene from "../../scene/Scene";
import type { AppState } from "../../types"; import type { AppState } from "../../types";
import { point, pointRotateRads } from "../../../math"; import { pointFrom, pointRotateRads } from "../../../math";
interface PositionProps { interface PositionProps {
property: "x" | "y"; property: "x" | "y";
@ -33,8 +33,8 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({
origElement.y + origElement.height / 2, origElement.y + origElement.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(origElement.x, origElement.y), pointFrom(origElement.x, origElement.y),
point(cx, cy), pointFrom(cx, cy),
origElement.angle, origElement.angle,
); );
@ -93,8 +93,8 @@ const Position = ({
appState, appState,
}: PositionProps) => { }: PositionProps) => {
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(element.x, element.y), pointFrom(element.x, element.y),
point(element.x + element.width / 2, element.y + element.height / 2), pointFrom(element.x + element.width / 2, element.y + element.height / 2),
element.angle, element.angle,
); );
const value = const value =

View file

@ -25,7 +25,7 @@ import { API } from "../../tests/helpers/api";
import { actionGroup } from "../../actions"; import { actionGroup } from "../../actions";
import { isInGroup } from "../../groups"; import { isInGroup } from "../../groups";
import type { Degrees } from "../../../math"; import type { Degrees } from "../../../math";
import { degreesToRadians, point, pointRotateRads } from "../../../math"; import { degreesToRadians, pointFrom, pointRotateRads } from "../../../math";
const { h } = window; const { h } = window;
const mouse = new Pointer("mouse"); const mouse = new Pointer("mouse");
@ -264,8 +264,8 @@ describe("stats for a generic element", () => {
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );
@ -283,8 +283,8 @@ describe("stats for a generic element", () => {
testInputProperty(rectangle, "angle", "A", 0, 45); testInputProperty(rectangle, "angle", "A", 0, 45);
let [newTopLeftX, newTopLeftY] = pointRotateRads( let [newTopLeftX, newTopLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );
@ -294,8 +294,8 @@ describe("stats for a generic element", () => {
testInputProperty(rectangle, "angle", "A", 45, 66); testInputProperty(rectangle, "angle", "A", 45, 66);
[newTopLeftX, newTopLeftY] = pointRotateRads( [newTopLeftX, newTopLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );
expect(newTopLeftX.toString()).not.toEqual(xInput.value); expect(newTopLeftX.toString()).not.toEqual(xInput.value);
@ -311,8 +311,8 @@ describe("stats for a generic element", () => {
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );
testInputProperty(rectangle, "width", "W", rectangle.width, 400); testInputProperty(rectangle, "width", "W", rectangle.width, 400);
@ -321,8 +321,8 @@ describe("stats for a generic element", () => {
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
]; ];
let [currentTopLeftX, currentTopLeftY] = pointRotateRads( let [currentTopLeftX, currentTopLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );
expect(currentTopLeftX).toBeCloseTo(topLeftX, 4); expect(currentTopLeftX).toBeCloseTo(topLeftX, 4);
@ -334,8 +334,8 @@ describe("stats for a generic element", () => {
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
]; ];
[currentTopLeftX, currentTopLeftY] = pointRotateRads( [currentTopLeftX, currentTopLeftY] = pointRotateRads(
point(rectangle.x, rectangle.y), pointFrom(rectangle.x, rectangle.y),
point(cx, cy), pointFrom(cx, cy),
rectangle.angle, rectangle.angle,
); );

View file

@ -1,5 +1,5 @@
import type { Radians } from "../../../math"; import type { Radians } from "../../../math";
import { point, pointRotateRads } from "../../../math"; import { pointFrom, pointRotateRads } from "../../../math";
import { import {
bindOrUnbindLinearElements, bindOrUnbindLinearElements,
updateBoundElements, updateBoundElements,
@ -231,8 +231,8 @@ export const moveElement = (
originalElement.y + originalElement.height / 2, originalElement.y + originalElement.height / 2,
]; ];
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(originalElement.x, originalElement.y), pointFrom(originalElement.x, originalElement.y),
point(cx, cy), pointFrom(cx, cy),
originalElement.angle, originalElement.angle,
); );
@ -240,8 +240,8 @@ export const moveElement = (
const changeInY = newTopLeftY - topLeftY; const changeInY = newTopLeftY - topLeftY;
const [x, y] = pointRotateRads( const [x, y] = pointRotateRads(
point(newTopLeftX, newTopLeftY), pointFrom(newTopLeftX, newTopLeftY),
point(cx + changeInX, cy + changeInY), pointFrom(cx + changeInX, cy + changeInY),
-originalElement.angle as Radians, -originalElement.angle as Radians,
); );

View file

@ -37,7 +37,7 @@ import { useAppProps, useExcalidrawAppState } from "../App";
import { isEmbeddableElement } from "../../element/typeChecks"; import { isEmbeddableElement } from "../../element/typeChecks";
import { getLinkHandleFromCoords } from "./helpers"; import { getLinkHandleFromCoords } from "./helpers";
import type { ViewportPoint } from "../../../math"; import type { ViewportPoint } from "../../../math";
import { point } from "../../../math"; import { pointFrom } from "../../../math";
const CONTAINER_WIDTH = 320; const CONTAINER_WIDTH = 320;
const SPACE_BOTTOM = 85; const SPACE_BOTTOM = 85;
@ -182,7 +182,7 @@ export const Hyperlink = ({
element, element,
elementsMap, elementsMap,
appState, appState,
point(event.clientX, event.clientY), pointFrom(event.clientX, event.clientY),
) as boolean; ) as boolean;
if (shouldHide) { if (shouldHide) {
timeoutId = window.setTimeout(() => { timeoutId = window.setTimeout(() => {
@ -326,7 +326,7 @@ const getCoordsForPopover = (
) => { ) => {
const [x1, y1] = getElementAbsoluteCoords(element, elementsMap); const [x1, y1] = getElementAbsoluteCoords(element, elementsMap);
const [viewportX, viewportY] = sceneCoordsToViewportCoords( const [viewportX, viewportY] = sceneCoordsToViewportCoords(
point(x1 + element.width / 2, y1), pointFrom(x1 + element.width / 2, y1),
appState, appState,
); );
const x = viewportX - appState.offsetLeft - CONTAINER_WIDTH / 2; const x = viewportX - appState.offsetLeft - CONTAINER_WIDTH / 2;
@ -388,7 +388,7 @@ const renderTooltip = (
); );
const linkViewportCoords = sceneCoordsToViewportCoords( const linkViewportCoords = sceneCoordsToViewportCoords(
point(linkX, linkY), pointFrom(linkX, linkY),
appState, appState,
); );

View file

@ -1,5 +1,5 @@
import type { GlobalPoint, Radians } from "../../../math"; import type { GlobalPoint, Radians } from "../../../math";
import { point, pointRotateRads } from "../../../math"; import { pointFrom, pointRotateRads } from "../../../math";
import { MIME_TYPES } from "../../constants"; import { MIME_TYPES } from "../../constants";
import { getElementAbsoluteCoords } from "../../element/bounds"; import { getElementAbsoluteCoords } from "../../element/bounds";
import { hitElementBoundingBox } from "../../element/collision"; import { hitElementBoundingBox } from "../../element/collision";
@ -35,8 +35,8 @@ export const getLinkHandleFromCoords = (
const y = y1 - dashedLineMargin - linkMarginY + centeringOffset; const y = y1 - dashedLineMargin - linkMarginY + centeringOffset;
const [rotatedX, rotatedY] = pointRotateRads( const [rotatedX, rotatedY] = pointRotateRads(
point(x + linkWidth / 2, y + linkHeight / 2), pointFrom(x + linkWidth / 2, y + linkHeight / 2),
point(centerX, centerY), pointFrom(centerX, centerY),
angle, angle,
); );
return [ return [
@ -85,5 +85,10 @@ export const isPointHittingLink = (
) { ) {
return true; return true;
} }
return isPointHittingLinkIcon(element, elementsMap, appState, point(x, y)); return isPointHittingLinkIcon(
element,
elementsMap,
appState,
pointFrom(x, y),
);
}; };

View file

@ -56,7 +56,7 @@ import {
getNormalizedZoom, getNormalizedZoom,
} from "../scene"; } from "../scene";
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { pointExtent, isFiniteNumber, point, radians } from "../../math"; import { pointExtent, isFiniteNumber, pointFrom, radians } from "../../math";
type RestoredAppState = Omit< type RestoredAppState = Omit<
AppState, AppState,
@ -267,7 +267,7 @@ const restoreElement = (
let y = element.y; let y = element.y;
let points = // migrate old arrow model to new one let points = // migrate old arrow model to new one
!Array.isArray(element.points) || element.points.length < 2 !Array.isArray(element.points) || element.points.length < 2
? [point(0, 0), point(element.width, element.height)] ? [pointFrom(0, 0), pointFrom(element.width, element.height)]
: element.points; : element.points;
if (points[0][0] !== 0 || points[0][1] !== 0) { if (points[0][0] !== 0 || points[0][1] !== 0) {
@ -295,7 +295,7 @@ const restoreElement = (
let y: number | undefined = element.y; let y: number | undefined = element.y;
let points: readonly LocalPoint[] | undefined = // migrate old arrow model to new one let points: readonly LocalPoint[] | undefined = // migrate old arrow model to new one
!Array.isArray(element.points) || element.points.length < 2 !Array.isArray(element.points) || element.points.length < 2
? [point(0, 0), point(element.width, element.height)] ? [pointFrom(0, 0), pointFrom(element.width, element.height)]
: element.points; : element.points;
if (points[0][0] !== 0 || points[0][1] !== 0) { if (points[0][0] !== 0 || points[0][1] !== 0) {

View file

@ -2,7 +2,7 @@ import { vi } from "vitest";
import type { ExcalidrawElementSkeleton } from "./transform"; import type { ExcalidrawElementSkeleton } from "./transform";
import { convertToExcalidrawElements } from "./transform"; import { convertToExcalidrawElements } from "./transform";
import type { ExcalidrawArrowElement } from "../element/types"; import type { ExcalidrawArrowElement } from "../element/types";
import { point } from "../../math"; import { pointFrom } from "../../math";
const opts = { regenerateIds: false }; const opts = { regenerateIds: false };
@ -917,7 +917,7 @@ describe("Test Transform", () => {
x: 111.262, x: 111.262,
y: 57, y: 57,
strokeWidth: 2, strokeWidth: 2,
points: [point(0, 0), point(272.985, 0)], points: [pointFrom(0, 0), pointFrom(272.985, 0)],
label: { label: {
text: "How are you?", text: "How are you?",
fontSize: 20, fontSize: 20,
@ -940,7 +940,7 @@ describe("Test Transform", () => {
x: 77.017, x: 77.017,
y: 79, y: 79,
strokeWidth: 2, strokeWidth: 2,
points: [point(0, 0)], points: [pointFrom(0, 0)],
label: { label: {
text: "Friendship", text: "Friendship",
fontSize: 20, fontSize: 20,

View file

@ -53,7 +53,7 @@ import { randomId } from "../random";
import { syncInvalidIndices } from "../fractionalIndex"; import { syncInvalidIndices } from "../fractionalIndex";
import { getLineHeight } from "../fonts"; import { getLineHeight } from "../fonts";
import { isArrowElement } from "../element/typeChecks"; import { isArrowElement } from "../element/typeChecks";
import { pointExtent, point, type LocalPoint } from "../../math"; import { pointExtent, pointFrom, type LocalPoint } from "../../math";
export type ValidLinearElement = { export type ValidLinearElement = {
type: "arrow" | "line"; type: "arrow" | "line";
@ -536,7 +536,7 @@ export const convertToExcalidrawElements = (
excalidrawElement = newLinearElement({ excalidrawElement = newLinearElement({
width, width,
height, height,
points: [point(0, 0), point(width, height)], points: [pointFrom(0, 0), pointFrom(width, height)],
...element, ...element,
}); });
@ -549,7 +549,7 @@ export const convertToExcalidrawElements = (
width, width,
height, height,
endArrowhead: "arrow", endArrowhead: "arrow",
points: [point(0, 0), point(width, height)], points: [pointFrom(0, 0), pointFrom(width, height)],
...element, ...element,
type: "arrow", type: "arrow",
}); });

View file

@ -52,7 +52,7 @@ import {
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { import {
segment, segment,
point, pointFrom,
pointRotateRads, pointRotateRads,
type GlobalPoint, type GlobalPoint,
vectorFromPoint, vectorFromPoint,
@ -701,7 +701,7 @@ export const getHeadingForElbowArrowSnap = (
return vectorToHeading( return vectorToHeading(
vectorFromPoint( vectorFromPoint(
p, p,
point<GlobalPoint>( pointFrom<GlobalPoint>(
bindableElement.x + bindableElement.width / 2, bindableElement.x + bindableElement.width / 2,
bindableElement.y + bindableElement.height / 2, bindableElement.y + bindableElement.height / 2,
), ),
@ -741,14 +741,14 @@ export const bindPointToSnapToElementOutline = (
const intersections: GlobalPoint[] = [ const intersections: GlobalPoint[] = [
...(intersectElementWithLine( ...(intersectElementWithLine(
bindableElement, bindableElement,
point(p[0], p[1] - 2 * bindableElement.height), pointFrom(p[0], p[1] - 2 * bindableElement.height),
point(p[0], p[1] + 2 * bindableElement.height), pointFrom(p[0], p[1] + 2 * bindableElement.height),
FIXED_BINDING_DISTANCE, FIXED_BINDING_DISTANCE,
) ?? []), ) ?? []),
...(intersectElementWithLine( ...(intersectElementWithLine(
bindableElement, bindableElement,
point(p[0] - 2 * bindableElement.width, p[1]), pointFrom(p[0] - 2 * bindableElement.width, p[1]),
point(p[0] + 2 * bindableElement.width, p[1]), pointFrom(p[0] + 2 * bindableElement.width, p[1]),
FIXED_BINDING_DISTANCE, FIXED_BINDING_DISTANCE,
) ?? []), ) ?? []),
].filter((p) => p != null); ].filter((p) => p != null);
@ -786,25 +786,25 @@ const headingToMidBindPoint = (
switch (true) { switch (true) {
case compareHeading(heading, HEADING_UP): case compareHeading(heading, HEADING_UP):
return pointRotateRads( return pointRotateRads(
point((aabb[0] + aabb[2]) / 2 + 0.1, aabb[1]), pointFrom((aabb[0] + aabb[2]) / 2 + 0.1, aabb[1]),
center, center,
bindableElement.angle, bindableElement.angle,
); );
case compareHeading(heading, HEADING_RIGHT): case compareHeading(heading, HEADING_RIGHT):
return pointRotateRads( return pointRotateRads(
point(aabb[2], (aabb[1] + aabb[3]) / 2 + 0.1), pointFrom(aabb[2], (aabb[1] + aabb[3]) / 2 + 0.1),
center, center,
bindableElement.angle, bindableElement.angle,
); );
case compareHeading(heading, HEADING_DOWN): case compareHeading(heading, HEADING_DOWN):
return pointRotateRads( return pointRotateRads(
point((aabb[0] + aabb[2]) / 2 - 0.1, aabb[3]), pointFrom((aabb[0] + aabb[2]) / 2 - 0.1, aabb[3]),
center, center,
bindableElement.angle, bindableElement.angle,
); );
default: default:
return pointRotateRads( return pointRotateRads(
point(aabb[0], (aabb[1] + aabb[3]) / 2 - 0.1), pointFrom(aabb[0], (aabb[1] + aabb[3]) / 2 - 0.1),
center, center,
bindableElement.angle, bindableElement.angle,
); );
@ -815,7 +815,7 @@ export const avoidRectangularCorner = (
element: ExcalidrawBindableElement, element: ExcalidrawBindableElement,
p: GlobalPoint, p: GlobalPoint,
): GlobalPoint => { ): GlobalPoint => {
const center = point<GlobalPoint>( const center = pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );
@ -825,13 +825,13 @@ export const avoidRectangularCorner = (
// Top left // Top left
if (nonRotatedPoint[1] - element.y > -FIXED_BINDING_DISTANCE) { if (nonRotatedPoint[1] - element.y > -FIXED_BINDING_DISTANCE) {
return pointRotateRads<GlobalPoint>( return pointRotateRads<GlobalPoint>(
point(element.x - FIXED_BINDING_DISTANCE, element.y), pointFrom(element.x - FIXED_BINDING_DISTANCE, element.y),
center, center,
element.angle, element.angle,
); );
} }
return pointRotateRads( return pointRotateRads(
point(element.x, element.y - FIXED_BINDING_DISTANCE), pointFrom(element.x, element.y - FIXED_BINDING_DISTANCE),
center, center,
element.angle, element.angle,
); );
@ -842,13 +842,16 @@ export const avoidRectangularCorner = (
// Bottom left // Bottom left
if (nonRotatedPoint[0] - element.x > -FIXED_BINDING_DISTANCE) { if (nonRotatedPoint[0] - element.x > -FIXED_BINDING_DISTANCE) {
return pointRotateRads( return pointRotateRads(
point(element.x, element.y + element.height + FIXED_BINDING_DISTANCE), pointFrom(
element.x,
element.y + element.height + FIXED_BINDING_DISTANCE,
),
center, center,
element.angle, element.angle,
); );
} }
return pointRotateRads( return pointRotateRads(
point(element.x - FIXED_BINDING_DISTANCE, element.y + element.height), pointFrom(element.x - FIXED_BINDING_DISTANCE, element.y + element.height),
center, center,
element.angle, element.angle,
); );
@ -862,7 +865,7 @@ export const avoidRectangularCorner = (
element.width + FIXED_BINDING_DISTANCE element.width + FIXED_BINDING_DISTANCE
) { ) {
return pointRotateRads( return pointRotateRads(
point( pointFrom(
element.x + element.width, element.x + element.width,
element.y + element.height + FIXED_BINDING_DISTANCE, element.y + element.height + FIXED_BINDING_DISTANCE,
), ),
@ -871,7 +874,7 @@ export const avoidRectangularCorner = (
); );
} }
return pointRotateRads( return pointRotateRads(
point( pointFrom(
element.x + element.width + FIXED_BINDING_DISTANCE, element.x + element.width + FIXED_BINDING_DISTANCE,
element.y + element.height, element.y + element.height,
), ),
@ -888,13 +891,16 @@ export const avoidRectangularCorner = (
element.width + FIXED_BINDING_DISTANCE element.width + FIXED_BINDING_DISTANCE
) { ) {
return pointRotateRads( return pointRotateRads(
point(element.x + element.width, element.y - FIXED_BINDING_DISTANCE), pointFrom(
element.x + element.width,
element.y - FIXED_BINDING_DISTANCE,
),
center, center,
element.angle, element.angle,
); );
} }
return pointRotateRads( return pointRotateRads(
point(element.x + element.width + FIXED_BINDING_DISTANCE, element.y), pointFrom(element.x + element.width + FIXED_BINDING_DISTANCE, element.y),
center, center,
element.angle, element.angle,
); );
@ -909,7 +915,10 @@ export const snapToMid = (
tolerance: number = 0.05, tolerance: number = 0.05,
): GlobalPoint => { ): GlobalPoint => {
const { x, y, width, height, angle } = element; const { x, y, width, height, angle } = element;
const center = point<GlobalPoint>(x + width / 2 - 0.1, y + height / 2 - 0.1); const center = pointFrom<GlobalPoint>(
x + width / 2 - 0.1,
y + height / 2 - 0.1,
);
const nonRotated = pointRotateRads(p, center, radians(-angle)); const nonRotated = pointRotateRads(p, center, radians(-angle));
// snap-to-center point is adaptive to element size, but we don't want to go // snap-to-center point is adaptive to element size, but we don't want to go
@ -924,7 +933,7 @@ export const snapToMid = (
) { ) {
// LEFT // LEFT
return pointRotateRads( return pointRotateRads(
point(x - FIXED_BINDING_DISTANCE, center[1]), pointFrom(x - FIXED_BINDING_DISTANCE, center[1]),
center, center,
angle, angle,
); );
@ -935,7 +944,7 @@ export const snapToMid = (
) { ) {
// TOP // TOP
return pointRotateRads( return pointRotateRads(
point(center[0], y - FIXED_BINDING_DISTANCE), pointFrom(center[0], y - FIXED_BINDING_DISTANCE),
center, center,
angle, angle,
); );
@ -946,7 +955,7 @@ export const snapToMid = (
) { ) {
// RIGHT // RIGHT
return pointRotateRads( return pointRotateRads(
point(x + width + FIXED_BINDING_DISTANCE, center[1]), pointFrom(x + width + FIXED_BINDING_DISTANCE, center[1]),
center, center,
angle, angle,
); );
@ -957,7 +966,7 @@ export const snapToMid = (
) { ) {
// DOWN // DOWN
return pointRotateRads( return pointRotateRads(
point(center[0], y + height + FIXED_BINDING_DISTANCE), pointFrom(center[0], y + height + FIXED_BINDING_DISTANCE),
center, center,
angle, angle,
); );
@ -994,11 +1003,11 @@ const updateBoundPoint = (
startOrEnd === "startBinding" ? "start" : "end", startOrEnd === "startBinding" ? "start" : "end",
elementsMap, elementsMap,
).fixedPoint; ).fixedPoint;
const globalMidPoint = point<GlobalPoint>( const globalMidPoint = pointFrom<GlobalPoint>(
bindableElement.x + bindableElement.width / 2, bindableElement.x + bindableElement.width / 2,
bindableElement.y + bindableElement.height / 2, bindableElement.y + bindableElement.height / 2,
); );
const global = point<GlobalPoint>( const global = pointFrom<GlobalPoint>(
bindableElement.x + fixedPoint[0] * bindableElement.width, bindableElement.x + fixedPoint[0] * bindableElement.width,
bindableElement.y + fixedPoint[1] * bindableElement.height, bindableElement.y + fixedPoint[1] * bindableElement.height,
); );
@ -1086,7 +1095,7 @@ export const calculateFixedPointForElbowArrowBinding = (
otherGlobalPoint, otherGlobalPoint,
hoveredElement, hoveredElement,
); );
const globalMidPoint = point( const globalMidPoint = pointFrom(
bounds[0] + (bounds[2] - bounds[0]) / 2, bounds[0] + (bounds[2] - bounds[0]) / 2,
bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[1] + (bounds[3] - bounds[1]) / 2,
); );
@ -1303,9 +1312,9 @@ export const bindingBorderTest = (
const threshold = maxBindingGap(element, element.width, element.height); const threshold = maxBindingGap(element, element.width, element.height);
const shape = getElementShape(element, elementsMap); const shape = getElementShape(element, elementsMap);
return ( return (
isPointOnShape(point(x, y), shape, threshold) || isPointOnShape(pointFrom(x, y), shape, threshold) ||
(fullShape === true && (fullShape === true &&
pointInsideBounds(point(x, y), aabbForElement(element))) pointInsideBounds(pointFrom(x, y), aabbForElement(element)))
); );
}; };
@ -1333,7 +1342,7 @@ const determineFocusDistance = (
// Another point on the line, in absolute coordinates (closer to element) // Another point on the line, in absolute coordinates (closer to element)
b: GlobalPoint, b: GlobalPoint,
): number => { ): number => {
const center = point<GlobalPoint>( const center = pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );
@ -1357,7 +1366,7 @@ const determineFocusPoint = (
focus: number, focus: number,
adjacentPoint: GlobalPoint, adjacentPoint: GlobalPoint,
): GlobalPoint => { ): GlobalPoint => {
const center = point<GlobalPoint>( const center = pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );
@ -1373,7 +1382,7 @@ const determineFocusPoint = (
), ),
Math.sign(focus) * Math.sign(focus) *
Math.min( Math.min(
pointDistance(point<GlobalPoint>(element.x, element.y), center) * pointDistance(pointFrom<GlobalPoint>(element.x, element.y), center) *
Math.abs(focus), Math.abs(focus),
element.width / 2, element.width / 2,
element.height / 2, element.height / 2,
@ -1698,11 +1707,11 @@ export const getGlobalFixedPointForBindableElement = (
const [fixedX, fixedY] = normalizeFixedPoint(fixedPointRatio); const [fixedX, fixedY] = normalizeFixedPoint(fixedPointRatio);
return pointRotateRads( return pointRotateRads(
point( pointFrom(
element.x + element.width * fixedX, element.x + element.width * fixedX,
element.y + element.height * fixedY, element.y + element.height * fixedY,
), ),
point<GlobalPoint>( pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
), ),
@ -1730,7 +1739,7 @@ const getGlobalFixedPoints = (
arrow.startBinding.fixedPoint, arrow.startBinding.fixedPoint,
startElement as ExcalidrawBindableElement, startElement as ExcalidrawBindableElement,
) )
: point<GlobalPoint>( : pointFrom<GlobalPoint>(
arrow.x + arrow.points[0][0], arrow.x + arrow.points[0][0],
arrow.y + arrow.points[0][1], arrow.y + arrow.points[0][1],
); );
@ -1740,7 +1749,7 @@ const getGlobalFixedPoints = (
arrow.endBinding.fixedPoint, arrow.endBinding.fixedPoint,
endElement as ExcalidrawBindableElement, endElement as ExcalidrawBindableElement,
) )
: point<GlobalPoint>( : pointFrom<GlobalPoint>(
arrow.x + arrow.points[arrow.points.length - 1][0], arrow.x + arrow.points[arrow.points.length - 1][0],
arrow.y + arrow.points[arrow.points.length - 1][1], arrow.y + arrow.points[arrow.points.length - 1][1],
); );

View file

@ -1,5 +1,5 @@
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { point } from "../../math"; import { pointFrom } from "../../math";
import { ROUNDNESS } from "../constants"; import { ROUNDNESS } from "../constants";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import { getElementAbsoluteCoords, getElementBounds } from "./bounds"; import { getElementAbsoluteCoords, getElementBounds } from "./bounds";
@ -125,9 +125,9 @@ describe("getElementBounds", () => {
a: 0.6447741904932416, a: 0.6447741904932416,
}), }),
points: [ points: [
point<LocalPoint>(0, 0), pointFrom<LocalPoint>(0, 0),
point<LocalPoint>(67.33984375, 92.48828125), pointFrom<LocalPoint>(67.33984375, 92.48828125),
point<LocalPoint>(-102.7890625, 52.15625), pointFrom<LocalPoint>(-102.7890625, 52.15625),
], ],
} as ExcalidrawLinearElement; } as ExcalidrawLinearElement;

View file

@ -24,7 +24,7 @@ import { ShapeCache } from "../scene/ShapeCache";
import { arrayToMap, invariant } from "../utils"; import { arrayToMap, invariant } from "../utils";
import type { GlobalPoint, LocalPoint, Segment } from "../../math"; import type { GlobalPoint, LocalPoint, Segment } from "../../math";
import { import {
point, pointFrom,
pointDistance, pointDistance,
pointFromArray, pointFromArray,
pointRotateRads, pointRotateRads,
@ -95,8 +95,8 @@ class ElementBounds {
const [minX, minY, maxX, maxY] = getBoundsFromFreeDrawPoints( const [minX, minY, maxX, maxY] = getBoundsFromFreeDrawPoints(
element.points.map(([x, y]) => element.points.map(([x, y]) =>
pointRotateRads( pointRotateRads(
point(x, y), pointFrom(x, y),
point(cx - element.x, cy - element.y), pointFrom(cx - element.x, cy - element.y),
element.angle, element.angle,
), ),
), ),
@ -112,23 +112,23 @@ class ElementBounds {
bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap); bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap);
} else if (element.type === "diamond") { } else if (element.type === "diamond") {
const [x11, y11] = pointRotateRads( const [x11, y11] = pointRotateRads(
point(cx, y1), pointFrom(cx, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x12, y12] = pointRotateRads( const [x12, y12] = pointRotateRads(
point(cx, y2), pointFrom(cx, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x22, y22] = pointRotateRads( const [x22, y22] = pointRotateRads(
point(x1, cy), pointFrom(x1, cy),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x21, y21] = pointRotateRads( const [x21, y21] = pointRotateRads(
point(x2, cy), pointFrom(x2, cy),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const minX = Math.min(x11, x12, x22, x21); const minX = Math.min(x11, x12, x22, x21);
@ -146,23 +146,23 @@ class ElementBounds {
bounds = [cx - ww, cy - hh, cx + ww, cy + hh]; bounds = [cx - ww, cy - hh, cx + ww, cy + hh];
} else { } else {
const [x11, y11] = pointRotateRads( const [x11, y11] = pointRotateRads(
point(x1, y1), pointFrom(x1, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x12, y12] = pointRotateRads( const [x12, y12] = pointRotateRads(
point(x1, y2), pointFrom(x1, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x22, y22] = pointRotateRads( const [x22, y22] = pointRotateRads(
point(x2, y2), pointFrom(x2, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const [x21, y21] = pointRotateRads( const [x21, y21] = pointRotateRads(
point(x2, y1), pointFrom(x2, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const minX = Math.min(x11, x12, x22, x21); const minX = Math.min(x11, x12, x22, x21);
@ -331,7 +331,7 @@ export const getMinMaxXYFromCurvePathOps = (
ops: Op[], ops: Op[],
transformXY?: (p: GlobalPoint) => GlobalPoint, transformXY?: (p: GlobalPoint) => GlobalPoint,
): Bounds => { ): Bounds => {
let currentP: GlobalPoint = point(0, 0); let currentP: GlobalPoint = pointFrom(0, 0);
const { minX, minY, maxX, maxY } = ops.reduce( const { minX, minY, maxX, maxY } = ops.reduce(
(limits, { op, data }) => { (limits, { op, data }) => {
@ -345,9 +345,9 @@ export const getMinMaxXYFromCurvePathOps = (
// move operation does not draw anything; so, it always // move operation does not draw anything; so, it always
// returns false // returns false
} else if (op === "bcurveTo") { } else if (op === "bcurveTo") {
const _p1 = point<GlobalPoint>(data[0], data[1]); const _p1 = pointFrom<GlobalPoint>(data[0], data[1]);
const _p2 = point<GlobalPoint>(data[2], data[3]); const _p2 = pointFrom<GlobalPoint>(data[2], data[3]);
const _p3 = point<GlobalPoint>(data[4], data[5]); const _p3 = pointFrom<GlobalPoint>(data[4], data[5]);
const p1 = transformXY ? transformXY(_p1) : _p1; const p1 = transformXY ? transformXY(_p1) : _p1;
const p2 = transformXY ? transformXY(_p2) : _p2; const p2 = transformXY ? transformXY(_p2) : _p2;
@ -442,8 +442,8 @@ const getLinearElementRotatedBounds = (
if (element.points.length < 2) { if (element.points.length < 2) {
const [pointX, pointY] = element.points[0]; const [pointX, pointY] = element.points[0];
const [x, y] = pointRotateRads( const [x, y] = pointRotateRads(
point(element.x + pointX, element.y + pointY), pointFrom(element.x + pointX, element.y + pointY),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
@ -471,8 +471,8 @@ const getLinearElementRotatedBounds = (
const ops = getCurvePathOps(shape); const ops = getCurvePathOps(shape);
const transformXY = ([x, y]: GlobalPoint) => const transformXY = ([x, y]: GlobalPoint) =>
pointRotateRads<GlobalPoint>( pointRotateRads<GlobalPoint>(
point(element.x + x, element.y + y), pointFrom(element.x + x, element.y + y),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const res = getMinMaxXYFromCurvePathOps(ops, transformXY); const res = getMinMaxXYFromCurvePathOps(ops, transformXY);
@ -620,8 +620,8 @@ export const getClosestElementBounds = (
elements.forEach((element) => { elements.forEach((element) => {
const [x1, y1, x2, y2] = getElementBounds(element, elementsMap); const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
const distance = pointDistance( const distance = pointDistance(
point((x1 + x2) / 2, (y1 + y2) / 2), pointFrom((x1 + x2) / 2, (y1 + y2) / 2),
point(from.x, from.y), pointFrom(from.x, from.y),
); );
if (distance < minDistance) { if (distance < minDistance) {
@ -652,7 +652,7 @@ export const getVisibleSceneBounds = ({
}; };
export const getCenterForBounds = (bounds: Bounds): GlobalPoint => export const getCenterForBounds = (bounds: Bounds): GlobalPoint =>
point( pointFrom(
bounds[0] + (bounds[2] - bounds[0]) / 2, bounds[0] + (bounds[2] - bounds[0]) / 2,
bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[1] + (bounds[3] - bounds[1]) / 2,
); );
@ -696,7 +696,7 @@ export const createDiamondArc = (
end: GlobalPoint, end: GlobalPoint,
r: number, r: number,
) => { ) => {
const c = point<GlobalPoint>( const c = pointFrom<GlobalPoint>(
(start[0] + end[0]) / 2, (start[0] + end[0]) / 2,
(start[1] + end[1]) / 2, (start[1] + end[1]) / 2,
); );

View file

@ -31,7 +31,7 @@ import type { Arc, GlobalPoint, Polygon } from "../../math";
import { import {
pathIsALoop, pathIsALoop,
isPointWithinBounds, isPointWithinBounds,
point, pointFrom,
rectangle, rectangle,
pointRotateRads, pointRotateRads,
radians, radians,
@ -119,7 +119,11 @@ export const hitElementBoundingBox = (
y1 -= tolerance; y1 -= tolerance;
x2 += tolerance; x2 += tolerance;
y2 += tolerance; y2 += tolerance;
return isPointWithinBounds(point(x1, y1), scenePointer, point(x2, y2)); return isPointWithinBounds(
pointFrom(x1, y1),
scenePointer,
pointFrom(x2, y2),
);
}; };
export const hitElementBoundingBoxOnly = ( export const hitElementBoundingBoxOnly = (
@ -175,13 +179,13 @@ export const intersectRectanguloidWithLine = (
offset: number, offset: number,
): GlobalPoint[] => { ): GlobalPoint[] => {
const r = rectangle( const r = rectangle(
point(element.x - offset, element.y - offset), pointFrom(element.x - offset, element.y - offset),
point( pointFrom(
element.x + element.width + offset, element.x + element.width + offset,
element.y + element.height + offset, element.y + element.height + offset,
), ),
); );
const center = point<GlobalPoint>( const center = pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );
@ -203,20 +207,20 @@ export const intersectRectanguloidWithLine = (
); );
const sideIntersections: GlobalPoint[] = [ const sideIntersections: GlobalPoint[] = [
segment<GlobalPoint>( segment<GlobalPoint>(
point<GlobalPoint>(r[0][0] + roundness, r[0][1]), pointFrom<GlobalPoint>(r[0][0] + roundness, r[0][1]),
point<GlobalPoint>(r[1][0] - roundness, r[0][1]), pointFrom<GlobalPoint>(r[1][0] - roundness, r[0][1]),
), ),
segment<GlobalPoint>( segment<GlobalPoint>(
point<GlobalPoint>(r[1][0], r[0][1] + roundness), pointFrom<GlobalPoint>(r[1][0], r[0][1] + roundness),
point<GlobalPoint>(r[1][0], r[1][1] - roundness), pointFrom<GlobalPoint>(r[1][0], r[1][1] - roundness),
), ),
segment<GlobalPoint>( segment<GlobalPoint>(
point<GlobalPoint>(r[1][0] - roundness, r[1][1]), pointFrom<GlobalPoint>(r[1][0] - roundness, r[1][1]),
point<GlobalPoint>(r[0][0] + roundness, r[1][1]), pointFrom<GlobalPoint>(r[0][0] + roundness, r[1][1]),
), ),
segment<GlobalPoint>( segment<GlobalPoint>(
point<GlobalPoint>(r[0][0], r[1][1] - roundness), pointFrom<GlobalPoint>(r[0][0], r[1][1] - roundness),
point<GlobalPoint>(r[0][0], r[0][1] + roundness), pointFrom<GlobalPoint>(r[0][0], r[0][1] + roundness),
), ),
] ]
.map((s) => .map((s) =>
@ -228,25 +232,25 @@ export const intersectRectanguloidWithLine = (
roundness > 0 roundness > 0
? [ ? [
arc<GlobalPoint>( arc<GlobalPoint>(
point(r[0][0] + roundness, r[0][1] + roundness), pointFrom(r[0][0] + roundness, r[0][1] + roundness),
roundness, roundness,
radians(Math.PI), radians(Math.PI),
radians((3 / 4) * Math.PI), radians((3 / 4) * Math.PI),
), ),
arc<GlobalPoint>( arc<GlobalPoint>(
point(r[1][0] - roundness, r[0][1] + roundness), pointFrom(r[1][0] - roundness, r[0][1] + roundness),
roundness, roundness,
radians((3 / 4) * Math.PI), radians((3 / 4) * Math.PI),
radians(0), radians(0),
), ),
arc<GlobalPoint>( arc<GlobalPoint>(
point(r[1][0] - roundness, r[1][1] - roundness), pointFrom(r[1][0] - roundness, r[1][1] - roundness),
roundness, roundness,
radians(0), radians(0),
radians((1 / 2) * Math.PI), radians((1 / 2) * Math.PI),
), ),
arc<GlobalPoint>( arc<GlobalPoint>(
point(r[0][0] + roundness, r[1][1] - roundness), pointFrom(r[0][0] + roundness, r[1][1] - roundness),
roundness, roundness,
radians((1 / 2) * Math.PI), radians((1 / 2) * Math.PI),
radians(Math.PI), radians(Math.PI),
@ -277,7 +281,10 @@ export const intersectDiamondWithLine = (
): GlobalPoint[] => { ): GlobalPoint[] => {
const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] = const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
getDiamondPoints(element, offset); getDiamondPoints(element, offset);
const center = point<GlobalPoint>((topX + bottomX) / 2, (topY + bottomY) / 2); const center = pointFrom<GlobalPoint>(
(topX + bottomX) / 2,
(topY + bottomY) / 2,
);
const verticalRadius = getCornerRadius(Math.abs(topX - leftX), element); const verticalRadius = getCornerRadius(Math.abs(topX - leftX), element);
const horizontalRadius = getCornerRadius(Math.abs(rightY - topY), element); const horizontalRadius = getCornerRadius(Math.abs(rightY - topY), element);
@ -286,10 +293,10 @@ export const intersectDiamondWithLine = (
const rotatedA = pointRotateRads(a, center, radians(-element.angle)); const rotatedA = pointRotateRads(a, center, radians(-element.angle));
const rotatedB = pointRotateRads(b, center, radians(-element.angle)); const rotatedB = pointRotateRads(b, center, radians(-element.angle));
const [top, right, bottom, left]: GlobalPoint[] = [ const [top, right, bottom, left]: GlobalPoint[] = [
point(element.x + topX, element.y + topY), pointFrom(element.x + topX, element.y + topY),
point(element.x + rightX, element.y + rightY), pointFrom(element.x + rightX, element.y + rightY),
point(element.x + bottomX, element.y + bottomY), pointFrom(element.x + bottomX, element.y + bottomY),
point(element.x + leftX, element.y + leftY), pointFrom(element.x + leftX, element.y + leftY),
]; ];
const topRight = createDiamondSide( const topRight = createDiamondSide(
@ -353,7 +360,7 @@ export const intersectEllipseWithLine = (
b: GlobalPoint, b: GlobalPoint,
offset: number = 0, offset: number = 0,
): GlobalPoint[] => { ): GlobalPoint[] => {
const center = point<GlobalPoint>( const center = pointFrom<GlobalPoint>(
element.x + element.width / 2, element.x + element.width / 2,
element.y + element.height / 2, element.y + element.height / 2,
); );

View file

@ -29,7 +29,7 @@ import {
isFlowchartNodeElement, isFlowchartNodeElement,
} from "./typeChecks"; } from "./typeChecks";
import { invariant } from "../utils"; import { invariant } from "../utils";
import { point, type LocalPoint } from "../../math"; import { pointFrom, type LocalPoint } from "../../math";
import { aabbForElement } from "../shapes"; import { aabbForElement } from "../shapes";
type LinkDirection = "up" | "right" | "down" | "left"; type LinkDirection = "up" | "right" | "down" | "left";
@ -421,7 +421,7 @@ const createBindingArrow = (
strokeColor: appState.currentItemStrokeColor, strokeColor: appState.currentItemStrokeColor,
strokeStyle: appState.currentItemStrokeStyle, strokeStyle: appState.currentItemStrokeStyle,
strokeWidth: appState.currentItemStrokeWidth, strokeWidth: appState.currentItemStrokeWidth,
points: [point(0, 0), point(endX, endY)], points: [pointFrom(0, 0), pointFrom(endX, endY)],
elbowed: true, elbowed: true,
}); });

View file

@ -7,7 +7,7 @@ import type {
ViewportPoint, ViewportPoint,
} from "../../math"; } from "../../math";
import { import {
point, pointFrom,
pointRotateRads, pointRotateRads,
pointScaleFromOrigin, pointScaleFromOrigin,
radiansToDegrees, radiansToDegrees,
@ -85,7 +85,7 @@ export const headingForPointFromElement = <
const top = pointRotateRads( const top = pointRotateRads(
pointScaleFromOrigin( pointScaleFromOrigin(
point(element.x + element.width / 2, element.y), pointFrom(element.x + element.width / 2, element.y),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
), ),
@ -94,7 +94,7 @@ export const headingForPointFromElement = <
); );
const right = pointRotateRads( const right = pointRotateRads(
pointScaleFromOrigin( pointScaleFromOrigin(
point(element.x + element.width, element.y + element.height / 2), pointFrom(element.x + element.width, element.y + element.height / 2),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
), ),
@ -103,7 +103,7 @@ export const headingForPointFromElement = <
); );
const bottom = pointRotateRads( const bottom = pointRotateRads(
pointScaleFromOrigin( pointScaleFromOrigin(
point(element.x + element.width / 2, element.y + element.height), pointFrom(element.x + element.width / 2, element.y + element.height),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
), ),
@ -112,7 +112,7 @@ export const headingForPointFromElement = <
); );
const left = pointRotateRads( const left = pointRotateRads(
pointScaleFromOrigin( pointScaleFromOrigin(
point(element.x, element.y + element.height / 2), pointFrom(element.x, element.y + element.height / 2),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
), ),
@ -136,22 +136,22 @@ export const headingForPointFromElement = <
} }
const topLeft = pointScaleFromOrigin( const topLeft = pointScaleFromOrigin(
point(aabb[0], aabb[1]), pointFrom(aabb[0], aabb[1]),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
) as Point; ) as Point;
const topRight = pointScaleFromOrigin( const topRight = pointScaleFromOrigin(
point(aabb[2], aabb[1]), pointFrom(aabb[2], aabb[1]),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
) as Point; ) as Point;
const bottomLeft = pointScaleFromOrigin( const bottomLeft = pointScaleFromOrigin(
point(aabb[0], aabb[3]), pointFrom(aabb[0], aabb[3]),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
) as Point; ) as Point;
const bottomRight = pointScaleFromOrigin( const bottomRight = pointScaleFromOrigin(
point(aabb[2], aabb[3]), pointFrom(aabb[2], aabb[3]),
midPoint, midPoint,
SEARCH_CONE_MULTIPLIER, SEARCH_CONE_MULTIPLIER,
) as Point; ) as Point;

View file

@ -44,7 +44,7 @@ import type Scene from "../scene/Scene";
import type { Radians } from "../../math"; import type { Radians } from "../../math";
import { import {
pointCenter, pointCenter,
point, pointFrom,
pointRotateRads, pointRotateRads,
pointsEqual, pointsEqual,
vector, vector,
@ -106,14 +106,14 @@ export class LinearElementEditor {
this.elementId = element.id as string & { this.elementId = element.id as string & {
_brand: "excalidrawLinearElementId"; _brand: "excalidrawLinearElementId";
}; };
if (!pointsEqual(element.points[0], point(0, 0))) { if (!pointsEqual(element.points[0], pointFrom(0, 0))) {
console.error("Linear element is not normalized", Error().stack); console.error("Linear element is not normalized", Error().stack);
} }
this.selectedPointsIndices = null; this.selectedPointsIndices = null;
this.lastUncommittedPoint = null; this.lastUncommittedPoint = null;
this.isDragging = false; this.isDragging = false;
this.pointerOffset = point(0, 0); this.pointerOffset = pointFrom(0, 0);
this.startBindingElement = "keep"; this.startBindingElement = "keep";
this.endBindingElement = "keep"; this.endBindingElement = "keep";
this.pointerDownState = { this.pointerDownState = {
@ -293,7 +293,7 @@ export class LinearElementEditor {
[ [
{ {
index: selectedIndex, index: selectedIndex,
point: point( point: pointFrom(
width + referencePoint[0], width + referencePoint[0],
height + referencePoint[1], height + referencePoint[1],
), ),
@ -327,7 +327,7 @@ export class LinearElementEditor {
), ),
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(), event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
) )
: point( : pointFrom(
element.points[pointIndex][0] + deltaX, element.points[pointIndex][0] + deltaX,
element.points[pointIndex][1] + deltaY, element.points[pointIndex][1] + deltaY,
); );
@ -478,7 +478,7 @@ export class LinearElementEditor {
? [pointerDownState.lastClickedPoint] ? [pointerDownState.lastClickedPoint]
: selectedPointsIndices, : selectedPointsIndices,
isDragging: false, isDragging: false,
pointerOffset: point(0, 0), pointerOffset: pointFrom(0, 0),
}; };
} }
@ -586,7 +586,7 @@ export class LinearElementEditor {
linearElementEditor.segmentMidPointHoveredCoords; linearElementEditor.segmentMidPointHoveredCoords;
if (existingSegmentMidpointHitCoords) { if (existingSegmentMidpointHitCoords) {
const distance = pointDistance( const distance = pointDistance(
point( pointFrom(
existingSegmentMidpointHitCoords[0], existingSegmentMidpointHitCoords[0],
existingSegmentMidpointHitCoords[1], existingSegmentMidpointHitCoords[1],
), ),
@ -602,7 +602,7 @@ export class LinearElementEditor {
while (index < midPoints.length) { while (index < midPoints.length) {
if (midPoints[index] !== null) { if (midPoints[index] !== null) {
const distance = pointDistance( const distance = pointDistance(
point(midPoints[index]![0], midPoints[index]![1]), pointFrom(midPoints[index]![0], midPoints[index]![1]),
scenePointer, scenePointer,
); );
if (distance <= threshold) { if (distance <= threshold) {
@ -622,8 +622,8 @@ export class LinearElementEditor {
zoom: AppState["zoom"], zoom: AppState["zoom"],
) { ) {
let distance = pointDistance( let distance = pointDistance(
point(startPoint[0], startPoint[1]), pointFrom(startPoint[0], startPoint[1]),
point(endPoint[0], endPoint[1]), pointFrom(endPoint[0], endPoint[1]),
); );
if (element.points.length > 2 && element.roundness) { if (element.points.length > 2 && element.roundness) {
distance = getBezierCurveLength(element, endPoint); distance = getBezierCurveLength(element, endPoint);
@ -823,11 +823,11 @@ export class LinearElementEditor {
const targetPoint = const targetPoint =
clickedPointIndex > -1 && clickedPointIndex > -1 &&
pointRotateRads<GlobalPoint>( pointRotateRads<GlobalPoint>(
point( pointFrom(
element.x + element.points[clickedPointIndex][0], element.x + element.points[clickedPointIndex][0],
element.y + element.points[clickedPointIndex][1], element.y + element.points[clickedPointIndex][1],
), ),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
@ -857,7 +857,7 @@ export class LinearElementEditor {
selectedPointsIndices: nextSelectedPointsIndices, selectedPointsIndices: nextSelectedPointsIndices,
pointerOffset: targetPoint pointerOffset: targetPoint
? pointSubtract(scenePointer, targetPoint) ? pointSubtract(scenePointer, targetPoint)
: point(0, 0), : pointFrom(0, 0),
}; };
return ret; return ret;
@ -922,7 +922,7 @@ export class LinearElementEditor {
event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(), event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize(),
); );
newPoint = point( newPoint = pointFrom(
width + lastCommittedPoint[0], width + lastCommittedPoint[0],
height + lastCommittedPoint[1], height + lastCommittedPoint[1],
); );
@ -976,8 +976,8 @@ export class LinearElementEditor {
const { x, y } = element; const { x, y } = element;
return pointRotateRads( return pointRotateRads(
point(x + p[0], y + p[1]), pointFrom(x + p[0], y + p[1]),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
} }
@ -993,8 +993,8 @@ export class LinearElementEditor {
return element.points.map((p) => { return element.points.map((p) => {
const { x, y } = element; const { x, y } = element;
return pointRotateRads( return pointRotateRads(
point(x + p[0], y + p[1]), pointFrom(x + p[0], y + p[1]),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
}); });
@ -1017,8 +1017,12 @@ export class LinearElementEditor {
const { x, y } = element; const { x, y } = element;
return p return p
? pointRotateRads(point(x + p[0], y + p[1]), point(cx, cy), element.angle) ? pointRotateRads(
: pointRotateRads(point(x, y), point(cx, cy), element.angle); pointFrom(x + p[0], y + p[1]),
pointFrom(cx, cy),
element.angle,
)
: pointRotateRads(pointFrom(x, y), pointFrom(cx, cy), element.angle);
} }
static pointFromAbsoluteCoords( static pointFromAbsoluteCoords(
@ -1028,7 +1032,7 @@ export class LinearElementEditor {
): LocalPoint { ): LocalPoint {
if (isElbowArrow(element)) { if (isElbowArrow(element)) {
// No rotation for elbow arrows // No rotation for elbow arrows
return point( return pointFrom(
absoluteCoords[0] - element.x, absoluteCoords[0] - element.x,
absoluteCoords[1] - element.y, absoluteCoords[1] - element.y,
); );
@ -1038,11 +1042,11 @@ export class LinearElementEditor {
const cx = (x1 + x2) / 2; const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2; const cy = (y1 + y2) / 2;
const [x, y] = pointRotateRads( const [x, y] = pointRotateRads(
point(absoluteCoords[0], absoluteCoords[1]), pointFrom(absoluteCoords[0], absoluteCoords[1]),
point(cx, cy), pointFrom(cx, cy),
-element.angle as Radians, -element.angle as Radians,
); );
return point(x - element.x, y - element.y); return pointFrom(x - element.x, y - element.y);
} }
static getPointIndexUnderCursor( static getPointIndexUnderCursor(
@ -1087,12 +1091,12 @@ export class LinearElementEditor {
const cx = (x1 + x2) / 2; const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2; const cy = (y1 + y2) / 2;
const [rotatedX, rotatedY] = pointRotateRads( const [rotatedX, rotatedY] = pointRotateRads(
point(pointerOnGrid[0], pointerOnGrid[1]), pointFrom(pointerOnGrid[0], pointerOnGrid[1]),
point(cx, cy), pointFrom(cx, cy),
-element.angle as Radians, -element.angle as Radians,
); );
return point(rotatedX - element.x, rotatedY - element.y); return pointFrom(rotatedX - element.x, rotatedY - element.y);
} }
/** /**
@ -1112,7 +1116,7 @@ export class LinearElementEditor {
return { return {
points: points.map((p) => { points: points.map((p) => {
return point(p[0] - offsetX, p[1] - offsetY); return pointFrom(p[0] - offsetX, p[1] - offsetY);
}), }),
x: element.x + offsetX, x: element.x + offsetX,
y: element.y + offsetY, y: element.y + offsetY,
@ -1166,8 +1170,8 @@ export class LinearElementEditor {
} }
acc.push( acc.push(
nextPoint nextPoint
? point((p[0] + nextPoint[0]) / 2, (p[1] + nextPoint[1]) / 2) ? pointFrom((p[0] + nextPoint[0]) / 2, (p[1] + nextPoint[1]) / 2)
: point(p[0], p[1]), : pointFrom(p[0], p[1]),
); );
nextSelectedIndices.push(indexCursor + 1); nextSelectedIndices.push(indexCursor + 1);
@ -1188,7 +1192,7 @@ export class LinearElementEditor {
[ [
{ {
index: element.points.length - 1, index: element.points.length - 1,
point: point(lastPoint[0] + 30, lastPoint[1] + 30), point: pointFrom(lastPoint[0] + 30, lastPoint[1] + 30),
}, },
], ],
elementsMap, elementsMap,
@ -1229,7 +1233,9 @@ export class LinearElementEditor {
const nextPoints = element.points.reduce((acc: LocalPoint[], p, idx) => { const nextPoints = element.points.reduce((acc: LocalPoint[], p, idx) => {
if (!pointIndices.includes(idx)) { if (!pointIndices.includes(idx)) {
acc.push( acc.push(
!acc.length ? point(0, 0) : point(p[0] - offsetX, p[1] - offsetY), !acc.length
? pointFrom(0, 0)
: pointFrom(p[0] - offsetX, p[1] - offsetY),
); );
} }
return acc; return acc;
@ -1306,9 +1312,9 @@ export class LinearElementEditor {
const deltaY = const deltaY =
selectedPointData.point[1] - points[selectedPointData.index][1]; selectedPointData.point[1] - points[selectedPointData.index][1];
return point(p[0] + deltaX - offsetX, p[1] + deltaY - offsetY); return pointFrom(p[0] + deltaX - offsetX, p[1] + deltaY - offsetY);
} }
return offsetX || offsetY ? point(p[0] - offsetX, p[1] - offsetY) : p; return offsetX || offsetY ? pointFrom(p[0] - offsetX, p[1] - offsetY) : p;
}); });
LinearElementEditor._updatePoints( LinearElementEditor._updatePoints(
@ -1483,8 +1489,8 @@ export class LinearElementEditor {
const dX = prevCenterX - nextCenterX; const dX = prevCenterX - nextCenterX;
const dY = prevCenterY - nextCenterY; const dY = prevCenterY - nextCenterY;
const rotated = pointRotateRads( const rotated = pointRotateRads(
point(offsetX, offsetY), pointFrom(offsetX, offsetY),
point(dX, dY), pointFrom(dX, dY),
element.angle, element.angle,
); );
mutateElement(element, { mutateElement(element, {
@ -1530,8 +1536,8 @@ export class LinearElementEditor {
); );
return pointRotateRads( return pointRotateRads(
point(width, height), pointFrom(width, height),
point(0, 0), pointFrom(0, 0),
-element.angle as Radians, -element.angle as Radians,
); );
} }
@ -1601,36 +1607,36 @@ export class LinearElementEditor {
); );
const boundTextX2 = boundTextX1 + boundTextElement.width; const boundTextX2 = boundTextX1 + boundTextElement.width;
const boundTextY2 = boundTextY1 + boundTextElement.height; const boundTextY2 = boundTextY1 + boundTextElement.height;
const centerPoint = point(cx, cy); const centerPoint = pointFrom(cx, cy);
const topLeftRotatedPoint = pointRotateRads( const topLeftRotatedPoint = pointRotateRads(
point(x1, y1), pointFrom(x1, y1),
centerPoint, centerPoint,
element.angle, element.angle,
); );
const topRightRotatedPoint = pointRotateRads( const topRightRotatedPoint = pointRotateRads(
point(x2, y1), pointFrom(x2, y1),
centerPoint, centerPoint,
element.angle, element.angle,
); );
const counterRotateBoundTextTopLeft = pointRotateRads( const counterRotateBoundTextTopLeft = pointRotateRads(
point(boundTextX1, boundTextY1), pointFrom(boundTextX1, boundTextY1),
centerPoint, centerPoint,
-element.angle as Radians, -element.angle as Radians,
); );
const counterRotateBoundTextTopRight = pointRotateRads( const counterRotateBoundTextTopRight = pointRotateRads(
point(boundTextX2, boundTextY1), pointFrom(boundTextX2, boundTextY1),
centerPoint, centerPoint,
-element.angle as Radians, -element.angle as Radians,
); );
const counterRotateBoundTextBottomLeft = pointRotateRads( const counterRotateBoundTextBottomLeft = pointRotateRads(
point(boundTextX1, boundTextY2), pointFrom(boundTextX1, boundTextY2),
centerPoint, centerPoint,
-element.angle as Radians, -element.angle as Radians,
); );
const counterRotateBoundTextBottomRight = pointRotateRads( const counterRotateBoundTextBottomRight = pointRotateRads(
point(boundTextX2, boundTextY2), pointFrom(boundTextX2, boundTextY2),
centerPoint, centerPoint,
-element.angle as Radians, -element.angle as Radians,
); );

View file

@ -5,7 +5,7 @@ import { FONT_FAMILY, ROUNDNESS } from "../constants";
import { isPrimitive } from "../utils"; import { isPrimitive } from "../utils";
import type { ExcalidrawLinearElement } from "./types"; import type { ExcalidrawLinearElement } from "./types";
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { point } from "../../math"; import { pointFrom } from "../../math";
const assertCloneObjects = (source: any, clone: any) => { const assertCloneObjects = (source: any, clone: any) => {
for (const key in clone) { for (const key in clone) {
@ -38,7 +38,7 @@ describe("duplicating single elements", () => {
element.__proto__ = { hello: "world" }; element.__proto__ = { hello: "world" };
mutateElement(element, { mutateElement(element, {
points: [point<LocalPoint>(1, 2), point<LocalPoint>(3, 4)], points: [pointFrom<LocalPoint>(1, 2), pointFrom<LocalPoint>(3, 4)],
}); });
const copy = duplicateElement(null, new Map(), element); const copy = duplicateElement(null, new Map(), element);

View file

@ -56,7 +56,7 @@ import type { GlobalPoint } from "../../math";
import { import {
pointCenter, pointCenter,
normalizeRadians, normalizeRadians,
point, pointFrom,
pointFromPair, pointFromPair,
pointRotateRads, pointRotateRads,
type Radians, type Radians,
@ -239,8 +239,8 @@ const resizeSingleTextElement = (
); );
// rotation pointer with reverse angle // rotation pointer with reverse angle
const [rotatedX, rotatedY] = pointRotateRads( const [rotatedX, rotatedY] = pointRotateRads(
point(pointerX, pointerY), pointFrom(pointerX, pointerY),
point(cx, cy), pointFrom(cx, cy),
-element.angle as Radians, -element.angle as Radians,
); );
let scaleX = 0; let scaleX = 0;
@ -275,23 +275,23 @@ const resizeSingleTextElement = (
const startBottomRight = [x2, y2]; const startBottomRight = [x2, y2];
const startCenter = [cx, cy]; const startCenter = [cx, cy];
let newTopLeft = point<GlobalPoint>(x1, y1); let newTopLeft = pointFrom<GlobalPoint>(x1, y1);
if (["n", "w", "nw"].includes(transformHandleType)) { if (["n", "w", "nw"].includes(transformHandleType)) {
newTopLeft = point<GlobalPoint>( newTopLeft = pointFrom<GlobalPoint>(
startBottomRight[0] - Math.abs(nextWidth), startBottomRight[0] - Math.abs(nextWidth),
startBottomRight[1] - Math.abs(nextHeight), startBottomRight[1] - Math.abs(nextHeight),
); );
} }
if (transformHandleType === "ne") { if (transformHandleType === "ne") {
const bottomLeft = [startTopLeft[0], startBottomRight[1]]; const bottomLeft = [startTopLeft[0], startBottomRight[1]];
newTopLeft = point<GlobalPoint>( newTopLeft = pointFrom<GlobalPoint>(
bottomLeft[0], bottomLeft[0],
bottomLeft[1] - Math.abs(nextHeight), bottomLeft[1] - Math.abs(nextHeight),
); );
} }
if (transformHandleType === "sw") { if (transformHandleType === "sw") {
const topRight = [startBottomRight[0], startTopLeft[1]]; const topRight = [startBottomRight[0], startTopLeft[1]];
newTopLeft = point<GlobalPoint>( newTopLeft = pointFrom<GlobalPoint>(
topRight[0] - Math.abs(nextWidth), topRight[0] - Math.abs(nextWidth),
topRight[1], topRight[1],
); );
@ -310,12 +310,20 @@ const resizeSingleTextElement = (
} }
const angle = element.angle; const angle = element.angle;
const rotatedTopLeft = pointRotateRads(newTopLeft, point(cx, cy), angle); const rotatedTopLeft = pointRotateRads(
const newCenter = point<GlobalPoint>( newTopLeft,
pointFrom(cx, cy),
angle,
);
const newCenter = pointFrom<GlobalPoint>(
newTopLeft[0] + Math.abs(nextWidth) / 2, newTopLeft[0] + Math.abs(nextWidth) / 2,
newTopLeft[1] + Math.abs(nextHeight) / 2, newTopLeft[1] + Math.abs(nextHeight) / 2,
); );
const rotatedNewCenter = pointRotateRads(newCenter, point(cx, cy), angle); const rotatedNewCenter = pointRotateRads(
newCenter,
pointFrom(cx, cy),
angle,
);
newTopLeft = pointRotateRads( newTopLeft = pointRotateRads(
rotatedTopLeft, rotatedTopLeft,
rotatedNewCenter, rotatedNewCenter,
@ -340,12 +348,12 @@ const resizeSingleTextElement = (
stateAtResizeStart.height, stateAtResizeStart.height,
true, true,
); );
const startTopLeft = point<GlobalPoint>(x1, y1); const startTopLeft = pointFrom<GlobalPoint>(x1, y1);
const startBottomRight = point<GlobalPoint>(x2, y2); const startBottomRight = pointFrom<GlobalPoint>(x2, y2);
const startCenter = pointCenter(startTopLeft, startBottomRight); const startCenter = pointCenter(startTopLeft, startBottomRight);
const rotatedPointer = pointRotateRads( const rotatedPointer = pointRotateRads(
point(pointerX, pointerY), pointFrom(pointerX, pointerY),
startCenter, startCenter,
-stateAtResizeStart.angle as Radians, -stateAtResizeStart.angle as Radians,
); );
@ -418,7 +426,7 @@ const resizeSingleTextElement = (
startCenter, startCenter,
angle, angle,
); );
const newCenter = point( const newCenter = pointFrom(
newTopLeft[0] + Math.abs(newBoundsWidth) / 2, newTopLeft[0] + Math.abs(newBoundsWidth) / 2,
newTopLeft[1] + Math.abs(newBoundsHeight) / 2, newTopLeft[1] + Math.abs(newBoundsHeight) / 2,
); );
@ -460,13 +468,13 @@ export const resizeSingleElement = (
stateAtResizeStart.height, stateAtResizeStart.height,
true, true,
); );
const startTopLeft = point(x1, y1); const startTopLeft = pointFrom(x1, y1);
const startBottomRight = point(x2, y2); const startBottomRight = pointFrom(x2, y2);
const startCenter = pointCenter(startTopLeft, startBottomRight); const startCenter = pointCenter(startTopLeft, startBottomRight);
// Calculate new dimensions based on cursor position // Calculate new dimensions based on cursor position
const rotatedPointer = pointRotateRads( const rotatedPointer = pointRotateRads(
point(pointerX, pointerY), pointFrom(pointerX, pointerY),
startCenter, startCenter,
-stateAtResizeStart.angle as Radians, -stateAtResizeStart.angle as Radians,
); );
@ -647,7 +655,7 @@ export const resizeSingleElement = (
startCenter, startCenter,
angle, angle,
); );
const newCenter = point( const newCenter = pointFrom(
newTopLeft[0] + Math.abs(newBoundsWidth) / 2, newTopLeft[0] + Math.abs(newBoundsWidth) / 2,
newTopLeft[1] + Math.abs(newBoundsHeight) / 2, newTopLeft[1] + Math.abs(newBoundsHeight) / 2,
); );
@ -818,20 +826,20 @@ export const resizeMultipleElements = (
const direction = transformHandleType; const direction = transformHandleType;
const anchorsMap: Record<TransformHandleDirection, GlobalPoint> = { const anchorsMap: Record<TransformHandleDirection, GlobalPoint> = {
ne: point(minX, maxY), ne: pointFrom(minX, maxY),
se: point(minX, minY), se: pointFrom(minX, minY),
sw: point(maxX, minY), sw: pointFrom(maxX, minY),
nw: point(maxX, maxY), nw: pointFrom(maxX, maxY),
e: point(minX, minY + height / 2), e: pointFrom(minX, minY + height / 2),
w: point(maxX, minY + height / 2), w: pointFrom(maxX, minY + height / 2),
n: point(minX + width / 2, maxY), n: pointFrom(minX + width / 2, maxY),
s: point(minX + width / 2, minY), s: pointFrom(minX + width / 2, minY),
}; };
// anchor point must be on the opposite side of the dragged selection handle // anchor point must be on the opposite side of the dragged selection handle
// or be the center of the selection if shouldResizeFromCenter // or be the center of the selection if shouldResizeFromCenter
const [anchorX, anchorY] = shouldResizeFromCenter const [anchorX, anchorY] = shouldResizeFromCenter
? point(midX, midY) ? pointFrom(midX, midY)
: anchorsMap[direction]; : anchorsMap[direction];
const resizeFromCenterScale = shouldResizeFromCenter ? 2 : 1; const resizeFromCenterScale = shouldResizeFromCenter ? 2 : 1;
@ -1045,8 +1053,8 @@ const rotateMultipleElements = (
const origAngle = const origAngle =
originalElements.get(element.id)?.angle ?? element.angle; originalElements.get(element.id)?.angle ?? element.angle;
const [rotatedCX, rotatedCY] = pointRotateRads( const [rotatedCX, rotatedCY] = pointRotateRads(
point(cx, cy), pointFrom(cx, cy),
point(centerX, centerY), pointFrom(centerX, centerY),
(centerAngle + origAngle - element.angle) as Radians, (centerAngle + origAngle - element.angle) as Radians,
); );
@ -1101,40 +1109,44 @@ export const getResizeOffsetXY = (
const angle = ( const angle = (
selectedElements.length === 1 ? selectedElements[0].angle : 0 selectedElements.length === 1 ? selectedElements[0].angle : 0
) as Radians; ) as Radians;
[x, y] = pointRotateRads(point(x, y), point(cx, cy), -angle as Radians); [x, y] = pointRotateRads(
pointFrom(x, y),
pointFrom(cx, cy),
-angle as Radians,
);
switch (transformHandleType) { switch (transformHandleType) {
case "n": case "n":
return pointRotateRads( return pointRotateRads(
point(x - (x1 + x2) / 2, y - y1), pointFrom(x - (x1 + x2) / 2, y - y1),
point(0, 0), pointFrom(0, 0),
angle, angle,
); );
case "s": case "s":
return pointRotateRads( return pointRotateRads(
point(x - (x1 + x2) / 2, y - y2), pointFrom(x - (x1 + x2) / 2, y - y2),
point(0, 0), pointFrom(0, 0),
angle, angle,
); );
case "w": case "w":
return pointRotateRads( return pointRotateRads(
point(x - x1, y - (y1 + y2) / 2), pointFrom(x - x1, y - (y1 + y2) / 2),
point(0, 0), pointFrom(0, 0),
angle, angle,
); );
case "e": case "e":
return pointRotateRads( return pointRotateRads(
point(x - x2, y - (y1 + y2) / 2), pointFrom(x - x2, y - (y1 + y2) / 2),
point(0, 0), pointFrom(0, 0),
angle, angle,
); );
case "nw": case "nw":
return pointRotateRads(point(x - x1, y - y1), point(0, 0), angle); return pointRotateRads(pointFrom(x - x1, y - y1), pointFrom(0, 0), angle);
case "ne": case "ne":
return pointRotateRads(point(x - x2, y - y1), point(0, 0), angle); return pointRotateRads(pointFrom(x - x2, y - y1), pointFrom(0, 0), angle);
case "sw": case "sw":
return pointRotateRads(point(x - x1, y - y2), point(0, 0), angle); return pointRotateRads(pointFrom(x - x1, y - y2), pointFrom(0, 0), angle);
case "se": case "se":
return pointRotateRads(point(x - x2, y - y2), point(0, 0), angle); return pointRotateRads(pointFrom(x - x2, y - y2), pointFrom(0, 0), angle);
default: default:
return [0, 0]; return [0, 0];
} }

View file

@ -23,7 +23,7 @@ import { SIDE_RESIZING_THRESHOLD } from "../constants";
import { isLinearElement } from "./typeChecks"; import { isLinearElement } from "./typeChecks";
import type { GlobalPoint, Segment, LocalPoint } from "../../math"; import type { GlobalPoint, Segment, LocalPoint } from "../../math";
import { import {
point, pointFrom,
segmentIncludesPoint, segmentIncludesPoint,
pointRotateRads, pointRotateRads,
type Radians, type Radians,
@ -92,9 +92,9 @@ export const resizeTest = <Point extends GlobalPoint | LocalPoint>(
if (!(isLinearElement(element) && element.points.length <= 2)) { if (!(isLinearElement(element) && element.points.length <= 2)) {
const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value; const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value;
const sides = getSelectionBorders( const sides = getSelectionBorders(
point<Point>(x1 - SPACING, y1 - SPACING), pointFrom<Point>(x1 - SPACING, y1 - SPACING),
point(x2 + SPACING, y2 + SPACING), pointFrom(x2 + SPACING, y2 + SPACING),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
@ -102,7 +102,7 @@ export const resizeTest = <Point extends GlobalPoint | LocalPoint>(
// test to see if x, y are on the line segment // test to see if x, y are on the line segment
if ( if (
segmentIncludesPoint( segmentIncludesPoint(
point<Point>(x, y), pointFrom<Point>(x, y),
side as Segment<Point>, side as Segment<Point>,
SPACING, SPACING,
) )
@ -178,9 +178,9 @@ export const getTransformHandleTypeFromCoords = (
const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value; const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value;
const sides = getSelectionBorders( const sides = getSelectionBorders(
point<GlobalPoint>(x1 - SPACING, y1 - SPACING), pointFrom<GlobalPoint>(x1 - SPACING, y1 - SPACING),
point(x2 + SPACING, y2 + SPACING), pointFrom(x2 + SPACING, y2 + SPACING),
point(cx, cy), pointFrom(cx, cy),
0 as Radians, 0 as Radians,
); );
@ -265,10 +265,10 @@ const getSelectionBorders = <Point extends LocalPoint | GlobalPoint>(
center: Point, center: Point,
angle: Radians, angle: Radians,
) => { ) => {
const topLeft = pointRotateRads(point(x1, y1), center, angle); const topLeft = pointRotateRads(pointFrom(x1, y1), center, angle);
const topRight = pointRotateRads(point(x2, y1), center, angle); const topRight = pointRotateRads(pointFrom(x2, y1), center, angle);
const bottomLeft = pointRotateRads(point(x1, y2), center, angle); const bottomLeft = pointRotateRads(pointFrom(x1, y2), center, angle);
const bottomRight = pointRotateRads(point(x2, y2), center, angle); const bottomRight = pointRotateRads(pointFrom(x2, y2), center, angle);
return { return {
n: [topLeft, topRight], n: [topLeft, topRight],

View file

@ -17,7 +17,7 @@ import type {
ExcalidrawElbowArrowElement, ExcalidrawElbowArrowElement,
} from "./types"; } from "./types";
import { ARROW_TYPE } from "../constants"; import { ARROW_TYPE } from "../constants";
import { point } from "../../math"; import { pointFrom } from "../../math";
const { h } = window; const { h } = window;
@ -32,8 +32,8 @@ describe("elbow arrow routing", () => {
}) as ExcalidrawElbowArrowElement; }) as ExcalidrawElbowArrowElement;
scene.insertElement(arrow); scene.insertElement(arrow);
mutateElbowArrow(arrow, scene.getNonDeletedElementsMap(), [ mutateElbowArrow(arrow, scene.getNonDeletedElementsMap(), [
point(-45 - arrow.x, -100.1 - arrow.y), pointFrom(-45 - arrow.x, -100.1 - arrow.y),
point(45 - arrow.x, 99.9 - arrow.y), pointFrom(45 - arrow.x, 99.9 - arrow.y),
]); ]);
expect(arrow.points).toEqual([ expect(arrow.points).toEqual([
[0, 0], [0, 0],
@ -69,7 +69,7 @@ describe("elbow arrow routing", () => {
y: -100.1, y: -100.1,
width: 90, width: 90,
height: 200, height: 200,
points: [point(0, 0), point(90, 200)], points: [pointFrom(0, 0), pointFrom(90, 200)],
}) as ExcalidrawElbowArrowElement; }) as ExcalidrawElbowArrowElement;
scene.insertElement(rectangle1); scene.insertElement(rectangle1);
scene.insertElement(rectangle2); scene.insertElement(rectangle2);
@ -81,7 +81,7 @@ describe("elbow arrow routing", () => {
expect(arrow.startBinding).not.toBe(null); expect(arrow.startBinding).not.toBe(null);
expect(arrow.endBinding).not.toBe(null); expect(arrow.endBinding).not.toBe(null);
mutateElbowArrow(arrow, elementsMap, [point(0, 0), point(90, 200)]); mutateElbowArrow(arrow, elementsMap, [pointFrom(0, 0), pointFrom(90, 200)]);
expect(arrow.points).toEqual([ expect(arrow.points).toEqual([
[0, 0], [0, 0],

View file

@ -1,7 +1,7 @@
import type { Radians } from "../../math"; import type { Radians } from "../../math";
import { import {
pointExtent, pointExtent,
point, pointFrom,
pointScaleFromOrigin, pointScaleFromOrigin,
pointTranslate, pointTranslate,
vector, vector,
@ -743,13 +743,13 @@ const getDonglePosition = (
): GlobalPoint => { ): GlobalPoint => {
switch (heading) { switch (heading) {
case HEADING_UP: case HEADING_UP:
return point(p[0], bounds[1]); return pointFrom(p[0], bounds[1]);
case HEADING_RIGHT: case HEADING_RIGHT:
return point(bounds[2], p[1]); return pointFrom(bounds[2], p[1]);
case HEADING_DOWN: case HEADING_DOWN:
return point(p[0], bounds[3]); return pointFrom(p[0], bounds[3]);
} }
return point(bounds[0], p[1]); return pointFrom(bounds[0], p[1]);
}; };
const estimateSegmentCount = ( const estimateSegmentCount = (

View file

@ -19,7 +19,7 @@ import type {
import { API } from "../tests/helpers/api"; import { API } from "../tests/helpers/api";
import { getOriginalContainerHeightFromCache } from "./containerCache"; import { getOriginalContainerHeightFromCache } from "./containerCache";
import { getTextEditor, updateTextEditor } from "../tests/queries/dom"; import { getTextEditor, updateTextEditor } from "../tests/queries/dom";
import { point } from "../../math"; import { pointFrom } from "../../math";
// Unmount ReactDOM from root // Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!); ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
@ -42,7 +42,7 @@ describe("textWysiwyg", () => {
type: "line", type: "line",
width: 100, width: 100,
height: 0, height: 0,
points: [point(0, 0), point(100, 0)], points: [pointFrom(0, 0), pointFrom(100, 0)],
}); });
const textSize = 20; const textSize = 20;
const text = API.createElement({ const text = API.createElement({

View file

@ -19,7 +19,7 @@ import {
isIOS, isIOS,
} from "../constants"; } from "../constants";
import type { Radians } from "../../math"; import type { Radians } from "../../math";
import { point, pointRotateRads } from "../../math"; import { pointFrom, pointRotateRads } from "../../math";
export type TransformHandleDirection = export type TransformHandleDirection =
| "n" | "n"
@ -95,8 +95,8 @@ const generateTransformHandle = (
angle: Radians, angle: Radians,
): TransformHandle => { ): TransformHandle => {
const [xx, yy] = pointRotateRads( const [xx, yy] = pointRotateRads(
point(x + width / 2, y + height / 2), pointFrom(x + width / 2, y + height / 2),
point(cx, cy), pointFrom(cx, cy),
angle, angle,
); );
return [xx - width / 2, yy - height / 2, width, height]; return [xx - width / 2, yy - height / 2, width, height];

View file

@ -37,9 +37,9 @@ import type { GlobalPoint, Segment } from "../math";
import { import {
isPointWithinBounds, isPointWithinBounds,
segment, segment,
point,
pointRotateRads, pointRotateRads,
segmentsIntersectAt, segmentsIntersectAt,
pointFrom,
} from "../math"; } from "../math";
// --------------------------- Frame State ------------------------------------ // --------------------------- Frame State ------------------------------------
@ -88,7 +88,7 @@ const getElementLineSegments = (
elementsMap, elementsMap,
); );
const center: GlobalPoint = point(cx, cy); const center: GlobalPoint = pointFrom(cx, cy);
if (isLinearElement(element) || isFreeDrawElement(element)) { if (isLinearElement(element) || isFreeDrawElement(element)) {
const segments: Segment<GlobalPoint>[] = []; const segments: Segment<GlobalPoint>[] = [];
@ -99,7 +99,7 @@ const getElementLineSegments = (
segments.push( segments.push(
segment( segment(
pointRotateRads( pointRotateRads(
point( pointFrom(
element.points[i][0] + element.x, element.points[i][0] + element.x,
element.points[i][1] + element.y, element.points[i][1] + element.y,
), ),
@ -107,7 +107,7 @@ const getElementLineSegments = (
element.angle, element.angle,
), ),
pointRotateRads( pointRotateRads(
point( pointFrom(
element.points[i + 1][0] + element.x, element.points[i + 1][0] + element.x,
element.points[i + 1][1] + element.y, element.points[i + 1][1] + element.y,
), ),
@ -256,7 +256,11 @@ export const isCursorInFrame = (
) => { ) => {
const [fx1, fy1, fx2, fy2] = getElementAbsoluteCoords(frame, elementsMap); const [fx1, fy1, fx2, fy2] = getElementAbsoluteCoords(frame, elementsMap);
return isPointWithinBounds(point(fx1, fy1), cursorCoords, point(fx2, fy2)); return isPointWithinBounds(
pointFrom(fx1, fy1),
cursorCoords,
pointFrom(fx2, fy2),
);
}; };
export const groupsAreAtLeastIntersectingTheFrame = ( export const groupsAreAtLeastIntersectingTheFrame = (

View file

@ -1,5 +1,5 @@
import type { ViewportPoint } from "../../math"; import type { ViewportPoint } from "../../math";
import { point, type GlobalPoint, type LocalPoint } from "../../math"; import { pointFrom, type GlobalPoint, type LocalPoint } from "../../math";
import { THEME } from "../constants"; import { THEME } from "../constants";
import type { PointSnapLine, PointerSnapLine } from "../snapping"; import type { PointSnapLine, PointerSnapLine } from "../snapping";
import type { InteractiveCanvasAppState } from "../types"; import type { InteractiveCanvasAppState } from "../types";
@ -141,27 +141,31 @@ const drawGapLine = <Point extends LocalPoint | GlobalPoint | ViewportPoint>(
// (1) // (1)
if (!appState.zenModeEnabled) { if (!appState.zenModeEnabled) {
drawLine( drawLine(
point(from[0], from[1] - FULL), pointFrom(from[0], from[1] - FULL),
point(from[0], from[1] + FULL), pointFrom(from[0], from[1] + FULL),
context, context,
); );
} }
// (3) // (3)
drawLine( drawLine(
point(halfPoint[0] - QUARTER, halfPoint[1] - HALF), pointFrom(halfPoint[0] - QUARTER, halfPoint[1] - HALF),
point(halfPoint[0] - QUARTER, halfPoint[1] + HALF), pointFrom(halfPoint[0] - QUARTER, halfPoint[1] + HALF),
context, context,
); );
drawLine( drawLine(
point(halfPoint[0] + QUARTER, halfPoint[1] - HALF), pointFrom(halfPoint[0] + QUARTER, halfPoint[1] - HALF),
point(halfPoint[0] + QUARTER, halfPoint[1] + HALF), pointFrom(halfPoint[0] + QUARTER, halfPoint[1] + HALF),
context, context,
); );
if (!appState.zenModeEnabled) { if (!appState.zenModeEnabled) {
// (4) // (4)
drawLine(point(to[0], to[1] - FULL), point(to[0], to[1] + FULL), context); drawLine(
pointFrom(to[0], to[1] - FULL),
pointFrom(to[0], to[1] + FULL),
context,
);
// (2) // (2)
drawLine(from, to, context); drawLine(from, to, context);
@ -171,27 +175,31 @@ const drawGapLine = <Point extends LocalPoint | GlobalPoint | ViewportPoint>(
// (1) // (1)
if (!appState.zenModeEnabled) { if (!appState.zenModeEnabled) {
drawLine( drawLine(
point(from[0] - FULL, from[1]), pointFrom(from[0] - FULL, from[1]),
point(from[0] + FULL, from[1]), pointFrom(from[0] + FULL, from[1]),
context, context,
); );
} }
// (3) // (3)
drawLine( drawLine(
point(halfPoint[0] - HALF, halfPoint[1] - QUARTER), pointFrom(halfPoint[0] - HALF, halfPoint[1] - QUARTER),
point(halfPoint[0] + HALF, halfPoint[1] - QUARTER), pointFrom(halfPoint[0] + HALF, halfPoint[1] - QUARTER),
context, context,
); );
drawLine( drawLine(
point(halfPoint[0] - HALF, halfPoint[1] + QUARTER), pointFrom(halfPoint[0] - HALF, halfPoint[1] + QUARTER),
point(halfPoint[0] + HALF, halfPoint[1] + QUARTER), pointFrom(halfPoint[0] + HALF, halfPoint[1] + QUARTER),
context, context,
); );
if (!appState.zenModeEnabled) { if (!appState.zenModeEnabled) {
// (4) // (4)
drawLine(point(to[0] - FULL, to[1]), point(to[0] + FULL, to[1]), context); drawLine(
pointFrom(to[0] - FULL, to[1]),
pointFrom(to[0] + FULL, to[1]),
context,
);
// (2) // (2)
drawLine(from, to, context); drawLine(from, to, context);

View file

@ -25,7 +25,7 @@ import { canChangeRoundness } from "./comparisons";
import type { EmbedsValidationStatus } from "../types"; import type { EmbedsValidationStatus } from "../types";
import { import {
pathIsALoop, pathIsALoop,
point, pointFrom,
pointDistance, pointDistance,
type GlobalPoint, type GlobalPoint,
type LocalPoint, type LocalPoint,
@ -409,7 +409,7 @@ export const _generateElementShape = (
// initial position to it // initial position to it
const points = element.points.length const points = element.points.length
? element.points ? element.points
: [point<LocalPoint>(0, 0)]; : [pointFrom<LocalPoint>(0, 0)];
if (isElbowArrow(element)) { if (isElbowArrow(element)) {
shape = [ shape = [

View file

@ -1,7 +1,7 @@
import type { GenericPoint, ViewportPoint } from "../math"; import type { GenericPoint, ViewportPoint } from "../math";
import { import {
isPoint, isPoint,
point, pointFrom,
pointDistance, pointDistance,
pointFromPair, pointFromPair,
pointRotateRads, pointRotateRads,
@ -167,15 +167,15 @@ export const getElementShape = (
? getClosedCurveShape<GlobalPoint>( ? getClosedCurveShape<GlobalPoint>(
element, element,
roughShape, roughShape,
point<GlobalPoint>(element.x, element.y), pointFrom<GlobalPoint>(element.x, element.y),
element.angle, element.angle,
point(cx, cy), pointFrom(cx, cy),
) )
: getCurveShape<GlobalPoint>( : getCurveShape<GlobalPoint>(
roughShape, roughShape,
point<GlobalPoint>(element.x, element.y), pointFrom<GlobalPoint>(element.x, element.y),
element.angle, element.angle,
point(cx, cy), pointFrom(cx, cy),
); );
} }
@ -186,7 +186,7 @@ export const getElementShape = (
const [, , , , cx, cy] = getElementAbsoluteCoords(element, elementsMap); const [, , , , cx, cy] = getElementAbsoluteCoords(element, elementsMap);
return getFreedrawShape( return getFreedrawShape(
element, element,
point(cx, cy), pointFrom(cx, cy),
shouldTestInside(element), shouldTestInside(element),
); );
} }
@ -231,7 +231,7 @@ export const getControlPointsForBezierCurve = <P extends GenericPoint>(
} }
const ops = getCurvePathOps(shape[0]); const ops = getCurvePathOps(shape[0]);
let currentP = point<P>(0, 0); let currentP = pointFrom<P>(0, 0);
let index = 0; let index = 0;
let minDistance = Infinity; let minDistance = Infinity;
let controlPoints: P[] | null = null; let controlPoints: P[] | null = null;
@ -247,9 +247,9 @@ export const getControlPointsForBezierCurve = <P extends GenericPoint>(
} }
if (op === "bcurveTo") { if (op === "bcurveTo") {
const p0 = currentP; const p0 = currentP;
const p1 = point<P>(data[0], data[1]); const p1 = pointFrom<P>(data[0], data[1]);
const p2 = point<P>(data[2], data[3]); const p2 = pointFrom<P>(data[2], data[3]);
const p3 = point<P>(data[4], data[5]); const p3 = pointFrom<P>(data[4], data[5]);
const distance = pointDistance(p3, endPoint); const distance = pointDistance(p3, endPoint);
if (distance < minDistance) { if (distance < minDistance) {
minDistance = distance; minDistance = distance;
@ -277,7 +277,7 @@ export const getBezierXY = <P extends GenericPoint>(
p0[idx] * Math.pow(t, 3); p0[idx] * Math.pow(t, 3);
const tx = equation(t, 0); const tx = equation(t, 0);
const ty = equation(t, 1); const ty = equation(t, 1);
return point(tx, ty); return pointFrom(tx, ty);
}; };
const getPointsInBezierCurve = <P extends GenericPoint>( const getPointsInBezierCurve = <P extends GenericPoint>(
@ -299,12 +299,12 @@ const getPointsInBezierCurve = <P extends GenericPoint>(
controlPoints[3], controlPoints[3],
t, t,
); );
pointsOnCurve.push(point(p[0], p[1])); pointsOnCurve.push(pointFrom(p[0], p[1]));
t -= 0.05; t -= 0.05;
} }
if (pointsOnCurve.length) { if (pointsOnCurve.length) {
if (pointsEqual(pointsOnCurve.at(-1)!, endPoint)) { if (pointsEqual(pointsOnCurve.at(-1)!, endPoint)) {
pointsOnCurve.push(point(endPoint[0], endPoint[1])); pointsOnCurve.push(pointFrom(endPoint[0], endPoint[1]));
} }
} }
return pointsOnCurve; return pointsOnCurve;
@ -391,24 +391,24 @@ export const aabbForElement = (
midY: element.y + element.height / 2, midY: element.y + element.height / 2,
}; };
const center = point(bbox.midX, bbox.midY); const center = pointFrom(bbox.midX, bbox.midY);
const [topLeftX, topLeftY] = pointRotateRads( const [topLeftX, topLeftY] = pointRotateRads(
point(bbox.minX, bbox.minY), pointFrom(bbox.minX, bbox.minY),
center, center,
element.angle, element.angle,
); );
const [topRightX, topRightY] = pointRotateRads( const [topRightX, topRightY] = pointRotateRads(
point(bbox.maxX, bbox.minY), pointFrom(bbox.maxX, bbox.minY),
center, center,
element.angle, element.angle,
); );
const [bottomRightX, bottomRightY] = pointRotateRads( const [bottomRightX, bottomRightY] = pointRotateRads(
point(bbox.maxX, bbox.maxY), pointFrom(bbox.maxX, bbox.maxY),
center, center,
element.angle, element.angle,
); );
const [bottomLeftX, bottomLeftY] = pointRotateRads( const [bottomLeftX, bottomLeftY] = pointRotateRads(
point(bbox.minX, bbox.maxY), pointFrom(bbox.minX, bbox.maxY),
center, center,
element.angle, element.angle,
); );
@ -442,14 +442,14 @@ export const pointInsideBounds = <
p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3]; p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3];
export const aabbsOverlapping = (a: Bounds, b: Bounds) => export const aabbsOverlapping = (a: Bounds, b: Bounds) =>
pointInsideBounds(point(a[0], a[1]), b) || pointInsideBounds(pointFrom(a[0], a[1]), b) ||
pointInsideBounds(point(a[2], a[1]), b) || pointInsideBounds(pointFrom(a[2], a[1]), b) ||
pointInsideBounds(point(a[2], a[3]), b) || pointInsideBounds(pointFrom(a[2], a[3]), b) ||
pointInsideBounds(point(a[0], a[3]), b) || pointInsideBounds(pointFrom(a[0], a[3]), b) ||
pointInsideBounds(point(b[0], b[1]), a) || pointInsideBounds(pointFrom(b[0], b[1]), a) ||
pointInsideBounds(point(b[2], b[1]), a) || pointInsideBounds(pointFrom(b[2], b[1]), a) ||
pointInsideBounds(point(b[2], b[3]), a) || pointInsideBounds(pointFrom(b[2], b[3]), a) ||
pointInsideBounds(point(b[0], b[3]), a); pointInsideBounds(pointFrom(b[0], b[3]), a);
export const getCornerRadius = (x: number, element: ExcalidrawElement) => { export const getCornerRadius = (x: number, element: ExcalidrawElement) => {
if ( if (

View file

@ -1,6 +1,6 @@
import type { InclusiveRange } from "../math"; import type { InclusiveRange } from "../math";
import { import {
point, pointFrom,
pointRotateRads, pointRotateRads,
rangeInclusive, rangeInclusive,
rangeIntersection, rangeIntersection,
@ -228,52 +228,52 @@ export const getElementsCorners = (
!boundingBoxCorners !boundingBoxCorners
) { ) {
const leftMid = pointRotateRads<GlobalPoint>( const leftMid = pointRotateRads<GlobalPoint>(
point(x1, y1 + halfHeight), pointFrom(x1, y1 + halfHeight),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const topMid = pointRotateRads<GlobalPoint>( const topMid = pointRotateRads<GlobalPoint>(
point(x1 + halfWidth, y1), pointFrom(x1 + halfWidth, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const rightMid = pointRotateRads<GlobalPoint>( const rightMid = pointRotateRads<GlobalPoint>(
point(x2, y1 + halfHeight), pointFrom(x2, y1 + halfHeight),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const bottomMid = pointRotateRads<GlobalPoint>( const bottomMid = pointRotateRads<GlobalPoint>(
point(x1 + halfWidth, y2), pointFrom(x1 + halfWidth, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const center = point<GlobalPoint>(cx, cy); const center = pointFrom<GlobalPoint>(cx, cy);
result = omitCenter result = omitCenter
? [leftMid, topMid, rightMid, bottomMid] ? [leftMid, topMid, rightMid, bottomMid]
: [leftMid, topMid, rightMid, bottomMid, center]; : [leftMid, topMid, rightMid, bottomMid, center];
} else { } else {
const topLeft = pointRotateRads<GlobalPoint>( const topLeft = pointRotateRads<GlobalPoint>(
point(x1, y1), pointFrom(x1, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const topRight = pointRotateRads<GlobalPoint>( const topRight = pointRotateRads<GlobalPoint>(
point(x2, y1), pointFrom(x2, y1),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const bottomLeft = pointRotateRads<GlobalPoint>( const bottomLeft = pointRotateRads<GlobalPoint>(
point(x1, y2), pointFrom(x1, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const bottomRight = pointRotateRads<GlobalPoint>( const bottomRight = pointRotateRads<GlobalPoint>(
point(x2, y2), pointFrom(x2, y2),
point(cx, cy), pointFrom(cx, cy),
element.angle, element.angle,
); );
const center = point<GlobalPoint>(cx, cy); const center = pointFrom<GlobalPoint>(cx, cy);
result = omitCenter result = omitCenter
? [topLeft, topRight, bottomLeft, bottomRight] ? [topLeft, topRight, bottomLeft, bottomRight]
@ -287,18 +287,18 @@ export const getElementsCorners = (
const width = maxX - minX; const width = maxX - minX;
const height = maxY - minY; const height = maxY - minY;
const topLeft = point<GlobalPoint>(minX, minY); const topLeft = pointFrom<GlobalPoint>(minX, minY);
const topRight = point<GlobalPoint>(maxX, minY); const topRight = pointFrom<GlobalPoint>(maxX, minY);
const bottomLeft = point<GlobalPoint>(minX, maxY); const bottomLeft = pointFrom<GlobalPoint>(minX, maxY);
const bottomRight = point<GlobalPoint>(maxX, maxY); const bottomRight = pointFrom<GlobalPoint>(maxX, maxY);
const center = point<GlobalPoint>(minX + width / 2, minY + height / 2); const center = pointFrom<GlobalPoint>(minX + width / 2, minY + height / 2);
result = omitCenter result = omitCenter
? [topLeft, topRight, bottomLeft, bottomRight] ? [topLeft, topRight, bottomLeft, bottomRight]
: [topLeft, topRight, bottomLeft, bottomRight, center]; : [topLeft, topRight, bottomLeft, bottomRight, center];
} }
return result.map((p) => point(round(p[0]), round(p[1]))); return result.map((p) => pointFrom(round(p[0]), round(p[1])));
}; };
const getReferenceElements = ( const getReferenceElements = (
@ -375,8 +375,11 @@ export const getVisibleGaps = (
horizontalGaps.push({ horizontalGaps.push({
startBounds, startBounds,
endBounds, endBounds,
startSide: [point(startMaxX, startMinY), point(startMaxX, startMaxY)], startSide: [
endSide: [point(endMinX, endMinY), point(endMinX, endMaxY)], pointFrom(startMaxX, startMinY),
pointFrom(startMaxX, startMaxY),
],
endSide: [pointFrom(endMinX, endMinY), pointFrom(endMinX, endMaxY)],
length: endMinX - startMaxX, length: endMinX - startMaxX,
overlap: rangeIntersection( overlap: rangeIntersection(
rangeInclusive(startMinY, startMaxY), rangeInclusive(startMinY, startMaxY),
@ -415,8 +418,11 @@ export const getVisibleGaps = (
verticalGaps.push({ verticalGaps.push({
startBounds, startBounds,
endBounds, endBounds,
startSide: [point(startMinX, startMaxY), point(startMaxX, startMaxY)], startSide: [
endSide: [point(endMinX, endMinY), point(endMaxX, endMinY)], pointFrom(startMinX, startMaxY),
pointFrom(startMaxX, startMaxY),
],
endSide: [pointFrom(endMinX, endMinY), pointFrom(endMaxX, endMinY)],
length: endMinY - startMaxY, length: endMinY - startMaxY,
overlap: rangeIntersection( overlap: rangeIntersection(
rangeInclusive(startMinX, startMaxX), rangeInclusive(startMinX, startMaxX),
@ -832,7 +838,7 @@ const createPointSnapLines = (
} }
snapsX[key].push( snapsX[key].push(
...snap.points.map((p) => ...snap.points.map((p) =>
point<GlobalPoint>(round(p[0]), round(p[1])), pointFrom<GlobalPoint>(round(p[0]), round(p[1])),
), ),
); );
} }
@ -849,7 +855,7 @@ const createPointSnapLines = (
} }
snapsY[key].push( snapsY[key].push(
...snap.points.map((p) => ...snap.points.map((p) =>
point<GlobalPoint>(round(p[0]), round(p[1])), pointFrom<GlobalPoint>(round(p[0]), round(p[1])),
), ),
); );
} }
@ -863,7 +869,7 @@ const createPointSnapLines = (
points: dedupePoints( points: dedupePoints(
points points
.map((p) => { .map((p) => {
return point<GlobalPoint>(Number(key), p[1]); return pointFrom<GlobalPoint>(Number(key), p[1]);
}) })
.sort((a, b) => a[1] - b[1]), .sort((a, b) => a[1] - b[1]),
), ),
@ -876,7 +882,7 @@ const createPointSnapLines = (
points: dedupePoints( points: dedupePoints(
points points
.map((p) => { .map((p) => {
return point<GlobalPoint>(p[0], Number(key)); return pointFrom<GlobalPoint>(p[0], Number(key));
}) })
.sort((a, b) => a[0] - b[0]), .sort((a, b) => a[0] - b[0]),
), ),
@ -940,16 +946,16 @@ const createGapSnapLines = (
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [ points: [
point(gapSnap.gap.startSide[0][0], gapLineY), pointFrom(gapSnap.gap.startSide[0][0], gapLineY),
point(minX, gapLineY), pointFrom(minX, gapLineY),
], ],
}, },
{ {
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [ points: [
point(maxX, gapLineY), pointFrom(maxX, gapLineY),
point(gapSnap.gap.endSide[0][0], gapLineY), pointFrom(gapSnap.gap.endSide[0][0], gapLineY),
], ],
}, },
); );
@ -966,16 +972,16 @@ const createGapSnapLines = (
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [ points: [
point(gapLineX, gapSnap.gap.startSide[0][1]), pointFrom(gapLineX, gapSnap.gap.startSide[0][1]),
point(gapLineX, minY), pointFrom(gapLineX, minY),
], ],
}, },
{ {
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [ points: [
point(gapLineX, maxY), pointFrom(gapLineX, maxY),
point(gapLineX, gapSnap.gap.endSide[0][1]), pointFrom(gapLineX, gapSnap.gap.endSide[0][1]),
], ],
}, },
); );
@ -991,12 +997,15 @@ const createGapSnapLines = (
{ {
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [point(startMaxX, gapLineY), point(endMinX, gapLineY)], points: [
pointFrom(startMaxX, gapLineY),
pointFrom(endMinX, gapLineY),
],
}, },
{ {
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [point(endMaxX, gapLineY), point(minX, gapLineY)], points: [pointFrom(endMaxX, gapLineY), pointFrom(minX, gapLineY)],
}, },
); );
} }
@ -1011,12 +1020,18 @@ const createGapSnapLines = (
{ {
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [point(maxX, gapLineY), point(startMinX, gapLineY)], points: [
pointFrom(maxX, gapLineY),
pointFrom(startMinX, gapLineY),
],
}, },
{ {
type: "gap", type: "gap",
direction: "horizontal", direction: "horizontal",
points: [point(startMaxX, gapLineY), point(endMinX, gapLineY)], points: [
pointFrom(startMaxX, gapLineY),
pointFrom(endMinX, gapLineY),
],
}, },
); );
} }
@ -1031,12 +1046,18 @@ const createGapSnapLines = (
{ {
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [point(gapLineX, maxY), point(gapLineX, startMinY)], points: [
pointFrom(gapLineX, maxY),
pointFrom(gapLineX, startMinY),
],
}, },
{ {
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [point(gapLineX, startMaxY), point(gapLineX, endMinY)], points: [
pointFrom(gapLineX, startMaxY),
pointFrom(gapLineX, endMinY),
],
}, },
); );
} }
@ -1051,12 +1072,15 @@ const createGapSnapLines = (
{ {
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [point(gapLineX, startMaxY), point(gapLineX, endMinY)], points: [
pointFrom(gapLineX, startMaxY),
pointFrom(gapLineX, endMinY),
],
}, },
{ {
type: "gap", type: "gap",
direction: "vertical", direction: "vertical",
points: [point(gapLineX, endMaxY), point(gapLineX, minY)], points: [pointFrom(gapLineX, endMaxY), pointFrom(gapLineX, minY)],
}, },
); );
} }
@ -1070,7 +1094,7 @@ const createGapSnapLines = (
return { return {
...gapSnapLine, ...gapSnapLine,
points: gapSnapLine.points.map((p) => points: gapSnapLine.points.map((p) =>
point(round(p[0]), round(p[1])), pointFrom(round(p[0]), round(p[1])),
) as PointPair, ) as PointPair,
}; };
}), }),
@ -1120,35 +1144,35 @@ export const snapResizingElements = (
if (transformHandle) { if (transformHandle) {
switch (transformHandle) { switch (transformHandle) {
case "e": { case "e": {
selectionSnapPoints.push(point(maxX, minY), point(maxX, maxY)); selectionSnapPoints.push(pointFrom(maxX, minY), pointFrom(maxX, maxY));
break; break;
} }
case "w": { case "w": {
selectionSnapPoints.push(point(minX, minY), point(minX, maxY)); selectionSnapPoints.push(pointFrom(minX, minY), pointFrom(minX, maxY));
break; break;
} }
case "n": { case "n": {
selectionSnapPoints.push(point(minX, minY), point(maxX, minY)); selectionSnapPoints.push(pointFrom(minX, minY), pointFrom(maxX, minY));
break; break;
} }
case "s": { case "s": {
selectionSnapPoints.push(point(minX, maxY), point(maxX, maxY)); selectionSnapPoints.push(pointFrom(minX, maxY), pointFrom(maxX, maxY));
break; break;
} }
case "ne": { case "ne": {
selectionSnapPoints.push(point(maxX, minY)); selectionSnapPoints.push(pointFrom(maxX, minY));
break; break;
} }
case "nw": { case "nw": {
selectionSnapPoints.push(point(minX, minY)); selectionSnapPoints.push(pointFrom(minX, minY));
break; break;
} }
case "se": { case "se": {
selectionSnapPoints.push(point(maxX, maxY)); selectionSnapPoints.push(pointFrom(maxX, maxY));
break; break;
} }
case "sw": { case "sw": {
selectionSnapPoints.push(point(minX, maxY)); selectionSnapPoints.push(pointFrom(minX, maxY));
break; break;
} }
} }
@ -1191,10 +1215,10 @@ export const snapResizingElements = (
); );
const corners: GlobalPoint[] = [ const corners: GlobalPoint[] = [
point(x1, y1), pointFrom(x1, y1),
point(x1, y2), pointFrom(x1, y2),
point(x2, y1), pointFrom(x2, y1),
point(x2, y2), pointFrom(x2, y2),
]; ];
getPointSnaps( getPointSnaps(
@ -1231,7 +1255,7 @@ export const snapNewElement = (
} }
const selectionSnapPoints: GlobalPoint[] = [ const selectionSnapPoints: GlobalPoint[] = [
point(origin.x + dragOffset.x, origin.y + dragOffset.y), pointFrom(origin.x + dragOffset.x, origin.y + dragOffset.y),
]; ];
const snapDistance = getSnapDistance(app.state.zoom.value); const snapDistance = getSnapDistance(app.state.zoom.value);
@ -1331,7 +1355,7 @@ export const getSnapLinesAtPointer = (
verticalSnapLines.push({ verticalSnapLines.push({
type: "pointer", type: "pointer",
points: [corner, point(corner[0], pointer.y)], points: [corner, pointFrom(corner[0], pointer.y)],
direction: "vertical", direction: "vertical",
}); });
@ -1347,7 +1371,7 @@ export const getSnapLinesAtPointer = (
horizontalSnapLines.push({ horizontalSnapLines.push({
type: "pointer", type: "pointer",
points: [corner, point(pointer.x, corner[1])], points: [corner, pointFrom(pointer.x, corner[1])],
direction: "horizontal", direction: "horizontal",
}); });

View file

@ -7,7 +7,7 @@ import { API } from "./helpers/api";
import { KEYS } from "../keys"; import { KEYS } from "../keys";
import { actionWrapTextInContainer } from "../actions/actionBoundText"; import { actionWrapTextInContainer } from "../actions/actionBoundText";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import { point } from "../../math"; import { pointFrom } from "../../math";
const { h } = window; const { h } = window;
@ -32,7 +32,12 @@ describe("element binding", () => {
y: 0, y: 0,
width: 100, width: 100,
height: 1, height: 1,
points: [point(0, 0), point(0, 0), point(100, 0), point(100, 0)], points: [
pointFrom(0, 0),
pointFrom(0, 0),
pointFrom(100, 0),
pointFrom(100, 0),
],
}); });
API.setElements([rect, arrow]); API.setElements([rect, arrow]);
expect(arrow.startBinding).toBe(null); expect(arrow.startBinding).toBe(null);
@ -310,7 +315,7 @@ describe("element binding", () => {
const arrow1 = API.createElement({ const arrow1 = API.createElement({
type: "arrow", type: "arrow",
id: "arrow1", id: "arrow1",
points: [point(0, 0), point(0, -87.45777932247563)], points: [pointFrom(0, 0), pointFrom(0, -87.45777932247563)],
startBinding: { startBinding: {
elementId: "rectangle1", elementId: "rectangle1",
focus: 0.2, focus: 0.2,
@ -328,7 +333,7 @@ describe("element binding", () => {
const arrow2 = API.createElement({ const arrow2 = API.createElement({
type: "arrow", type: "arrow",
id: "arrow2", id: "arrow2",
points: [point(0, 0), point(0, -87.45777932247563)], points: [pointFrom(0, 0), pointFrom(0, -87.45777932247563)],
startBinding: { startBinding: {
elementId: "text1", elementId: "text1",
focus: 0.2, focus: 0.2,

View file

@ -38,7 +38,7 @@ import type App from "../../components/App";
import { createTestHook } from "../../components/App"; import { createTestHook } from "../../components/App";
import type { Action } from "../../actions/types"; import type { Action } from "../../actions/types";
import { mutateElement } from "../../element/mutateElement"; import { mutateElement } from "../../element/mutateElement";
import { point, type LocalPoint, type Radians } from "../../../math"; import { pointFrom, type LocalPoint, type Radians } from "../../../math";
const readFile = util.promisify(fs.readFile); const readFile = util.promisify(fs.readFile);
// so that window.h is available when App.tsx is not imported as well. // so that window.h is available when App.tsx is not imported as well.
@ -307,8 +307,8 @@ export class API {
height, height,
type, type,
points: rest.points ?? [ points: rest.points ?? [
point<LocalPoint>(0, 0), pointFrom<LocalPoint>(0, 0),
point<LocalPoint>(100, 100), pointFrom<LocalPoint>(100, 100),
], ],
elbowed: rest.elbowed ?? false, elbowed: rest.elbowed ?? false,
}); });
@ -320,8 +320,8 @@ export class API {
height, height,
type, type,
points: rest.points ?? [ points: rest.points ?? [
point<LocalPoint>(0, 0), pointFrom<LocalPoint>(0, 0),
point<LocalPoint>(100, 100), pointFrom<LocalPoint>(100, 100),
], ],
}); });
break; break;

View file

@ -34,7 +34,7 @@ import { getTextEditor } from "../queries/dom";
import { arrayToMap } from "../../utils"; import { arrayToMap } from "../../utils";
import { createTestHook } from "../../components/App"; import { createTestHook } from "../../components/App";
import type { GlobalPoint, LocalPoint, Radians } from "../../../math"; import type { GlobalPoint, LocalPoint, Radians } from "../../../math";
import { point, pointRotateRads } from "../../../math"; import { pointFrom, pointRotateRads } from "../../../math";
// so that window.h is available when App.tsx is not imported as well. // so that window.h is available when App.tsx is not imported as well.
createTestHook(); createTestHook();
@ -142,7 +142,7 @@ const getElementPointForSelection = (
element: ExcalidrawElement, element: ExcalidrawElement,
): GlobalPoint => { ): GlobalPoint => {
const { x, y, width, height, angle } = element; const { x, y, width, height, angle } = element;
const target = point<GlobalPoint>( const target = pointFrom<GlobalPoint>(
x + x +
(isLinearElement(element) || isFreeDrawElement(element) ? 0 : width / 2), (isLinearElement(element) || isFreeDrawElement(element) ? 0 : width / 2),
y, y,
@ -151,9 +151,12 @@ const getElementPointForSelection = (
if (isLinearElement(element)) { if (isLinearElement(element)) {
const bounds = getElementPointsCoords(element, element.points); const bounds = getElementPointsCoords(element, element.points);
center = point((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2); center = pointFrom(
(bounds[0] + bounds[2]) / 2,
(bounds[1] + bounds[3]) / 2,
);
} else { } else {
center = point(x + width / 2, y + height / 2); center = pointFrom(x + width / 2, y + height / 2);
} }
if (isTextElement(element)) { if (isTextElement(element)) {
@ -469,8 +472,8 @@ export class UI {
const width = initialWidth ?? initialHeight ?? size; const width = initialWidth ?? initialHeight ?? size;
const height = initialHeight ?? size; const height = initialHeight ?? size;
const points: LocalPoint[] = initialPoints ?? [ const points: LocalPoint[] = initialPoints ?? [
point(0, 0), pointFrom(0, 0),
point(width, height), pointFrom(width, height),
]; ];
UI.clickTool(type); UI.clickTool(type);

View file

@ -46,7 +46,7 @@ import { HistoryEntry } from "../history";
import { AppStateChange, ElementsChange } from "../change"; import { AppStateChange, ElementsChange } from "../change";
import { Snapshot, StoreAction } from "../store"; import { Snapshot, StoreAction } from "../store";
import type { LocalPoint, Radians } from "../../math"; import type { LocalPoint, Radians } from "../../math";
import { point } from "../../math"; import { pointFrom } from "../../math";
const { h } = window; const { h } = window;
@ -2041,9 +2041,9 @@ describe("history", () => {
width: 178.9000000000001, width: 178.9000000000001,
height: 236.10000000000002, height: 236.10000000000002,
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(178.9000000000001, 0), pointFrom(178.9000000000001, 0),
point(178.9000000000001, 236.10000000000002), pointFrom(178.9000000000001, 236.10000000000002),
], ],
startBinding: { startBinding: {
elementId: "KPrBI4g_v9qUB1XxYLgSz", elementId: "KPrBI4g_v9qUB1XxYLgSz",
@ -2159,11 +2159,11 @@ describe("history", () => {
elements: [ elements: [
newElementWith(h.elements[0] as ExcalidrawLinearElement, { newElementWith(h.elements[0] as ExcalidrawLinearElement, {
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(5, 5), pointFrom(5, 5),
point(10, 10), pointFrom(10, 10),
point(15, 15), pointFrom(15, 15),
point(20, 20), pointFrom(20, 20),
] as LocalPoint[], ] as LocalPoint[],
}), }),
], ],

View file

@ -28,7 +28,7 @@ import { ROUNDNESS, VERTICAL_ALIGN } from "../constants";
import { vi } from "vitest"; import { vi } from "vitest";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import type { GlobalPoint } from "../../math"; import type { GlobalPoint } from "../../math";
import { pointCenter, point } from "../../math"; import { pointCenter, pointFrom } from "../../math";
const renderInteractiveScene = vi.spyOn( const renderInteractiveScene = vi.spyOn(
InteractiveCanvas, InteractiveCanvas,
@ -57,8 +57,8 @@ describe("Test Linear Elements", () => {
interactiveCanvas = container.querySelector("canvas.interactive")!; interactiveCanvas = container.querySelector("canvas.interactive")!;
}); });
const p1 = point<GlobalPoint>(20, 20); const p1 = pointFrom<GlobalPoint>(20, 20);
const p2 = point<GlobalPoint>(60, 20); const p2 = pointFrom<GlobalPoint>(60, 20);
const midpoint = pointCenter<GlobalPoint>(p1, p2); const midpoint = pointCenter<GlobalPoint>(p1, p2);
const delta = 50; const delta = 50;
const mouse = new Pointer("mouse"); const mouse = new Pointer("mouse");
@ -75,7 +75,7 @@ describe("Test Linear Elements", () => {
height: 0, height: 0,
type, type,
roughness, roughness,
points: [point(0, 0), point(p2[0] - p1[0], p2[1] - p1[1])], points: [pointFrom(0, 0), pointFrom(p2[0] - p1[0], p2[1] - p1[1])],
roundness, roundness,
}); });
API.setElements([line]); API.setElements([line]);
@ -99,9 +99,9 @@ describe("Test Linear Elements", () => {
type, type,
roughness, roughness,
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(p3[0], p3[1]), pointFrom(p3[0], p3[1]),
point(p2[0] - p1[0], p2[1] - p1[1]), pointFrom(p2[0] - p1[0], p2[1] - p1[1]),
], ],
roundness, roundness,
}); });
@ -161,7 +161,7 @@ describe("Test Linear Elements", () => {
expect(line.points.length).toEqual(2); expect(line.points.length).toEqual(2);
mouse.clickAt(midpoint[0], midpoint[1]); mouse.clickAt(midpoint[0], midpoint[1]);
drag(midpoint, point(midpoint[0] + 1, midpoint[1] + 1)); drag(midpoint, pointFrom(midpoint[0] + 1, midpoint[1] + 1));
expect(line.points.length).toEqual(2); expect(line.points.length).toEqual(2);
@ -169,7 +169,7 @@ describe("Test Linear Elements", () => {
expect(line.y).toBe(originalY); expect(line.y).toBe(originalY);
expect(line.points.length).toEqual(2); expect(line.points.length).toEqual(2);
drag(midpoint, point(midpoint[0] + delta, midpoint[1] + delta)); drag(midpoint, pointFrom(midpoint[0] + delta, midpoint[1] + delta));
expect(line.x).toBe(originalX); expect(line.x).toBe(originalX);
expect(line.y).toBe(originalY); expect(line.y).toBe(originalY);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
@ -184,7 +184,7 @@ describe("Test Linear Elements", () => {
expect((h.elements[0] as ExcalidrawLinearElement).points.length).toEqual(2); expect((h.elements[0] as ExcalidrawLinearElement).points.length).toEqual(2);
// drag line from midpoint // drag line from midpoint
drag(midpoint, point(midpoint[0] + delta, midpoint[1] + delta)); drag(midpoint, pointFrom(midpoint[0] + delta, midpoint[1] + delta));
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`);
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
@ -248,7 +248,7 @@ describe("Test Linear Elements", () => {
mouse.clickAt(midpoint[0], midpoint[1]); mouse.clickAt(midpoint[0], midpoint[1]);
expect(line.points.length).toEqual(2); expect(line.points.length).toEqual(2);
drag(midpoint, point(midpoint[0] + 1, midpoint[1] + 1)); drag(midpoint, pointFrom(midpoint[0] + 1, midpoint[1] + 1));
expect(line.x).toBe(originalX); expect(line.x).toBe(originalX);
expect(line.y).toBe(originalY); expect(line.y).toBe(originalY);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
@ -261,7 +261,7 @@ describe("Test Linear Elements", () => {
enterLineEditingMode(line); enterLineEditingMode(line);
// drag line from midpoint // drag line from midpoint
drag(midpoint, point(midpoint[0] + delta, midpoint[1] + delta)); drag(midpoint, pointFrom(midpoint[0] + delta, midpoint[1] + delta));
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`12`, `12`,
); );
@ -356,7 +356,7 @@ describe("Test Linear Elements", () => {
const startPoint = pointCenter(points[0], midPoints[0]!); const startPoint = pointCenter(points[0], midPoints[0]!);
const deltaX = 50; const deltaX = 50;
const deltaY = 20; const deltaY = 20;
const endPoint = point<GlobalPoint>( const endPoint = pointFrom<GlobalPoint>(
startPoint[0] + deltaX, startPoint[0] + deltaX,
startPoint[1] + deltaY, startPoint[1] + deltaY,
); );
@ -399,8 +399,8 @@ describe("Test Linear Elements", () => {
// This is the expected midpoint for line with round edge // This is the expected midpoint for line with round edge
// hence hardcoding it so if later some bug is introduced // hence hardcoding it so if later some bug is introduced
// this will fail and we can fix it // this will fail and we can fix it
const firstSegmentMidpoint = point<GlobalPoint>(55, 45); const firstSegmentMidpoint = pointFrom<GlobalPoint>(55, 45);
const lastSegmentMidpoint = point<GlobalPoint>(75, 40); const lastSegmentMidpoint = pointFrom<GlobalPoint>(75, 40);
let line: ExcalidrawLinearElement; let line: ExcalidrawLinearElement;
@ -416,7 +416,7 @@ describe("Test Linear Elements", () => {
// drag line via first segment midpoint // drag line via first segment midpoint
drag( drag(
firstSegmentMidpoint, firstSegmentMidpoint,
point( pointFrom(
firstSegmentMidpoint[0] + delta, firstSegmentMidpoint[0] + delta,
firstSegmentMidpoint[1] + delta, firstSegmentMidpoint[1] + delta,
), ),
@ -426,7 +426,10 @@ describe("Test Linear Elements", () => {
// drag line from last segment midpoint // drag line from last segment midpoint
drag( drag(
lastSegmentMidpoint, lastSegmentMidpoint,
point(lastSegmentMidpoint[0] + delta, lastSegmentMidpoint[1] + delta), pointFrom(
lastSegmentMidpoint[0] + delta,
lastSegmentMidpoint[1] + delta,
),
); );
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
@ -475,10 +478,10 @@ describe("Test Linear Elements", () => {
h.state, h.state,
); );
const hitCoords = point<GlobalPoint>(points[0][0], points[0][1]); const hitCoords = pointFrom<GlobalPoint>(points[0][0], points[0][1]);
// Drag from first point // Drag from first point
drag(hitCoords, point(hitCoords[0] - delta, hitCoords[1] - delta)); drag(hitCoords, pointFrom(hitCoords[0] - delta, hitCoords[1] - delta));
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`12`, `12`,
@ -516,10 +519,10 @@ describe("Test Linear Elements", () => {
h.state, h.state,
); );
const hitCoords = point<GlobalPoint>(points[0][0], points[0][1]); const hitCoords = pointFrom<GlobalPoint>(points[0][0], points[0][1]);
// Drag from first point // Drag from first point
drag(hitCoords, point(hitCoords[0] + delta, hitCoords[1] + delta)); drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`12`, `12`,
@ -556,7 +559,7 @@ describe("Test Linear Elements", () => {
// dragging line from last segment midpoint // dragging line from last segment midpoint
drag( drag(
lastSegmentMidpoint, lastSegmentMidpoint,
point(lastSegmentMidpoint[0] + 50, lastSegmentMidpoint[1] + 50), pointFrom(lastSegmentMidpoint[0] + 50, lastSegmentMidpoint[1] + 50),
); );
expect(line.points.length).toEqual(4); expect(line.points.length).toEqual(4);
@ -589,11 +592,11 @@ describe("Test Linear Elements", () => {
// This is the expected midpoint for line with round edge // This is the expected midpoint for line with round edge
// hence hardcoding it so if later some bug is introduced // hence hardcoding it so if later some bug is introduced
// this will fail and we can fix it // this will fail and we can fix it
const firstSegmentMidpoint = point<GlobalPoint>( const firstSegmentMidpoint = pointFrom<GlobalPoint>(
55.9697848965255, 55.9697848965255,
47.442326230998205, 47.442326230998205,
); );
const lastSegmentMidpoint = point<GlobalPoint>( const lastSegmentMidpoint = pointFrom<GlobalPoint>(
76.08587175006699, 76.08587175006699,
43.294165939653226, 43.294165939653226,
); );
@ -612,7 +615,7 @@ describe("Test Linear Elements", () => {
// drag line from first segment midpoint // drag line from first segment midpoint
drag( drag(
firstSegmentMidpoint, firstSegmentMidpoint,
point( pointFrom(
firstSegmentMidpoint[0] + delta, firstSegmentMidpoint[0] + delta,
firstSegmentMidpoint[1] + delta, firstSegmentMidpoint[1] + delta,
), ),
@ -622,7 +625,10 @@ describe("Test Linear Elements", () => {
// drag line from last segment midpoint // drag line from last segment midpoint
drag( drag(
lastSegmentMidpoint, lastSegmentMidpoint,
point(lastSegmentMidpoint[0] + delta, lastSegmentMidpoint[1] + delta), pointFrom(
lastSegmentMidpoint[0] + delta,
lastSegmentMidpoint[1] + delta,
),
); );
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`16`, `16`,
@ -669,10 +675,10 @@ describe("Test Linear Elements", () => {
h.state, h.state,
); );
const hitCoords = point<GlobalPoint>(points[0][0], points[0][1]); const hitCoords = pointFrom<GlobalPoint>(points[0][0], points[0][1]);
// Drag from first point // Drag from first point
drag(hitCoords, point(hitCoords[0] - delta, hitCoords[1] - delta)); drag(hitCoords, pointFrom(hitCoords[0] - delta, hitCoords[1] - delta));
const newPoints = LinearElementEditor.getPointsGlobalCoordinates( const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
line, line,
@ -717,10 +723,10 @@ describe("Test Linear Elements", () => {
h.state, h.state,
); );
const hitCoords = point<GlobalPoint>(points[0][0], points[0][1]); const hitCoords = pointFrom<GlobalPoint>(points[0][0], points[0][1]);
// Drag from first point // Drag from first point
drag(hitCoords, point(hitCoords[0] + delta, hitCoords[1] + delta)); drag(hitCoords, pointFrom(hitCoords[0] + delta, hitCoords[1] + delta));
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`12`, `12`,
@ -751,7 +757,10 @@ describe("Test Linear Elements", () => {
drag( drag(
lastSegmentMidpoint, lastSegmentMidpoint,
point(lastSegmentMidpoint[0] + delta, lastSegmentMidpoint[1] + delta), pointFrom(
lastSegmentMidpoint[0] + delta,
lastSegmentMidpoint[1] + delta,
),
); );
expect(line.points.length).toEqual(4); expect(line.points.length).toEqual(4);
@ -811,8 +820,8 @@ describe("Test Linear Elements", () => {
API.setSelectedElements([line]); API.setSelectedElements([line]);
enterLineEditingMode(line, true); enterLineEditingMode(line, true);
drag( drag(
point(line.points[0][0] + line.x, line.points[0][1] + line.y), pointFrom(line.points[0][0] + line.x, line.points[0][1] + line.y),
point( pointFrom(
dragEndPositionOffset[0] + line.x, dragEndPositionOffset[0] + line.x,
dragEndPositionOffset[1] + line.y, dragEndPositionOffset[1] + line.y,
), ),
@ -927,14 +936,14 @@ describe("Test Linear Elements", () => {
// This is the expected midpoint for line with round edge // This is the expected midpoint for line with round edge
// hence hardcoding it so if later some bug is introduced // hence hardcoding it so if later some bug is introduced
// this will fail and we can fix it // this will fail and we can fix it
const firstSegmentMidpoint = point<GlobalPoint>( const firstSegmentMidpoint = pointFrom<GlobalPoint>(
55.9697848965255, 55.9697848965255,
47.442326230998205, 47.442326230998205,
); );
// drag line from first segment midpoint // drag line from first segment midpoint
drag( drag(
firstSegmentMidpoint, firstSegmentMidpoint,
point( pointFrom(
firstSegmentMidpoint[0] + delta, firstSegmentMidpoint[0] + delta,
firstSegmentMidpoint[1] + delta, firstSegmentMidpoint[1] + delta,
), ),
@ -1151,7 +1160,7 @@ describe("Test Linear Elements", () => {
); );
// Drag from last point // Drag from last point
drag(points[1], point(points[1][0] + 300, points[1][1])); drag(points[1], pointFrom(points[1][0] + 300, points[1][1]));
expect({ width: container.width, height: container.height }) expect({ width: container.width, height: container.height })
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`
@ -1350,11 +1359,11 @@ describe("Test Linear Elements", () => {
[ [
{ {
index: 0, index: 0,
point: point(line.points[0][0] + 10, line.points[0][1] + 10), point: pointFrom(line.points[0][0] + 10, line.points[0][1] + 10),
}, },
{ {
index: line.points.length - 1, index: line.points.length - 1,
point: point( point: pointFrom(
line.points[line.points.length - 1][0] - 10, line.points[line.points.length - 1][0] - 10,
line.points[line.points.length - 1][1] - 10, line.points[line.points.length - 1][1] - 10,
), ),

View file

@ -17,7 +17,7 @@ import { isLinearElement } from "../element/typeChecks";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import type { LocalPoint } from "../../math"; import type { LocalPoint } from "../../math";
import { point } from "../../math"; import { pointFrom } from "../../math";
ReactDOM.unmountComponentAtNode(document.getElementById("root")!); ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
@ -220,12 +220,17 @@ describe("generic element", () => {
describe.each(["line", "freedraw"] as const)("%s element", (type) => { describe.each(["line", "freedraw"] as const)("%s element", (type) => {
const points: Record<typeof type, LocalPoint[]> = { const points: Record<typeof type, LocalPoint[]> = {
line: [point(0, 0), point(60, -20), point(20, 40), point(-40, 0)], line: [
pointFrom(0, 0),
pointFrom(60, -20),
pointFrom(20, 40),
pointFrom(-40, 0),
],
freedraw: [ freedraw: [
point(0, 0), pointFrom(0, 0),
point(-2.474600807561444, 41.021700699972), pointFrom(-2.474600807561444, 41.021700699972),
point(3.6627956000014024, 47.84174560617245), pointFrom(3.6627956000014024, 47.84174560617245),
point(40.495224145598115, 47.15909710753482), pointFrom(40.495224145598115, 47.15909710753482),
], ],
}; };
@ -293,11 +298,11 @@ describe("arrow element", () => {
it("resizes with a label", async () => { it("resizes with a label", async () => {
const arrow = UI.createElement("arrow", { const arrow = UI.createElement("arrow", {
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(40, 140), pointFrom(40, 140),
point(80, 60), // label's anchor pointFrom(80, 60), // label's anchor
point(180, 20), pointFrom(180, 20),
point(200, 120), pointFrom(200, 120),
], ],
}); });
const label = await UI.editText(arrow, "Hello"); const label = await UI.editText(arrow, "Hello");
@ -747,24 +752,24 @@ describe("multiple selection", () => {
x: 60, x: 60,
y: 40, y: 40,
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(-40, 40), pointFrom(-40, 40),
point(-60, 0), pointFrom(-60, 0),
point(0, -40), pointFrom(0, -40),
point(40, 20), pointFrom(40, 20),
point(0, 40), pointFrom(0, 40),
], ],
}); });
const freedraw = UI.createElement("freedraw", { const freedraw = UI.createElement("freedraw", {
x: 63.56072661326618, x: 63.56072661326618,
y: 100, y: 100,
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(-43.56072661326618, 18.15048126846341), pointFrom(-43.56072661326618, 18.15048126846341),
point(-43.56072661326618, 29.041198460587566), pointFrom(-43.56072661326618, 29.041198460587566),
point(-38.115368017204105, 42.652452795512204), pointFrom(-38.115368017204105, 42.652452795512204),
point(-19.964886748740696, 66.24829266003775), pointFrom(-19.964886748740696, 66.24829266003775),
point(19.056612930986716, 77.1390098521619), pointFrom(19.056612930986716, 77.1390098521619),
], ],
}); });
@ -1101,13 +1106,13 @@ describe("multiple selection", () => {
x: 60, x: 60,
y: 0, y: 0,
points: [ points: [
point(0, 0), pointFrom(0, 0),
point(-40, 40), pointFrom(-40, 40),
point(-20, 60), pointFrom(-20, 60),
point(20, 20), pointFrom(20, 20),
point(40, 40), pointFrom(40, 40),
point(-20, 100), pointFrom(-20, 100),
point(-60, 60), pointFrom(-60, 60),
], ],
}); });

View file

@ -1,5 +1,5 @@
import type { Segment } from "../math"; import type { Segment } from "../math";
import { isSegment, segment, point, type GlobalPoint } from "../math"; import { isSegment, segment, pointFrom, type GlobalPoint } from "../math";
import { isBounds } from "./element/typeChecks"; import { isBounds } from "./element/typeChecks";
import type { Bounds } from "./element/types"; import type { Bounds } from "./element/types";
@ -52,8 +52,8 @@ export const debugDrawPoint = (
debugDrawLine( debugDrawLine(
segment( segment(
point<GlobalPoint>(p[0] + xOffset - 10, p[1] + yOffset - 10), pointFrom<GlobalPoint>(p[0] + xOffset - 10, p[1] + yOffset - 10),
point<GlobalPoint>(p[0] + xOffset + 10, p[1] + yOffset + 10), pointFrom<GlobalPoint>(p[0] + xOffset + 10, p[1] + yOffset + 10),
), ),
{ {
color: opts?.color ?? "cyan", color: opts?.color ?? "cyan",
@ -62,8 +62,8 @@ export const debugDrawPoint = (
); );
debugDrawLine( debugDrawLine(
segment( segment(
point<GlobalPoint>(p[0] + xOffset - 10, p[1] + yOffset + 10), pointFrom<GlobalPoint>(p[0] + xOffset - 10, p[1] + yOffset + 10),
point<GlobalPoint>(p[0] + xOffset + 10, p[1] + yOffset - 10), pointFrom<GlobalPoint>(p[0] + xOffset + 10, p[1] + yOffset - 10),
), ),
{ {
color: opts?.color ?? "cyan", color: opts?.color ?? "cyan",
@ -83,20 +83,20 @@ export const debugDrawBounds = (
debugDrawLine( debugDrawLine(
[ [
segment( segment(
point<GlobalPoint>(bbox[0], bbox[1]), pointFrom<GlobalPoint>(bbox[0], bbox[1]),
point<GlobalPoint>(bbox[2], bbox[1]), pointFrom<GlobalPoint>(bbox[2], bbox[1]),
), ),
segment( segment(
point<GlobalPoint>(bbox[2], bbox[1]), pointFrom<GlobalPoint>(bbox[2], bbox[1]),
point<GlobalPoint>(bbox[2], bbox[3]), pointFrom<GlobalPoint>(bbox[2], bbox[3]),
), ),
segment( segment(
point<GlobalPoint>(bbox[2], bbox[3]), pointFrom<GlobalPoint>(bbox[2], bbox[3]),
point<GlobalPoint>(bbox[0], bbox[3]), pointFrom<GlobalPoint>(bbox[0], bbox[3]),
), ),
segment( segment(
point<GlobalPoint>(bbox[0], bbox[3]), pointFrom<GlobalPoint>(bbox[0], bbox[3]),
point<GlobalPoint>(bbox[0], bbox[1]), pointFrom<GlobalPoint>(bbox[0], bbox[1]),
), ),
], ],
{ {

View file

@ -6,31 +6,31 @@ import {
arcSegmentInterceptPoints, arcSegmentInterceptPoints,
} from "./arc"; } from "./arc";
import { line } from "./line"; import { line } from "./line";
import { point } from "./point"; import { pointFrom } from "./point";
import { segment } from "./segment"; import { segment } from "./segment";
describe("point on arc", () => { describe("point on arc", () => {
it("should detect point on simple arc", () => { it("should detect point on simple arc", () => {
expect( expect(
arcIncludesPoint( arcIncludesPoint(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
point(0.92291667, 0.385), pointFrom(0.92291667, 0.385),
), ),
).toBe(true); ).toBe(true);
}); });
it("should not detect point outside of a simple arc", () => { it("should not detect point outside of a simple arc", () => {
expect( expect(
arcIncludesPoint( arcIncludesPoint(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
point(-0.92291667, 0.385), pointFrom(-0.92291667, 0.385),
), ),
).toBe(false); ).toBe(false);
}); });
it("should not detect point with good angle but incorrect radius", () => { it("should not detect point with good angle but incorrect radius", () => {
expect( expect(
arcIncludesPoint( arcIncludesPoint(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
point(-0.5, 0.5), pointFrom(-0.5, 0.5),
), ),
).toBe(false); ).toBe(false);
}); });
@ -40,42 +40,42 @@ describe("intersection", () => {
it("should report correct interception point for segment", () => { it("should report correct interception point for segment", () => {
expect( expect(
arcSegmentInterceptPoints( arcSegmentInterceptPoints(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
segment(point(2, 1), point(0, 0)), segment(pointFrom(2, 1), pointFrom(0, 0)),
), ),
).toEqual([point(0.894427190999916, 0.447213595499958)]); ).toEqual([pointFrom(0.894427190999916, 0.447213595499958)]);
}); });
it("should report both interception points when present for segment", () => { it("should report both interception points when present for segment", () => {
expect( expect(
arcSegmentInterceptPoints( arcSegmentInterceptPoints(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
segment(point(0.9, -2), point(0.9, 2)), segment(pointFrom(0.9, -2), pointFrom(0.9, 2)),
), ),
).toEqual([ ).toEqual([
point(0.9, -0.4358898943540668), pointFrom(0.9, -0.4358898943540668),
point(0.9, 0.4358898943540668), pointFrom(0.9, 0.4358898943540668),
]); ]);
}); });
it("should report correct interception point for line", () => { it("should report correct interception point for line", () => {
expect( expect(
arcLineInterceptPoints( arcLineInterceptPoints(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
line(point(2, 1), point(0, 0)), line(pointFrom(2, 1), pointFrom(0, 0)),
), ),
).toEqual([point(0.894427190999916, 0.447213595499958)]); ).toEqual([pointFrom(0.894427190999916, 0.447213595499958)]);
}); });
it("should report both interception points when present for line", () => { it("should report both interception points when present for line", () => {
expect( expect(
arcLineInterceptPoints( arcLineInterceptPoints(
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)), arc(pointFrom(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
line(point(0.9, -2), point(0.9, 2)), line(pointFrom(0.9, -2), pointFrom(0.9, 2)),
), ),
).toEqual([ ).toEqual([
point(0.9, 0.4358898943540668), pointFrom(0.9, 0.4358898943540668),
point(0.9, -0.4358898943540668), pointFrom(0.9, -0.4358898943540668),
]); ]);
}); });
}); });

View file

@ -1,4 +1,4 @@
import { point, pointRotateRads } from "./point"; import { pointFrom, pointRotateRads } from "./point";
import type { Curve, GenericPoint, Radians } from "./types"; import type { Curve, GenericPoint, Radians } from "./types";
/** /**
@ -43,10 +43,10 @@ export function curveToBezier<Point extends GenericPoint>(
const out: Point[] = []; const out: Point[] = [];
if (len === 3) { if (len === 3) {
out.push( out.push(
point(pointsIn[0][0], pointsIn[0][1]), // Points need to be cloned pointFrom(pointsIn[0][0], pointsIn[0][1]), // Points need to be cloned
point(pointsIn[1][0], pointsIn[1][1]), // Points need to be cloned pointFrom(pointsIn[1][0], pointsIn[1][1]), // Points need to be cloned
point(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned pointFrom(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned
point(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned pointFrom(pointsIn[2][0], pointsIn[2][1]), // Points need to be cloned
); );
} else { } else {
const points: Point[] = []; const points: Point[] = [];
@ -59,19 +59,19 @@ export function curveToBezier<Point extends GenericPoint>(
} }
const b: Point[] = []; const b: Point[] = [];
const s = 1 - curveTightness; const s = 1 - curveTightness;
out.push(point(points[0][0], points[0][1])); out.push(pointFrom(points[0][0], points[0][1]));
for (let i = 1; i + 2 < points.length; i++) { for (let i = 1; i + 2 < points.length; i++) {
const cachedVertArray = points[i]; const cachedVertArray = points[i];
b[0] = point(cachedVertArray[0], cachedVertArray[1]); b[0] = pointFrom(cachedVertArray[0], cachedVertArray[1]);
b[1] = point( b[1] = pointFrom(
cachedVertArray[0] + (s * points[i + 1][0] - s * points[i - 1][0]) / 6, cachedVertArray[0] + (s * points[i + 1][0] - s * points[i - 1][0]) / 6,
cachedVertArray[1] + (s * points[i + 1][1] - s * points[i - 1][1]) / 6, cachedVertArray[1] + (s * points[i + 1][1] - s * points[i - 1][1]) / 6,
); );
b[2] = point( b[2] = pointFrom(
points[i + 1][0] + (s * points[i][0] - s * points[i + 2][0]) / 6, points[i + 1][0] + (s * points[i][0] - s * points[i + 2][0]) / 6,
points[i + 1][1] + (s * points[i][1] - s * points[i + 2][1]) / 6, points[i + 1][1] + (s * points[i][1] - s * points[i + 2][1]) / 6,
); );
b[3] = point(points[i + 1][0], points[i + 1][1]); b[3] = pointFrom(points[i + 1][0], points[i + 1][1]);
out.push(b[1], b[2], b[3]); out.push(b[1], b[2], b[3]);
} }
} }
@ -102,7 +102,7 @@ export const cubicBezierPoint = <Point extends GenericPoint>(
3 * (1 - t) * Math.pow(t, 2) * p2[1] + 3 * (1 - t) * Math.pow(t, 2) * p2[1] +
Math.pow(t, 3) * p3[1]; Math.pow(t, 3) * p3[1];
return point(x, y); return pointFrom(x, y);
}; };
/** /**

View file

@ -1,4 +1,4 @@
import { point, pointRotateRads } from "./point"; import { pointFrom, pointRotateRads } from "./point";
import type { Radians } from "./types"; import type { Radians } from "./types";
describe("rotate", () => { describe("rotate", () => {
@ -9,14 +9,14 @@ describe("rotate", () => {
const y2 = 30; const y2 = 30;
const angle = (Math.PI / 2) as Radians; const angle = (Math.PI / 2) as Radians;
const [rotatedX, rotatedY] = pointRotateRads( const [rotatedX, rotatedY] = pointRotateRads(
point(x1, y1), pointFrom(x1, y1),
point(x2, y2), pointFrom(x2, y2),
angle, angle,
); );
expect([rotatedX, rotatedY]).toEqual([30, 20]); expect([rotatedX, rotatedY]).toEqual([30, 20]);
const res2 = pointRotateRads( const res2 = pointRotateRads(
point(rotatedX, rotatedY), pointFrom(rotatedX, rotatedY),
point(x2, y2), pointFrom(x2, y2),
-angle as Radians, -angle as Radians,
); );
expect(res2).toEqual([x1, x2]); expect(res2).toEqual([x1, x2]);

View file

@ -10,7 +10,10 @@ import { vectorFromPoint, vectorScale } from "./vector";
* @param y The Y coordinate * @param y The Y coordinate
* @returns The branded and created point * @returns The branded and created point
*/ */
export function point<Point extends GenericPoint>(x: number, y: number): Point { export function pointFrom<Point extends GenericPoint>(
x: number,
y: number,
): Point {
return [x, y] as Point; return [x, y] as Point;
} }
@ -24,7 +27,7 @@ export function pointFromArray<Point extends GenericPoint>(
numberArray: number[], numberArray: number[],
): Point | undefined { ): Point | undefined {
return numberArray.length === 2 return numberArray.length === 2
? point<Point>(numberArray[0], numberArray[1]) ? pointFrom<Point>(numberArray[0], numberArray[1])
: undefined; : undefined;
} }
@ -48,9 +51,9 @@ export function pointFromPair<Point extends GenericPoint>(
*/ */
export function pointFromVector<P extends GenericPoint>( export function pointFromVector<P extends GenericPoint>(
v: Vector, v: Vector,
offset: P = point(0, 0), offset: P = pointFrom(0, 0),
): P { ): P {
return point<P>(offset[0] + v[0], offset[1] + v[1]); return pointFrom<P>(offset[0] + v[0], offset[1] + v[1]);
} }
/** /**
@ -102,7 +105,7 @@ export function pointRotateRads<Point extends GenericPoint>(
const cos = Math.cos(angle); const cos = Math.cos(angle);
const sin = Math.sin(angle); const sin = Math.sin(angle);
return point( return pointFrom(
(x - cx) * cos - (y - cy) * sin + cx, (x - cx) * cos - (y - cy) * sin + cx,
(x - cx) * sin + (y - cy) * cos + cy, (x - cx) * sin + (y - cy) * cos + cy,
); );
@ -141,7 +144,7 @@ export function pointTranslate<
From extends GenericPoint, From extends GenericPoint,
To extends GenericPoint, To extends GenericPoint,
>(p: From, v: Vector = [0, 0] as Vector): To { >(p: From, v: Vector = [0, 0] as Vector): To {
return point(p[0] + v[0], p[1] + v[1]); return pointFrom(p[0] + v[0], p[1] + v[1]);
} }
/** /**
@ -171,7 +174,7 @@ export function pointAdd<Point extends GenericPoint>(
a: Point, a: Point,
b: Point, b: Point,
): Point { ): Point {
return point(a[0] + b[0], a[1] + b[1]); return pointFrom(a[0] + b[0], a[1] + b[1]);
} }
/** /**
@ -186,7 +189,7 @@ export function pointSubtract<Point extends GenericPoint>(
a: Point, a: Point,
b: Point, b: Point,
): Point { ): Point {
return point(a[0] - b[0], a[1] - b[1]); return pointFrom(a[0] - b[0], a[1] - b[1]);
} }
/** /**

View file

@ -4,7 +4,7 @@ import {
degreesToRadians, degreesToRadians,
segment, segment,
segmentRotate, segmentRotate,
point, pointFrom,
pointRotateDegs, pointRotateDegs,
} from "../math"; } from "../math";
import { pointOnCurve, pointOnPolyline } from "./collision"; import { pointOnCurve, pointOnPolyline } from "./collision";
@ -12,21 +12,21 @@ import type { Polyline } from "./geometry/shape";
describe("point and curve", () => { describe("point and curve", () => {
const c: Curve<GlobalPoint> = curve( const c: Curve<GlobalPoint> = curve(
point(1.4, 1.65), pointFrom(1.4, 1.65),
point(1.9, 7.9), pointFrom(1.9, 7.9),
point(5.9, 1.65), pointFrom(5.9, 1.65),
point(6.44, 4.84), pointFrom(6.44, 4.84),
); );
it("point on curve", () => { it("point on curve", () => {
expect(pointOnCurve(c[0], c, 10e-5)).toBe(true); expect(pointOnCurve(c[0], c, 10e-5)).toBe(true);
expect(pointOnCurve(c[3], c, 10e-5)).toBe(true); expect(pointOnCurve(c[3], c, 10e-5)).toBe(true);
expect(pointOnCurve(point(2, 4), c, 0.1)).toBe(true); expect(pointOnCurve(pointFrom(2, 4), c, 0.1)).toBe(true);
expect(pointOnCurve(point(4, 4.4), c, 0.1)).toBe(true); expect(pointOnCurve(pointFrom(4, 4.4), c, 0.1)).toBe(true);
expect(pointOnCurve(point(5.6, 3.85), c, 0.1)).toBe(true); expect(pointOnCurve(pointFrom(5.6, 3.85), c, 0.1)).toBe(true);
expect(pointOnCurve(point(5.6, 4), c, 0.1)).toBe(false); expect(pointOnCurve(pointFrom(5.6, 4), c, 0.1)).toBe(false);
expect(pointOnCurve(c[1], c, 0.1)).toBe(false); expect(pointOnCurve(c[1], c, 0.1)).toBe(false);
expect(pointOnCurve(c[2], c, 0.1)).toBe(false); expect(pointOnCurve(c[2], c, 0.1)).toBe(false);
}); });
@ -34,52 +34,52 @@ describe("point and curve", () => {
describe("point and polylines", () => { describe("point and polylines", () => {
const polyline: Polyline<GlobalPoint> = [ const polyline: Polyline<GlobalPoint> = [
segment(point(1, 0), point(1, 2)), segment(pointFrom(1, 0), pointFrom(1, 2)),
segment(point(1, 2), point(2, 2)), segment(pointFrom(1, 2), pointFrom(2, 2)),
segment(point(2, 2), point(2, 1)), segment(pointFrom(2, 2), pointFrom(2, 1)),
segment(point(2, 1), point(3, 1)), segment(pointFrom(2, 1), pointFrom(3, 1)),
]; ];
it("point on the line", () => { it("point on the line", () => {
expect(pointOnPolyline(point(1, 0), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(1, 0), polyline)).toBe(true);
expect(pointOnPolyline(point(1, 2), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(1, 2), polyline)).toBe(true);
expect(pointOnPolyline(point(2, 2), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(2, 2), polyline)).toBe(true);
expect(pointOnPolyline(point(2, 1), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(2, 1), polyline)).toBe(true);
expect(pointOnPolyline(point(3, 1), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(3, 1), polyline)).toBe(true);
expect(pointOnPolyline(point(1, 1), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(1, 1), polyline)).toBe(true);
expect(pointOnPolyline(point(2, 1.5), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(2, 1.5), polyline)).toBe(true);
expect(pointOnPolyline(point(2.5, 1), polyline)).toBe(true); expect(pointOnPolyline(pointFrom(2.5, 1), polyline)).toBe(true);
expect(pointOnPolyline(point(0, 1), polyline)).toBe(false); expect(pointOnPolyline(pointFrom(0, 1), polyline)).toBe(false);
expect(pointOnPolyline(point(2.1, 1.5), polyline)).toBe(false); expect(pointOnPolyline(pointFrom(2.1, 1.5), polyline)).toBe(false);
}); });
it("point on the line with rotation", () => { it("point on the line with rotation", () => {
const truePoints = [ const truePoints = [
point(1, 0), pointFrom(1, 0),
point(1, 2), pointFrom(1, 2),
point(2, 2), pointFrom(2, 2),
point(2, 1), pointFrom(2, 1),
point(3, 1), pointFrom(3, 1),
]; ];
truePoints.forEach((p) => { truePoints.forEach((p) => {
const rotation = (Math.random() * 360) as Degrees; const rotation = (Math.random() * 360) as Degrees;
const rotatedPoint = pointRotateDegs(p, point(0, 0), rotation); const rotatedPoint = pointRotateDegs(p, pointFrom(0, 0), rotation);
const rotatedPolyline = polyline.map((line) => const rotatedPolyline = polyline.map((line) =>
segmentRotate(line, degreesToRadians(rotation), point(0, 0)), segmentRotate(line, degreesToRadians(rotation), pointFrom(0, 0)),
); );
expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(true); expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(true);
}); });
const falsePoints = [point(0, 1), point(2.1, 1.5)]; const falsePoints = [pointFrom(0, 1), pointFrom(2.1, 1.5)];
falsePoints.forEach((p) => { falsePoints.forEach((p) => {
const rotation = (Math.random() * 360) as Degrees; const rotation = (Math.random() * 360) as Degrees;
const rotatedPoint = pointRotateDegs(p, point(0, 0), rotation); const rotatedPoint = pointRotateDegs(p, pointFrom(0, 0), rotation);
const rotatedPolyline = polyline.map((line) => const rotatedPolyline = polyline.map((line) =>
segmentRotate(line, degreesToRadians(rotation), point(0, 0)), segmentRotate(line, degreesToRadians(rotation), pointFrom(0, 0)),
); );
expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(false); expect(pointOnPolyline(rotatedPoint, rotatedPolyline)).toBe(false);
}); });

View file

@ -3,7 +3,7 @@ import { type GeometricShape } from "./geometry/shape";
import type { Curve, GenericPoint } from "../math"; import type { Curve, GenericPoint } from "../math";
import { import {
segment, segment,
point, pointFrom,
polygonIncludesPoint, polygonIncludesPoint,
segmentIncludesPoint, segmentIncludesPoint,
pointOnPolygon, pointOnPolygon,
@ -95,7 +95,7 @@ const polyLineFromCurve = <Point extends GenericPoint>(
for (let i = 0; i < segments; i++) { for (let i = 0; i < segments; i++) {
t += increment; t += increment;
if (t <= 1) { if (t <= 1) {
const nextPoint: Point = point(equation(t, 0), equation(t, 1)); const nextPoint: Point = pointFrom(equation(t, 0), equation(t, 1));
lineSegments.push(segment(startingPoint, nextPoint)); lineSegments.push(segment(startingPoint, nextPoint));
startingPoint = nextPoint; startingPoint = nextPoint;
} }

View file

@ -1,6 +1,6 @@
import type { GlobalPoint, Segment, Polygon } from "../../math"; import type { GlobalPoint, Segment, Polygon } from "../../math";
import { import {
point, pointFrom,
segment, segment,
polygon, polygon,
segmentIncludesPoint, segmentIncludesPoint,
@ -9,40 +9,40 @@ import {
} from "../../math"; } from "../../math";
describe("point and line", () => { describe("point and line", () => {
const s: Segment<GlobalPoint> = segment(point(1, 0), point(1, 2)); const s: Segment<GlobalPoint> = segment(pointFrom(1, 0), pointFrom(1, 2));
it("point on the line", () => { it("point on the line", () => {
expect(segmentIncludesPoint(point(0, 1), s)).toBe(false); expect(segmentIncludesPoint(pointFrom(0, 1), s)).toBe(false);
expect(segmentIncludesPoint(point(1, 1), s, 0)).toBe(true); expect(segmentIncludesPoint(pointFrom(1, 1), s, 0)).toBe(true);
expect(segmentIncludesPoint(point(2, 1), s)).toBe(false); expect(segmentIncludesPoint(pointFrom(2, 1), s)).toBe(false);
}); });
}); });
describe("point and polygon", () => { describe("point and polygon", () => {
const poly: Polygon<GlobalPoint> = polygon( const poly: Polygon<GlobalPoint> = polygon(
point(10, 10), pointFrom(10, 10),
point(50, 10), pointFrom(50, 10),
point(50, 50), pointFrom(50, 50),
point(10, 50), pointFrom(10, 50),
); );
it("point on polygon", () => { it("point on polygon", () => {
expect(pointOnPolygon(point(30, 10), poly)).toBe(true); expect(pointOnPolygon(pointFrom(30, 10), poly)).toBe(true);
expect(pointOnPolygon(point(50, 30), poly)).toBe(true); expect(pointOnPolygon(pointFrom(50, 30), poly)).toBe(true);
expect(pointOnPolygon(point(30, 50), poly)).toBe(true); expect(pointOnPolygon(pointFrom(30, 50), poly)).toBe(true);
expect(pointOnPolygon(point(10, 30), poly)).toBe(true); expect(pointOnPolygon(pointFrom(10, 30), poly)).toBe(true);
expect(pointOnPolygon(point(30, 30), poly)).toBe(false); expect(pointOnPolygon(pointFrom(30, 30), poly)).toBe(false);
expect(pointOnPolygon(point(30, 70), poly)).toBe(false); expect(pointOnPolygon(pointFrom(30, 70), poly)).toBe(false);
}); });
it("point in polygon", () => { it("point in polygon", () => {
const poly: Polygon<GlobalPoint> = polygon( const poly: Polygon<GlobalPoint> = polygon(
point(0, 0), pointFrom(0, 0),
point(2, 0), pointFrom(2, 0),
point(2, 2), pointFrom(2, 2),
point(0, 2), pointFrom(0, 2),
); );
expect(polygonIncludesPoint(point(1, 1), poly)).toBe(true); expect(polygonIncludesPoint(pointFrom(1, 1), poly)).toBe(true);
expect(polygonIncludesPoint(point(3, 3), poly)).toBe(false); expect(polygonIncludesPoint(pointFrom(3, 3), poly)).toBe(false);
}); });
}); });

View file

@ -25,7 +25,7 @@ import {
curve, curve,
ellipse, ellipse,
segment, segment,
point, pointFrom,
pointFromArray, pointFromArray,
pointFromVector, pointFromVector,
pointRotateRads, pointRotateRads,
@ -115,23 +115,23 @@ export const getPolygonShape = <Point extends GlobalPoint | LocalPoint>(
const cx = x + width / 2; const cx = x + width / 2;
const cy = y + height / 2; const cy = y + height / 2;
const center: Point = point(cx, cy); const center: Point = pointFrom(cx, cy);
let data: Polygon<Point>; let data: Polygon<Point>;
if (element.type === "diamond") { if (element.type === "diamond") {
data = polygon( data = polygon(
pointRotateRads(point(cx, y), center, angle), pointRotateRads(pointFrom(cx, y), center, angle),
pointRotateRads(point(x + width, cy), center, angle), pointRotateRads(pointFrom(x + width, cy), center, angle),
pointRotateRads(point(cx, y + height), center, angle), pointRotateRads(pointFrom(cx, y + height), center, angle),
pointRotateRads(point(x, cy), center, angle), pointRotateRads(pointFrom(x, cy), center, angle),
); );
} else { } else {
data = polygon( data = polygon(
pointRotateRads(point(x, y), center, angle), pointRotateRads(pointFrom(x, y), center, angle),
pointRotateRads(point(x + width, y), center, angle), pointRotateRads(pointFrom(x + width, y), center, angle),
pointRotateRads(point(x + width, y + height), center, angle), pointRotateRads(pointFrom(x + width, y + height), center, angle),
pointRotateRads(point(x, y + height), center, angle), pointRotateRads(pointFrom(x, y + height), center, angle),
); );
} }
@ -159,11 +159,11 @@ export const getSelectionBoxShape = <Point extends GlobalPoint | LocalPoint>(
y2 += padding; y2 += padding;
//const angleInDegrees = angleToDegrees(element.angle); //const angleInDegrees = angleToDegrees(element.angle);
const center = point(cx, cy); const center = pointFrom(cx, cy);
const topLeft = pointRotateRads(point(x1, y1), center, element.angle); const topLeft = pointRotateRads(pointFrom(x1, y1), center, element.angle);
const topRight = pointRotateRads(point(x2, y1), center, element.angle); const topRight = pointRotateRads(pointFrom(x2, y1), center, element.angle);
const bottomLeft = pointRotateRads(point(x1, y2), center, element.angle); const bottomLeft = pointRotateRads(pointFrom(x1, y2), center, element.angle);
const bottomRight = pointRotateRads(point(x2, y2), center, element.angle); const bottomRight = pointRotateRads(pointFrom(x2, y2), center, element.angle);
return { return {
type: "polygon", type: "polygon",
@ -179,7 +179,11 @@ export const getEllipseShape = <Point extends GlobalPoint | LocalPoint>(
return { return {
type: "ellipse", type: "ellipse",
data: ellipse(point(x + width / 2, y + height / 2), width / 2, height / 2), data: ellipse(
pointFrom(x + width / 2, y + height / 2),
width / 2,
height / 2,
),
}; };
}; };
@ -195,20 +199,20 @@ export const getCurvePathOps = (shape: Drawable): Op[] => {
// linear // linear
export const getCurveShape = <Point extends GlobalPoint | LocalPoint>( export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
roughShape: Drawable, roughShape: Drawable,
startingPoint: Point = point(0, 0), startingPoint: Point = pointFrom(0, 0),
angleInRadian: Radians, angleInRadian: Radians,
center: Point, center: Point,
): GeometricShape<Point> => { ): GeometricShape<Point> => {
const transform = (p: Point): Point => const transform = (p: Point): Point =>
pointRotateRads( pointRotateRads(
point(p[0] + startingPoint[0], p[1] + startingPoint[1]), pointFrom(p[0] + startingPoint[0], p[1] + startingPoint[1]),
center, center,
angleInRadian, angleInRadian,
); );
const ops = getCurvePathOps(roughShape); const ops = getCurvePathOps(roughShape);
const polycurve: Polycurve<Point> = []; const polycurve: Polycurve<Point> = [];
let p0 = point<Point>(0, 0); let p0 = pointFrom<Point>(0, 0);
for (const op of ops) { for (const op of ops) {
if (op.op === "move") { if (op.op === "move") {
@ -217,9 +221,9 @@ export const getCurveShape = <Point extends GlobalPoint | LocalPoint>(
p0 = transform(p); p0 = transform(p);
} }
if (op.op === "bcurveTo") { if (op.op === "bcurveTo") {
const p1 = transform(point<Point>(op.data[0], op.data[1])); const p1 = transform(pointFrom<Point>(op.data[0], op.data[1]));
const p2 = transform(point<Point>(op.data[2], op.data[3])); const p2 = transform(pointFrom<Point>(op.data[2], op.data[3]));
const p3 = transform(point<Point>(op.data[4], op.data[5])); const p3 = transform(pointFrom<Point>(op.data[4], op.data[5]));
polycurve.push(curve<Point>(p0, p1, p2, p3)); polycurve.push(curve<Point>(p0, p1, p2, p3));
p0 = p3; p0 = p3;
} }
@ -280,13 +284,13 @@ export const getFreedrawShape = (
export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>( export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
element: ExcalidrawLinearElement, element: ExcalidrawLinearElement,
roughShape: Drawable, roughShape: Drawable,
startingPoint: Point = point<Point>(0, 0), startingPoint: Point = pointFrom<Point>(0, 0),
angleInRadian: Radians, angleInRadian: Radians,
center: Point, center: Point,
): GeometricShape<Point> => { ): GeometricShape<Point> => {
const transform = (p: Point) => const transform = (p: Point) =>
pointRotateRads( pointRotateRads(
point(p[0] + startingPoint[0], p[1] + startingPoint[1]), pointFrom(p[0] + startingPoint[0], p[1] + startingPoint[1]),
center, center,
angleInRadian, angleInRadian,
); );
@ -308,17 +312,17 @@ export const getClosedCurveShape = <Point extends GlobalPoint | LocalPoint>(
if (operation.op === "move") { if (operation.op === "move") {
odd = !odd; odd = !odd;
if (odd) { if (odd) {
points.push(point(operation.data[0], operation.data[1])); points.push(pointFrom(operation.data[0], operation.data[1]));
} }
} else if (operation.op === "bcurveTo") { } else if (operation.op === "bcurveTo") {
if (odd) { if (odd) {
points.push(point(operation.data[0], operation.data[1])); points.push(pointFrom(operation.data[0], operation.data[1]));
points.push(point(operation.data[2], operation.data[3])); points.push(pointFrom(operation.data[2], operation.data[3]));
points.push(point(operation.data[4], operation.data[5])); points.push(pointFrom(operation.data[4], operation.data[5]));
} }
} else if (operation.op === "lineTo") { } else if (operation.op === "lineTo") {
if (odd) { if (odd) {
points.push(point(operation.data[0], operation.data[1])); points.push(pointFrom(operation.data[0], operation.data[1]));
} }
} }
} }
@ -356,27 +360,27 @@ export const segmentIntersectRectangleElement = <
element.x + element.width + gap, element.x + element.width + gap,
element.y + element.height + gap, element.y + element.height + gap,
]; ];
const center = point( const center = pointFrom(
(bounds[0] + bounds[2]) / 2, (bounds[0] + bounds[2]) / 2,
(bounds[1] + bounds[3]) / 2, (bounds[1] + bounds[3]) / 2,
); );
return [ return [
segment( segment(
pointRotateRads(point(bounds[0], bounds[1]), center, element.angle), pointRotateRads(pointFrom(bounds[0], bounds[1]), center, element.angle),
pointRotateRads(point(bounds[2], bounds[1]), center, element.angle), pointRotateRads(pointFrom(bounds[2], bounds[1]), center, element.angle),
), ),
segment( segment(
pointRotateRads(point(bounds[2], bounds[1]), center, element.angle), pointRotateRads(pointFrom(bounds[2], bounds[1]), center, element.angle),
pointRotateRads(point(bounds[2], bounds[3]), center, element.angle), pointRotateRads(pointFrom(bounds[2], bounds[3]), center, element.angle),
), ),
segment( segment(
pointRotateRads(point(bounds[2], bounds[3]), center, element.angle), pointRotateRads(pointFrom(bounds[2], bounds[3]), center, element.angle),
pointRotateRads(point(bounds[0], bounds[3]), center, element.angle), pointRotateRads(pointFrom(bounds[0], bounds[3]), center, element.angle),
), ),
segment( segment(
pointRotateRads(point(bounds[0], bounds[3]), center, element.angle), pointRotateRads(pointFrom(bounds[0], bounds[3]), center, element.angle),
pointRotateRads(point(bounds[0], bounds[1]), center, element.angle), pointRotateRads(pointFrom(bounds[0], bounds[1]), center, element.angle),
), ),
] ]
.map((l) => segmentsIntersectAt(s, l)) .map((l) => segmentsIntersectAt(s, l))

View file

@ -17,7 +17,7 @@ import { arrayToMap } from "../excalidraw/utils";
import type { LocalPoint } from "../math"; import type { LocalPoint } from "../math";
import { import {
rangeIncludesValue, rangeIncludesValue,
point, pointFrom,
pointRotateRads, pointRotateRads,
rangeInclusive, rangeInclusive,
} from "../math"; } from "../math";
@ -36,17 +36,17 @@ const getNonLinearElementRelativePoints = (
] => { ] => {
if (element.type === "diamond") { if (element.type === "diamond") {
return [ return [
point(element.width / 2, 0), pointFrom(element.width / 2, 0),
point(element.width, element.height / 2), pointFrom(element.width, element.height / 2),
point(element.width / 2, element.height), pointFrom(element.width / 2, element.height),
point(0, element.height / 2), pointFrom(0, element.height / 2),
]; ];
} }
return [ return [
point(0, 0), pointFrom(0, 0),
point(0 + element.width, 0), pointFrom(0 + element.width, 0),
point(0 + element.width, element.height), pointFrom(0 + element.width, element.height),
point(0, element.height), pointFrom(0, element.height),
]; ];
}; };
@ -91,7 +91,7 @@ const getRotatedBBox = (element: NonDeletedExcalidrawElement): Bounds => {
const points = getElementRelativePoints(element); const points = getElementRelativePoints(element);
const { cx, cy } = getMinMaxPoints(points); const { cx, cy } = getMinMaxPoints(points);
const centerPoint = point<LocalPoint>(cx, cy); const centerPoint = pointFrom<LocalPoint>(cx, cy);
const rotatedPoints = points.map((p) => const rotatedPoints = points.map((p) =>
pointRotateRads(p, centerPoint, element.angle), pointRotateRads(p, centerPoint, element.angle),