From 4ef8285107ed167b3f619700770d0ff90c2f83ff Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Tue, 1 Apr 2025 22:42:35 +1100 Subject: [PATCH] test not importing from math --- packages/excalidraw/lasso/utils.ts | 179 +++++++++++++++++++++++++++-- 1 file changed, 168 insertions(+), 11 deletions(-) diff --git a/packages/excalidraw/lasso/utils.ts b/packages/excalidraw/lasso/utils.ts index 32aeb9160..b2731121e 100644 --- a/packages/excalidraw/lasso/utils.ts +++ b/packages/excalidraw/lasso/utils.ts @@ -1,16 +1,12 @@ import { simplify } from "points-on-curve"; -import { - polygonFromPoints, - polygonIncludesPoint, -} from "@excalidraw/math/polygon"; - -import { - lineSegment, - lineSegmentIntersectionPoints, -} from "@excalidraw/math/segment"; - -import type { GlobalPoint, LineSegment } from "@excalidraw/math/types"; +import type { + GlobalPoint, + Line, + LineSegment, + LocalPoint, + Polygon, +} from "@excalidraw/math/types"; import type { ExcalidrawElement } from "@excalidraw/element/types"; import type { @@ -107,3 +103,164 @@ const intersectionTest = ( ), ); }; + +export function polygonFromPoints( + points: Point[], +) { + return polygonClose(points) as Polygon; +} + +function polygonClose( + polygon: Point[], +) { + return polygonIsClosed(polygon) + ? polygon + : ([...polygon, polygon[0]] as Polygon); +} + +function polygonIsClosed( + polygon: Point[], +) { + return pointsEqual(polygon[0], polygon[polygon.length - 1]); +} + +const PRECISION = 10e-5; + +function pointsEqual( + a: Point, + b: Point, +): boolean { + const abs = Math.abs; + return abs(a[0] - b[0]) < PRECISION && abs(a[1] - b[1]) < PRECISION; +} + +const polygonIncludesPoint = ( + point: Point, + polygon: Polygon, +) => { + const x = point[0]; + const y = point[1]; + let inside = false; + + for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { + const xi = polygon[i][0]; + const yi = polygon[i][1]; + const xj = polygon[j][0]; + const yj = polygon[j][1]; + + if ( + ((yi > y && yj <= y) || (yi <= y && yj > y)) && + x < ((xj - xi) * (y - yi)) / (yj - yi) + xi + ) { + inside = !inside; + } + } + + return inside; +}; + +function lineSegment

( + a: P, + b: P, +): LineSegment

{ + return [a, b] as LineSegment

; +} + +function lineSegmentIntersectionPoints( + l: LineSegment, + s: LineSegment, + threshold?: number, +): Point | null { + const candidate = linesIntersectAt(line(l[0], l[1]), line(s[0], s[1])); + + if ( + !candidate || + !pointOnLineSegment(candidate, s, threshold) || + !pointOnLineSegment(candidate, l, threshold) + ) { + return null; + } + + return candidate; +} + +function linesIntersectAt( + a: Line, + b: Line, +): Point | null { + const A1 = a[1][1] - a[0][1]; + const B1 = a[0][0] - a[1][0]; + const A2 = b[1][1] - b[0][1]; + const B2 = b[0][0] - b[1][0]; + const D = A1 * B2 - A2 * B1; + if (D !== 0) { + const C1 = A1 * a[0][0] + B1 * a[0][1]; + const C2 = A2 * b[0][0] + B2 * b[0][1]; + return pointFrom((C1 * B2 - C2 * B1) / D, (A1 * C2 - A2 * C1) / D); + } + + return null; +} + +function line

(a: P, b: P): Line

{ + return [a, b] as Line

; +} + +const pointOnLineSegment = ( + point: Point, + line: LineSegment, + threshold = PRECISION, +) => { + const distance = distanceToLineSegment(point, line); + + if (distance === 0) { + return true; + } + + return distance < threshold; +}; + +const distanceToLineSegment = ( + point: Point, + line: LineSegment, +) => { + const [x, y] = point; + const [[x1, y1], [x2, y2]] = line; + + const A = x - x1; + const B = y - y1; + const C = x2 - x1; + const D = y2 - y1; + + const dot = A * C + B * D; + const len_sq = C * C + D * D; + let param = -1; + if (len_sq !== 0) { + param = dot / len_sq; + } + + let xx; + let yy; + + if (param < 0) { + xx = x1; + yy = y1; + } else if (param > 1) { + xx = x2; + yy = y2; + } else { + xx = x1 + param * C; + yy = y1 + param * D; + } + + const dx = x - xx; + const dy = y - yy; + return Math.sqrt(dx * dx + dy * dy); +}; + +function pointFrom( + x: number, + y: number, +): Point { + return [x, y] as Point; +}