aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/bbox.ts
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:35 -0400
committerkj_sh6042026-03-15 16:19:35 -0400
commit6ec259a0e71174651bae95d4628138bf6fd68742 (patch)
tree5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/utils/bbox.ts
parent16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff)
refactor: packages/
Diffstat (limited to 'packages/utils/bbox.ts')
-rw-r--r--packages/utils/bbox.ts72
1 files changed, 72 insertions, 0 deletions
diff --git a/packages/utils/bbox.ts b/packages/utils/bbox.ts
new file mode 100644
index 0000000..19a1a54
--- /dev/null
+++ b/packages/utils/bbox.ts
@@ -0,0 +1,72 @@
+import {
+ vectorCross,
+ vectorFromPoint,
+ type GlobalPoint,
+ type LocalPoint,
+} from "@excalidraw/math";
+import type { Bounds } from "@excalidraw/excalidraw/element/bounds";
+
+export type LineSegment<P extends LocalPoint | GlobalPoint> = [P, P];
+
+export function getBBox<P extends LocalPoint | GlobalPoint>(
+ line: LineSegment<P>,
+): Bounds {
+ return [
+ Math.min(line[0][0], line[1][0]),
+ Math.min(line[0][1], line[1][1]),
+ Math.max(line[0][0], line[1][0]),
+ Math.max(line[0][1], line[1][1]),
+ ];
+}
+
+export function doBBoxesIntersect(a: Bounds, b: Bounds) {
+ return a[0] <= b[2] && a[2] >= b[0] && a[1] <= b[3] && a[3] >= b[1];
+}
+
+const EPSILON = 0.000001;
+
+export function isPointOnLine<P extends GlobalPoint | LocalPoint>(
+ l: LineSegment<P>,
+ p: P,
+) {
+ const p1 = vectorFromPoint(l[1], l[0]);
+ const p2 = vectorFromPoint(p, l[0]);
+
+ const r = vectorCross(p1, p2);
+
+ return Math.abs(r) < EPSILON;
+}
+
+export function isPointRightOfLine<P extends GlobalPoint | LocalPoint>(
+ l: LineSegment<P>,
+ p: P,
+) {
+ const p1 = vectorFromPoint(l[1], l[0]);
+ const p2 = vectorFromPoint(p, l[0]);
+
+ return vectorCross(p1, p2) < 0;
+}
+
+export function isLineSegmentTouchingOrCrossingLine<
+ P extends GlobalPoint | LocalPoint,
+>(a: LineSegment<P>, b: LineSegment<P>) {
+ return (
+ isPointOnLine(a, b[0]) ||
+ isPointOnLine(a, b[1]) ||
+ (isPointRightOfLine(a, b[0])
+ ? !isPointRightOfLine(a, b[1])
+ : isPointRightOfLine(a, b[1]))
+ );
+}
+
+// https://martin-thoma.com/how-to-check-if-two-line-segments-intersect/
+export function doLineSegmentsIntersect<P extends GlobalPoint | LocalPoint>(
+ a: LineSegment<P>,
+ b: LineSegment<P>,
+) {
+ return (
+ doBBoxesIntersect(getBBox(a), getBBox(b)) &&
+ isLineSegmentTouchingOrCrossingLine(a, b) &&
+ isLineSegmentTouchingOrCrossingLine(b, a)
+ );
+}