From bcdcb219712089af6d552211e67768ee4371d875 Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Sun, 18 May 2025 20:23:53 +0200 Subject: [PATCH] Refactor Signed-off-by: Mark Tolmacs --- packages/element/src/collision.ts | 43 ++++++------------------------- packages/element/src/distance.ts | 41 +++++------------------------ packages/element/src/utils.ts | 21 +++++++++++---- 3 files changed, 30 insertions(+), 75 deletions(-) diff --git a/packages/element/src/collision.ts b/packages/element/src/collision.ts index 5fbdb1091..25f0137cb 100644 --- a/packages/element/src/collision.ts +++ b/packages/element/src/collision.ts @@ -5,8 +5,6 @@ import { } from "@excalidraw/common"; import { curveIntersectLineSegment, - isCurve, - isLineSegment, isPointWithinBounds, lineSegment, lineSegmentIntersectionPoints, @@ -24,12 +22,7 @@ import { ellipseSegmentInterceptPoints, } from "@excalidraw/math/ellipse"; -import type { - Curve, - GlobalPoint, - LineSegment, - Radians, -} from "@excalidraw/math"; +import type { GlobalPoint, LineSegment, Radians } from "@excalidraw/math"; import type { FrameNameBounds } from "@excalidraw/excalidraw/types"; @@ -218,33 +211,13 @@ const intersectLinearOrFreeDrawWithLineSegment = ( element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, segment: LineSegment, ): GlobalPoint[] => { - const shapes = deconstructLinearOrFreeDrawElement(element); - const intersections: GlobalPoint[] = []; - - for (const shape of shapes) { - switch (true) { - case isCurve(shape): - //debugDrawCubicBezier(shape); - intersections.push( - ...curveIntersectLineSegment(shape as Curve, segment), - ); - continue; - case isLineSegment(shape): - //debugDrawLine(shape); - const point = lineSegmentIntersectionPoints( - segment, - shape as LineSegment, - ); - - if (point) { - intersections.push(point); - } - - continue; - } - } - - return intersections; + const [lines, curves] = deconstructLinearOrFreeDrawElement(element); + return [ + ...lines + .map((l) => lineSegmentIntersectionPoints(l, segment)) + .filter((p): p is GlobalPoint => p != null), + ...curves.flatMap((c) => curveIntersectLineSegment(c, segment)), + ].sort(); }; const intersectRectanguloidWithLineSegment = ( diff --git a/packages/element/src/distance.ts b/packages/element/src/distance.ts index 43482c87e..e4b9b2f3c 100644 --- a/packages/element/src/distance.ts +++ b/packages/element/src/distance.ts @@ -1,8 +1,6 @@ import { curvePointDistance, distanceToLineSegment, - isCurve, - isLineSegment, pointRotateRads, } from "@excalidraw/math"; @@ -10,12 +8,7 @@ import { ellipse, ellipseDistanceFromPoint } from "@excalidraw/math/ellipse"; import { elementCenterPoint } from "@excalidraw/common"; -import type { - Curve, - GlobalPoint, - LineSegment, - Radians, -} from "@excalidraw/math"; +import type { GlobalPoint, Radians } from "@excalidraw/math"; import { deconstructDiamondElement, @@ -137,31 +130,9 @@ const distanceToLinearOrFreeDraElement = ( element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, p: GlobalPoint, ) => { - const shapes = deconstructLinearOrFreeDrawElement(element); - let distance = Infinity; - - for (const shape of shapes) { - switch (true) { - case isCurve(shape): { - const d = curvePointDistance(shape as Curve, p); - - if (d < distance) { - distance = d; - } - - continue; - } - case isLineSegment(shape): { - const d = distanceToLineSegment(p, shape as LineSegment); - - if (d < distance) { - distance = d; - } - - continue; - } - } - } - - return distance; + const [lines, curves] = deconstructLinearOrFreeDrawElement(element); + return Math.min( + ...lines.map((s) => distanceToLineSegment(p, s)), + ...curves.map((a) => curvePointDistance(a, p)), + ); }; diff --git a/packages/element/src/utils.ts b/packages/element/src/utils.ts index ccc41c11f..9f801fcf3 100644 --- a/packages/element/src/utils.ts +++ b/packages/element/src/utils.ts @@ -19,19 +19,30 @@ import { generateLinearCollisionShape } from "./Shape"; import type { ExcalidrawDiamondElement, + ExcalidrawElement, ExcalidrawFreeDrawElement, ExcalidrawLinearElement, ExcalidrawRectanguloidElement, } from "./types"; +type ElementShape = [LineSegment[], Curve[]]; + +class ElementShapeCache { + private static cache = new WeakMap< + ExcalidrawElement, + Map + >(); +} + export function deconstructLinearOrFreeDrawElement( element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, -): (Curve | LineSegment)[] { +): [LineSegment[], Curve[]] { const ops = generateLinearCollisionShape(element) as { op: string; data: number[]; }[]; - const components = []; + const lines = []; + const curves = []; for (let idx = 0; idx < ops.length; idx += 1) { const op = ops[idx]; @@ -45,7 +56,7 @@ export function deconstructLinearOrFreeDrawElement( throw new Error("prevPoint is undefined"); } - components.push( + lines.push( lineSegment( pointFrom( element.x + prevPoint[0], @@ -63,7 +74,7 @@ export function deconstructLinearOrFreeDrawElement( throw new Error("prevPoint is undefined"); } - components.push( + curves.push( curve( pointFrom( element.x + prevPoint[0], @@ -90,7 +101,7 @@ export function deconstructLinearOrFreeDrawElement( } } - return components; + return [lines, curves]; } /**