diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts index b476995da1..f7557a97fc 100644 --- a/packages/excalidraw/data/restore.ts +++ b/packages/excalidraw/data/restore.ts @@ -48,7 +48,6 @@ import type { MarkOptional, Mutable } from "../utility-types"; import { detectLineHeight, getContainerElement } from "../element/textElement"; import { normalizeLink } from "./url"; import { syncInvalidIndices } from "../fractionalIndex"; -import { getSizeFromPoints } from "../points"; import { getLineHeight } from "../fonts"; import { normalizeFixedPoint } from "../element/binding"; import { @@ -57,7 +56,7 @@ import { getNormalizedZoom, } from "../scene"; import type { LocalPoint, Radians } from "../../math"; -import { isFiniteNumber, point } from "../../math"; +import { pointExtent, isFiniteNumber, point } from "../../math"; type RestoredAppState = Omit< AppState, @@ -288,7 +287,7 @@ const restoreElement = ( points, x, y, - ...getSizeFromPoints(points), + ...pointExtent(points), }); case "arrow": { const { startArrowhead = null, endArrowhead = "arrow" } = element; @@ -315,7 +314,7 @@ const restoreElement = ( x, y, elbowed: (element as ExcalidrawArrowElement).elbowed, - ...getSizeFromPoints(points), + ...pointExtent(points), }); } diff --git a/packages/excalidraw/data/transform.ts b/packages/excalidraw/data/transform.ts index 6573abd0d0..b06fdf89a0 100644 --- a/packages/excalidraw/data/transform.ts +++ b/packages/excalidraw/data/transform.ts @@ -48,12 +48,11 @@ import { getFontString, toBrandedType, } from "../utils"; -import { getSizeFromPoints } from "../points"; import { randomId } from "../random"; import { syncInvalidIndices } from "../fractionalIndex"; import { getLineHeight } from "../fonts"; import { isArrowElement } from "../element/typeChecks"; -import { point, type LocalPoint } from "../../math"; +import { pointExtent, point, type LocalPoint } from "../../math"; export type ValidLinearElement = { type: "arrow" | "line"; @@ -556,7 +555,7 @@ export const convertToExcalidrawElements = ( Object.assign( excalidrawElement, - getSizeFromPoints(excalidrawElement.points), + pointExtent(excalidrawElement.points), ); break; } diff --git a/packages/excalidraw/element/bounds.ts b/packages/excalidraw/element/bounds.ts index 16f431855c..eb6a5036fd 100644 --- a/packages/excalidraw/element/bounds.ts +++ b/packages/excalidraw/element/bounds.ts @@ -19,7 +19,6 @@ import { isLinearElement, isTextElement, } from "./typeChecks"; -import { rescalePoints } from "../points"; import { getBoundTextElement, getContainerElement } from "./textElement"; import { LinearElementEditor } from "./linearElementEditor"; import { ShapeCache } from "../scene/ShapeCache"; @@ -38,6 +37,7 @@ import { pointDistance, pointFromArray, pointRotateRads, + pointRescaleFromTopLeft, } from "../../math"; import type { Mutable } from "../utility-types"; @@ -859,10 +859,10 @@ export const getResizedElementAbsoluteCoords = ( ]; } - const points = rescalePoints( + const points = pointRescaleFromTopLeft( 0, nextWidth, - rescalePoints(1, nextHeight, element.points, normalizePoints), + pointRescaleFromTopLeft(1, nextHeight, element.points, normalizePoints), normalizePoints, ); diff --git a/packages/excalidraw/element/mutateElement.ts b/packages/excalidraw/element/mutateElement.ts index ef84854f9a..53bf834e24 100644 --- a/packages/excalidraw/element/mutateElement.ts +++ b/packages/excalidraw/element/mutateElement.ts @@ -1,10 +1,10 @@ import type { ExcalidrawElement } from "./types"; import Scene from "../scene/Scene"; -import { getSizeFromPoints } from "../points"; import { randomInteger } from "../random"; import { getUpdatedTimestamp } from "../utils"; import type { Mutable } from "../utility-types"; import { ShapeCache } from "../scene/ShapeCache"; +import { pointExtent } from "../../math"; export type ElementUpdate = Omit< Partial, @@ -27,7 +27,7 @@ export const mutateElement = >( const { points, fileId } = updates as any; if (typeof points !== "undefined") { - updates = { ...getSizeFromPoints(points), ...updates }; + updates = { ...pointExtent(points), ...updates }; } for (const key in updates) { diff --git a/packages/excalidraw/element/resizeElements.ts b/packages/excalidraw/element/resizeElements.ts index 4b5a481a53..0704740c85 100644 --- a/packages/excalidraw/element/resizeElements.ts +++ b/packages/excalidraw/element/resizeElements.ts @@ -1,5 +1,4 @@ import { MIN_FONT_SIZE, SHIFT_LOCKING_ANGLE } from "../constants"; -import { rescalePoints } from "../points"; import type { ExcalidrawLinearElement, ExcalidrawTextElement, @@ -62,6 +61,7 @@ import { pointFromPair, pointRotateRads, type Radians, + pointRescaleFromTopLeft, } from "../../math"; // Returns true when transform (resizing/rotation) happened @@ -191,10 +191,10 @@ export const rescalePointsInElement = ( ) => isLinearElement(element) || isFreeDrawElement(element) ? { - points: rescalePoints( + points: pointRescaleFromTopLeft( 0, width, - rescalePoints(1, height, element.points, normalizePoints), + pointRescaleFromTopLeft(1, height, element.points, normalizePoints), normalizePoints, ), } @@ -674,14 +674,14 @@ export const resizeSingleElement = ( let rescaledElementPointsY; let rescaledPoints; if (isLinearElement(element) || isFreeDrawElement(element)) { - rescaledElementPointsY = rescalePoints( + rescaledElementPointsY = pointRescaleFromTopLeft( 1, eleNewHeight, (stateAtResizeStart as ExcalidrawLinearElement).points, true, ); - rescaledPoints = rescalePoints( + rescaledPoints = pointRescaleFromTopLeft( 0, eleNewWidth, rescaledElementPointsY, diff --git a/packages/excalidraw/element/routing.ts b/packages/excalidraw/element/routing.ts index 7efedd78b9..52c9490d78 100644 --- a/packages/excalidraw/element/routing.ts +++ b/packages/excalidraw/element/routing.ts @@ -1,5 +1,6 @@ import type { Radians } from "../../math"; import { + pointExtent, point, pointScaleFromOrigin, pointTranslate, @@ -12,7 +13,6 @@ import { type Vector, } from "../../math"; import BinaryHeap from "../binaryheap"; -import { getSizeFromPoints } from "../points"; import { aabbForElement, pointInsideBounds } from "../shapes"; import { isAnyTrue, toBrandedType } from "../utils"; import { @@ -955,7 +955,7 @@ const normalizedArrowElementUpdate = ( points, x: offsetX + (externalOffsetX ?? 0), y: offsetY + (externalOffsetY ?? 0), - ...getSizeFromPoints(points), + ...pointExtent(points), }; }; diff --git a/packages/excalidraw/points.ts b/packages/excalidraw/points.ts deleted file mode 100644 index 5f9480120c..0000000000 --- a/packages/excalidraw/points.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { pointFromPair, type GlobalPoint, type LocalPoint } from "../math"; - -export const getSizeFromPoints = ( - points: readonly (GlobalPoint | LocalPoint)[], -) => { - const xs = points.map((point) => point[0]); - const ys = points.map((point) => point[1]); - return { - width: Math.max(...xs) - Math.min(...xs), - height: Math.max(...ys) - Math.min(...ys), - }; -}; - -/** @arg dimension, 0 for rescaling only x, 1 for y */ -export const rescalePoints = ( - dimension: 0 | 1, - newSize: number, - points: readonly Point[], - normalize: boolean, -): Point[] => { - const coordinates = points.map((point) => point[dimension]); - const maxCoordinate = Math.max(...coordinates); - const minCoordinate = Math.min(...coordinates); - const size = maxCoordinate - minCoordinate; - const scale = size === 0 ? 1 : newSize / size; - - let nextMinCoordinate = Infinity; - - const scaledPoints = points.map((point): Point => { - const newCoordinate = point[dimension] * scale; - const newPoint = [...point]; - newPoint[dimension] = newCoordinate; - if (newCoordinate < nextMinCoordinate) { - nextMinCoordinate = newCoordinate; - } - return newPoint as Point; - }); - - if (!normalize) { - return scaledPoints; - } - - if (scaledPoints.length === 2) { - // we don't translate two-point lines - return scaledPoints; - } - - const translation = minCoordinate - nextMinCoordinate; - - const nextPoints = scaledPoints.map((scaledPoint) => - pointFromPair( - scaledPoint.map((value, currentDimension) => { - return currentDimension === dimension ? value + translation : value; - }) as [number, number], - ), - ); - - return nextPoints; -}; diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 6e1f535036..1e2b86918e 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -8447,10 +8447,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1` "value": null, }, }, - "pointerOffset": { - "x": 0, - "y": 0, - }, + "pointerOffset": [ + 0, + 0, + ], "segmentMidPointHoveredCoords": null, "selectedPointsIndices": null, "startBindingElement": "keep", @@ -8667,10 +8667,10 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] "value": null, }, }, - "pointerOffset": { - "x": 0, - "y": 0, - }, + "pointerOffset": [ + 0, + 0, + ], "segmentMidPointHoveredCoords": null, "selectedPointsIndices": null, "startBindingElement": "keep", @@ -9077,10 +9077,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1` "value": null, }, }, - "pointerOffset": { - "x": 0, - "y": 0, - }, + "pointerOffset": [ + 0, + 0, + ], "segmentMidPointHoveredCoords": null, "selectedPointsIndices": null, "startBindingElement": "keep", @@ -9474,10 +9474,10 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`] "value": null, }, }, - "pointerOffset": { - "x": 0, - "y": 0, - }, + "pointerOffset": [ + 0, + 0, + ], "segmentMidPointHoveredCoords": null, "selectedPointsIndices": null, "startBindingElement": "keep", diff --git a/packages/excalidraw/visualdebug.ts b/packages/excalidraw/visualdebug.ts index 86f4d39a82..2c5587c597 100644 --- a/packages/excalidraw/visualdebug.ts +++ b/packages/excalidraw/visualdebug.ts @@ -1,5 +1,5 @@ +import type { LineSegment } from "../math"; import { isLineSegment, lineSegment, point, type GlobalPoint } from "../math"; -import type { LineSegment } from "../utils"; import type { BoundingBox, Bounds } from "./element/bounds"; import { isBounds } from "./element/typeChecks"; diff --git a/packages/math/angle.ts b/packages/math/angle.ts index 21cd653d2a..74cda1c16d 100644 --- a/packages/math/angle.ts +++ b/packages/math/angle.ts @@ -1,13 +1,43 @@ -import type { - Degrees, - GlobalPoint, - LocalPoint, - PolarCoords, - Radians, - ViewportPoint, -} from "./types"; +import type { Degrees, GenericPoint, PolarCoords, Radians } from "./types"; import { PRECISION } from "./utils"; +/** + * Construct an angle value in radians + * + * @param angle The number to mark as radians + * @returns The radians typed value + */ +export function radians(angle: number): Radians { + return angle as Radians; +} + +/** + * Construct an angle value in degrees + * + * @param angle The number to mark as degrees + * @returns The degrees typed value + */ +export function degrees(angle: number): Degrees { + return angle as Degrees; +} + +/** + * Construct a polar coordinate + * + * @param radius The radius of the circle to address with this coordinate + * @param angle The angle from the "northest" point of the cirle to address + * @returns The polar coordinate value + */ +export function polar(radius: number, angle: Radians): PolarCoords { + return [radius, angle] as PolarCoords; +} + +/** + * Convert an angle in radians into it's smallest octave + * + * @param angle The angle to normalie + * @returns The normalized angle in radians + */ // TODO: Simplify with modulo and fix for angles beyond 4*Math.PI and - 4*Math.PI export const normalizeRadians = (angle: Radians): Radians => { if (angle < 0) { @@ -23,15 +53,31 @@ export const normalizeRadians = (angle: Radians): Radians => { * Return the polar coordinates for the given cartesian point represented by * (x, y) for the center point 0,0 where the first number returned is the radius, * the second is the angle in radians. + * + * @param param0 + * @returns */ -export const cartesian2Polar = < - P extends GlobalPoint | LocalPoint | ViewportPoint, ->([x, y]: P): PolarCoords => [Math.hypot(x, y), Math.atan2(y, x)]; +export const cartesian2Polar =

([ + x, + y, +]: P): PolarCoords => polar(Math.hypot(x, y), radians(Math.atan2(y, x))); +/** + * Convert an angle in degrees into randians + * + * @param degrees The angle to convert + * @returns The angle in radians + */ export function degreesToRadians(degrees: Degrees): Radians { return ((degrees * Math.PI) / 180) as Radians; } +/** + * Convert an angle in radians into degrees + * + * @param degrees The angle to convert + * @returns The angle in degrees + */ export function radiansToDegrees(degrees: Radians): Degrees { return ((degrees * 180) / Math.PI) as Degrees; } diff --git a/packages/math/arc.test.ts b/packages/math/arc.test.ts index 12e880c9c1..6243ec0bd7 100644 --- a/packages/math/arc.test.ts +++ b/packages/math/arc.test.ts @@ -1,15 +1,12 @@ -import { isPointOnSymmetricArc } from "./arc"; +import { radians } from "./angle"; +import { arc, isPointOnSymmetricArc } from "./arc"; import { point } from "./point"; describe("point on arc", () => { it("should detect point on simple arc", () => { expect( isPointOnSymmetricArc( - { - radius: 1, - startAngle: -Math.PI / 4, - endAngle: Math.PI / 4, - }, + arc(1, radians(-Math.PI / 4), radians(Math.PI / 4)), point(0.92291667, 0.385), ), ).toBe(true); @@ -17,11 +14,7 @@ describe("point on arc", () => { it("should not detect point outside of a simple arc", () => { expect( isPointOnSymmetricArc( - { - radius: 1, - startAngle: -Math.PI / 4, - endAngle: Math.PI / 4, - }, + arc(1, radians(-Math.PI / 4), radians(Math.PI / 4)), point(-0.92291667, 0.385), ), ).toBe(false); @@ -29,11 +22,7 @@ describe("point on arc", () => { it("should not detect point with good angle but incorrect radius", () => { expect( isPointOnSymmetricArc( - { - radius: 1, - startAngle: -Math.PI / 4, - endAngle: Math.PI / 4, - }, + arc(1, radians(-Math.PI / 4), radians(Math.PI / 4)), point(-0.5, 0.5), ), ).toBe(false); diff --git a/packages/math/arc.ts b/packages/math/arc.ts index a9a3130218..2c1935fa68 100644 --- a/packages/math/arc.ts +++ b/packages/math/arc.ts @@ -1,22 +1,29 @@ import { cartesian2Polar } from "./angle"; -import type { - GlobalPoint, - LocalPoint, - SymmetricArc, - ViewportPoint, -} from "./types"; +import type { GenericPoint, Radians, SymmetricArc } from "./types"; import { PRECISION } from "./utils"; +/** + * Constructs a symmetric arc defined by the originating circle radius + * the start angle and end angle with 0 radians being the "northest" point + * of the circle. + * + * @param radius The radius of the circle this arc lies on + * @param startAngle The start angle with 0 radians being the "northest" point + * @param endAngle The end angle with 0 radians being the "northest" point + * @returns The constructed symmetric arc + */ +export function arc(radius: number, startAngle: Radians, endAngle: Radians) { + return { radius, startAngle, endAngle } as SymmetricArc; +} + /** * Determines if a cartesian point lies on a symmetric arc, i.e. an arc which * is part of a circle contour centered on 0, 0. */ -export const isPointOnSymmetricArc = < - P extends GlobalPoint | LocalPoint | ViewportPoint, ->( +export function isPointOnSymmetricArc

( { radius: arcRadius, startAngle, endAngle }: SymmetricArc, point: P, -): boolean => { +): boolean { const [radius, angle] = cartesian2Polar(point); return startAngle < endAngle @@ -24,4 +31,4 @@ export const isPointOnSymmetricArc = < startAngle <= angle && endAngle >= angle : startAngle <= angle || endAngle >= angle; -}; +} diff --git a/packages/math/curve.ts b/packages/math/curve.ts index ca4571057d..fb916c740c 100644 --- a/packages/math/curve.ts +++ b/packages/math/curve.ts @@ -1,5 +1,5 @@ import { point, pointRotateRads } from "./point"; -import type { Curve, GlobalPoint, LocalPoint, Radians } from "./types"; +import type { Curve, GenericPoint, Radians } from "./types"; /** * @@ -9,7 +9,7 @@ import type { Curve, GlobalPoint, LocalPoint, Radians } from "./types"; * @param d * @returns */ -export function curve( +export function curve( a: Point, b: Point, c: Point, @@ -18,7 +18,7 @@ export function curve( return [a, b, c, d] as Curve; } -export const curveRotate = ( +export const curveRotate = ( curve: Curve, angle: Radians, origin: Point, @@ -32,7 +32,7 @@ export const curveRotate = ( * @param curveTightness * @returns */ -export function curveToBezier( +export function curveToBezier( pointsIn: readonly Point[], curveTightness = 0, ): Point[] { @@ -84,7 +84,7 @@ export function curveToBezier( * @param controlPoints * @returns */ -export const cubicBezierPoint = ( +export const cubicBezierPoint = ( t: number, controlPoints: Curve, ): Point => { @@ -111,7 +111,7 @@ export const cubicBezierPoint = ( * @param controlPoints * @returns */ -export const cubicBezierDistance = ( +export const cubicBezierDistance = ( point: Point, controlPoints: Curve, ) => { @@ -169,7 +169,7 @@ const solveCubic = (a: number, b: number, c: number, d: number) => { return roots; }; -const findClosestParameter = ( +const findClosestParameter = ( point: Point, controlPoints: Curve, ) => { diff --git a/packages/math/point.ts b/packages/math/point.ts index 10b41bd226..659d3b8820 100644 --- a/packages/math/point.ts +++ b/packages/math/point.ts @@ -6,6 +6,8 @@ import type { Degrees, Vector, ViewportPoint, + GenericPoint, + Extent, } from "./types"; import { PRECISION } from "./utils"; import { vectorFromPoint, vectorScale } from "./vector"; @@ -259,3 +261,73 @@ export const isPointWithinBounds = < q[1] >= Math.min(p[1], r[1]) ); }; + +/** + * The extent (width and height) of a set of points. + * + * @param points The points to calculate the extent for + * @returns + */ +export const pointExtent = (points: readonly GenericPoint[]): Extent => { + const xs = points.map((point) => point[0]); + const ys = points.map((point) => point[1]); + return { + width: Math.max(...xs) - Math.min(...xs), + height: Math.max(...ys) - Math.min(...ys), + } as Extent; +}; + +/** + * Rescale the set of points from the top leftmost point as origin + * + * @param dimension 0 for rescaling only x, 1 for y + * @param newSize The target size + * @param points The points to restcale + * @param normalize Whether to normalize the result + */ +// TODO: Center should be parametric and should use pointScaleFromOrigin() +export const pointRescaleFromTopLeft = ( + dimension: 0 | 1, + newSize: number, + points: readonly Point[], + normalize: boolean, +): Point[] => { + const coordinates = points.map((point) => point[dimension]); + const maxCoordinate = Math.max(...coordinates); + const minCoordinate = Math.min(...coordinates); + const size = maxCoordinate - minCoordinate; + const scale = size === 0 ? 1 : newSize / size; + + let nextMinCoordinate = Infinity; + + const scaledPoints = points.map((point): Point => { + const newCoordinate = point[dimension] * scale; + const newPoint = [...point]; + newPoint[dimension] = newCoordinate; + if (newCoordinate < nextMinCoordinate) { + nextMinCoordinate = newCoordinate; + } + return newPoint as Point; + }); + + if (!normalize) { + return scaledPoints; + } + + if (scaledPoints.length === 2) { + // we don't translate two-point lines + return scaledPoints; + } + + const translation = minCoordinate - nextMinCoordinate; + + const nextPoints = scaledPoints.map((scaledPoint) => + pointFromPair( + scaledPoint.map((value, currentDimension) => { + return currentDimension === dimension ? value + translation : value; + }) as [number, number], + ), + ); + + return nextPoints; +}; diff --git a/packages/math/range.ts b/packages/math/range.ts index 0bef4f2636..3c89a4196b 100644 --- a/packages/math/range.ts +++ b/packages/math/range.ts @@ -87,6 +87,6 @@ export const rangeIncludesValue = ( * @param range The range of which to measure the extent of * @returns The scalar distance or extent of the start and end of the range */ -export function rangeExtent([a, b]: InclusiveRange) { +export function rangeExtent([a, b]: InclusiveRange): number { return Math.abs(a - b); } diff --git a/packages/math/rectangle.ts b/packages/math/rectangle.ts new file mode 100644 index 0000000000..96c00fbedc --- /dev/null +++ b/packages/math/rectangle.ts @@ -0,0 +1,28 @@ +import { invariant } from "../excalidraw/utils"; +import type { GenericPoint, Rectangle } from "./types"; + +export function rectangle

( + a: P, + b: P, + c: P, + d: P, +): Rectangle

{ + return [a, b, c, d] as Rectangle

; +} + +export function rectangleFromQuad

( + quad: [a: P, b: P, c: P, d: P], +): Rectangle

{ + return quad as Rectangle

; +} + +export function rectangleFromArray

( + pointArray: P[], +): Rectangle

{ + invariant( + pointArray.length === 4, + "Point array contains more or less points to create a rectangle from", + ); + + return pointArray as Rectangle

; +} diff --git a/packages/math/types.ts b/packages/math/types.ts index 2dce6ae978..107cfd2c62 100644 --- a/packages/math/types.ts +++ b/packages/math/types.ts @@ -14,19 +14,11 @@ export type Radians = number & { _brand: "excalimath__radian" }; */ export type Degrees = number & { _brand: "excalimath_degree" }; -// -// Range -// - /** * A number range which includes the start and end numbers in the range. */ export type InclusiveRange = [number, number] & { _brand: "excalimath_degree" }; -// -// Point -// - /** * Represents a 2D position in world or canvas space. A * global coordinate. @@ -50,7 +42,18 @@ export type ViewportPoint = [x: number, y: number] & { _brand: "excalimath_viewportpoint"; }; -// Line +/** + * A coordinate system useful for circular path calculations + */ +export type PolarCoords = [radius: number, angle: Radians] & { + _brand: "excalimath_polarCoords"; +}; + +/** + * Aggregate type of all the point types when a function + * is point type agnostic + */ +export type GenericPoint = GlobalPoint | LocalPoint | ViewportPoint; /** * A line is an infinitely long object with no width, depth, or curvature. @@ -71,10 +74,6 @@ export type LineSegment

= [ _brand: "excalimath_linesegment"; }; -// -// Vector -// - /** * Represents a 2D vector */ @@ -82,12 +81,10 @@ export type Vector = [u: number, v: number] & { _brand: "excalimath__vector"; }; -// Triangles - /** * A triangle represented by 3 points */ -export type Triangle

= [ +export type Triangle

= [ a: P, b: P, c: P, @@ -95,9 +92,17 @@ export type Triangle

= [ _brand: "excalimath__triangle"; }; -// -// Polygon -// +/** + * A rectangular shape represented by 4 points at its corners + */ +export type Rectangle

= [ + a: P, + b: P, + c: P, + d: P, +] & { + _brand: "excalimath__rectangle"; +}; /** * A polygon is a closed shape by connecting the given points @@ -108,10 +113,6 @@ export type Polygon = _brand: "excalimath_polygon"; }; -// -// Curve -// - /** * Cubic bezier curve with four control points */ @@ -124,18 +125,24 @@ export type Curve = [ _brand: "excalimath_curve"; }; -export type PolarCoords = [ - radius: number, - /** angle in radians */ - angle: number, -]; - /** * Angles are in radians and centered on 0, 0. Zero radians on a 1 radius circle - * corresponds to (1, 0) cartesian coordinates (point), i.e. to the "right". + * corresponds to (1, 0) cartesian coordinates (point), i.e. to the "right" */ export type SymmetricArc = { radius: number; - startAngle: number; - endAngle: number; + startAngle: Radians; + endAngle: Radians; +} & { + _brand: "excalimath_symmetricarc"; +}; + +/** + * The width and height represented as a type + */ +export type Extent = { + width: number; + height: number; +} & { + _brand: "excalimath_extent"; }; diff --git a/packages/utils/bbox.ts b/packages/utils/bbox.ts index 933c630c89..a1ffb997b2 100644 --- a/packages/utils/bbox.ts +++ b/packages/utils/bbox.ts @@ -1,3 +1,4 @@ +import type { LineSegment } from "../math"; import { vectorCross, vectorFromPoint, @@ -6,8 +7,6 @@ import { } from "../math"; import type { Bounds } from "../excalidraw/element/bounds"; -export type LineSegment

= [P, P]; - export function getBBox

( line: LineSegment

, ): Bounds {