Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2025-05-18 20:23:53 +02:00
parent 624b9927cd
commit bcdcb21971
No known key found for this signature in database
3 changed files with 30 additions and 75 deletions

View File

@ -5,8 +5,6 @@ import {
} from "@excalidraw/common"; } from "@excalidraw/common";
import { import {
curveIntersectLineSegment, curveIntersectLineSegment,
isCurve,
isLineSegment,
isPointWithinBounds, isPointWithinBounds,
lineSegment, lineSegment,
lineSegmentIntersectionPoints, lineSegmentIntersectionPoints,
@ -24,12 +22,7 @@ import {
ellipseSegmentInterceptPoints, ellipseSegmentInterceptPoints,
} from "@excalidraw/math/ellipse"; } from "@excalidraw/math/ellipse";
import type { import type { GlobalPoint, LineSegment, Radians } from "@excalidraw/math";
Curve,
GlobalPoint,
LineSegment,
Radians,
} from "@excalidraw/math";
import type { FrameNameBounds } from "@excalidraw/excalidraw/types"; import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
@ -218,33 +211,13 @@ const intersectLinearOrFreeDrawWithLineSegment = (
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
segment: LineSegment<GlobalPoint>, segment: LineSegment<GlobalPoint>,
): GlobalPoint[] => { ): GlobalPoint[] => {
const shapes = deconstructLinearOrFreeDrawElement(element); const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
const intersections: GlobalPoint[] = []; return [
...lines
for (const shape of shapes) { .map((l) => lineSegmentIntersectionPoints(l, segment))
switch (true) { .filter((p): p is GlobalPoint => p != null),
case isCurve(shape): ...curves.flatMap((c) => curveIntersectLineSegment(c, segment)),
//debugDrawCubicBezier(shape); ].sort();
intersections.push(
...curveIntersectLineSegment(shape as Curve<GlobalPoint>, segment),
);
continue;
case isLineSegment(shape):
//debugDrawLine(shape);
const point = lineSegmentIntersectionPoints(
segment,
shape as LineSegment<GlobalPoint>,
);
if (point) {
intersections.push(point);
}
continue;
}
}
return intersections;
}; };
const intersectRectanguloidWithLineSegment = ( const intersectRectanguloidWithLineSegment = (

View File

@ -1,8 +1,6 @@
import { import {
curvePointDistance, curvePointDistance,
distanceToLineSegment, distanceToLineSegment,
isCurve,
isLineSegment,
pointRotateRads, pointRotateRads,
} from "@excalidraw/math"; } from "@excalidraw/math";
@ -10,12 +8,7 @@ import { ellipse, ellipseDistanceFromPoint } from "@excalidraw/math/ellipse";
import { elementCenterPoint } from "@excalidraw/common"; import { elementCenterPoint } from "@excalidraw/common";
import type { import type { GlobalPoint, Radians } from "@excalidraw/math";
Curve,
GlobalPoint,
LineSegment,
Radians,
} from "@excalidraw/math";
import { import {
deconstructDiamondElement, deconstructDiamondElement,
@ -137,31 +130,9 @@ const distanceToLinearOrFreeDraElement = (
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
p: GlobalPoint, p: GlobalPoint,
) => { ) => {
const shapes = deconstructLinearOrFreeDrawElement(element); const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
let distance = Infinity; return Math.min(
...lines.map((s) => distanceToLineSegment(p, s)),
for (const shape of shapes) { ...curves.map((a) => curvePointDistance(a, p)),
switch (true) { );
case isCurve(shape): {
const d = curvePointDistance(shape as Curve<GlobalPoint>, p);
if (d < distance) {
distance = d;
}
continue;
}
case isLineSegment(shape): {
const d = distanceToLineSegment(p, shape as LineSegment<GlobalPoint>);
if (d < distance) {
distance = d;
}
continue;
}
}
}
return distance;
}; };

View File

@ -19,19 +19,30 @@ import { generateLinearCollisionShape } from "./Shape";
import type { import type {
ExcalidrawDiamondElement, ExcalidrawDiamondElement,
ExcalidrawElement,
ExcalidrawFreeDrawElement, ExcalidrawFreeDrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawRectanguloidElement, ExcalidrawRectanguloidElement,
} from "./types"; } from "./types";
type ElementShape = [LineSegment<GlobalPoint>[], Curve<GlobalPoint>[]];
class ElementShapeCache {
private static cache = new WeakMap<
ExcalidrawElement,
Map<number, ElementShape>
>();
}
export function deconstructLinearOrFreeDrawElement( export function deconstructLinearOrFreeDrawElement(
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement, element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
): (Curve<GlobalPoint> | LineSegment<GlobalPoint>)[] { ): [LineSegment<GlobalPoint>[], Curve<GlobalPoint>[]] {
const ops = generateLinearCollisionShape(element) as { const ops = generateLinearCollisionShape(element) as {
op: string; op: string;
data: number[]; data: number[];
}[]; }[];
const components = []; const lines = [];
const curves = [];
for (let idx = 0; idx < ops.length; idx += 1) { for (let idx = 0; idx < ops.length; idx += 1) {
const op = ops[idx]; const op = ops[idx];
@ -45,7 +56,7 @@ export function deconstructLinearOrFreeDrawElement(
throw new Error("prevPoint is undefined"); throw new Error("prevPoint is undefined");
} }
components.push( lines.push(
lineSegment<GlobalPoint>( lineSegment<GlobalPoint>(
pointFrom<GlobalPoint>( pointFrom<GlobalPoint>(
element.x + prevPoint[0], element.x + prevPoint[0],
@ -63,7 +74,7 @@ export function deconstructLinearOrFreeDrawElement(
throw new Error("prevPoint is undefined"); throw new Error("prevPoint is undefined");
} }
components.push( curves.push(
curve<GlobalPoint>( curve<GlobalPoint>(
pointFrom<GlobalPoint>( pointFrom<GlobalPoint>(
element.x + prevPoint[0], element.x + prevPoint[0],
@ -90,7 +101,7 @@ export function deconstructLinearOrFreeDrawElement(
} }
} }
return components; return [lines, curves];
} }
/** /**