chore: Refactor doBoundsIntersect (#9657)
This commit is contained in:
parent
058918f8e5
commit
958597dfaa
@ -24,7 +24,6 @@ import {
|
|||||||
pointsEqual,
|
pointsEqual,
|
||||||
lineSegmentIntersectionPoints,
|
lineSegmentIntersectionPoints,
|
||||||
PRECISION,
|
PRECISION,
|
||||||
doBoundsIntersect,
|
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { LocalPoint, Radians } from "@excalidraw/math";
|
||||||
@ -33,7 +32,11 @@ import type { AppState } from "@excalidraw/excalidraw/types";
|
|||||||
|
|
||||||
import type { MapEntry, Mutable } from "@excalidraw/common/utility-types";
|
import type { MapEntry, Mutable } from "@excalidraw/common/utility-types";
|
||||||
|
|
||||||
import { getCenterForBounds, getElementBounds } from "./bounds";
|
import {
|
||||||
|
doBoundsIntersect,
|
||||||
|
getCenterForBounds,
|
||||||
|
getElementBounds,
|
||||||
|
} from "./bounds";
|
||||||
import { intersectElementWithLineSegment } from "./collision";
|
import { intersectElementWithLineSegment } from "./collision";
|
||||||
import { distanceToElement } from "./distance";
|
import { distanceToElement } from "./distance";
|
||||||
import {
|
import {
|
||||||
|
@ -584,7 +584,7 @@ const solveQuadratic = (
|
|||||||
return [s1, s2];
|
return [s1, s2];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCubicBezierCurveBound = (
|
export const getCubicBezierCurveBound = (
|
||||||
p0: GlobalPoint,
|
p0: GlobalPoint,
|
||||||
p1: GlobalPoint,
|
p1: GlobalPoint,
|
||||||
p2: GlobalPoint,
|
p2: GlobalPoint,
|
||||||
@ -1230,6 +1230,20 @@ export const pointInsideBounds = <P extends GlobalPoint | LocalPoint>(
|
|||||||
): boolean =>
|
): boolean =>
|
||||||
p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3];
|
p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3];
|
||||||
|
|
||||||
|
export const doBoundsIntersect = (
|
||||||
|
bounds1: Bounds | null,
|
||||||
|
bounds2: Bounds | null,
|
||||||
|
): boolean => {
|
||||||
|
if (bounds1 == null || bounds2 == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [minX1, minY1, maxX1, maxY1] = bounds1;
|
||||||
|
const [minX2, minY2, maxX2, maxY2] = bounds2;
|
||||||
|
|
||||||
|
return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
|
||||||
|
};
|
||||||
|
|
||||||
export const elementCenterPoint = (
|
export const elementCenterPoint = (
|
||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
vectorFromPoint,
|
vectorFromPoint,
|
||||||
vectorNormalize,
|
vectorNormalize,
|
||||||
vectorScale,
|
vectorScale,
|
||||||
doBoundsIntersect,
|
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -19,15 +18,22 @@ import {
|
|||||||
ellipseSegmentInterceptPoints,
|
ellipseSegmentInterceptPoints,
|
||||||
} from "@excalidraw/math/ellipse";
|
} from "@excalidraw/math/ellipse";
|
||||||
|
|
||||||
import type { GlobalPoint, LineSegment, Radians } from "@excalidraw/math";
|
import type {
|
||||||
|
Curve,
|
||||||
|
GlobalPoint,
|
||||||
|
LineSegment,
|
||||||
|
Radians,
|
||||||
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import { isPathALoop } from "./utils";
|
import { isPathALoop } from "./utils";
|
||||||
import {
|
import {
|
||||||
type Bounds,
|
type Bounds,
|
||||||
|
doBoundsIntersect,
|
||||||
elementCenterPoint,
|
elementCenterPoint,
|
||||||
getCenterForBounds,
|
getCenterForBounds,
|
||||||
|
getCubicBezierCurveBound,
|
||||||
getElementBounds,
|
getElementBounds,
|
||||||
} from "./bounds";
|
} from "./bounds";
|
||||||
import {
|
import {
|
||||||
@ -255,13 +261,75 @@ export const intersectElementWithLineSegment = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const curveIntersections = (
|
||||||
|
curves: Curve<GlobalPoint>[],
|
||||||
|
segment: LineSegment<GlobalPoint>,
|
||||||
|
intersections: GlobalPoint[],
|
||||||
|
center: GlobalPoint,
|
||||||
|
angle: Radians,
|
||||||
|
onlyFirst = false,
|
||||||
|
) => {
|
||||||
|
for (const c of curves) {
|
||||||
|
// Optimize by doing a cheap bounding box check first
|
||||||
|
const b1 = getCubicBezierCurveBound(c[0], c[1], c[2], c[3]);
|
||||||
|
const b2 = [
|
||||||
|
Math.min(segment[0][0], segment[1][0]),
|
||||||
|
Math.min(segment[0][1], segment[1][1]),
|
||||||
|
Math.max(segment[0][0], segment[1][0]),
|
||||||
|
Math.max(segment[0][1], segment[1][1]),
|
||||||
|
] as Bounds;
|
||||||
|
|
||||||
|
if (!doBoundsIntersect(b1, b2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hits = curveIntersectLineSegment(c, segment);
|
||||||
|
|
||||||
|
if (hits.length > 0) {
|
||||||
|
for (const j of hits) {
|
||||||
|
intersections.push(pointRotateRads(j, center, angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onlyFirst) {
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
};
|
||||||
|
|
||||||
|
const lineIntersections = (
|
||||||
|
lines: LineSegment<GlobalPoint>[],
|
||||||
|
segment: LineSegment<GlobalPoint>,
|
||||||
|
intersections: GlobalPoint[],
|
||||||
|
center: GlobalPoint,
|
||||||
|
angle: Radians,
|
||||||
|
onlyFirst = false,
|
||||||
|
) => {
|
||||||
|
for (const l of lines) {
|
||||||
|
const intersection = lineSegmentIntersectionPoints(l, segment);
|
||||||
|
if (intersection) {
|
||||||
|
intersections.push(pointRotateRads(intersection, center, angle));
|
||||||
|
|
||||||
|
if (onlyFirst) {
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
};
|
||||||
|
|
||||||
const intersectLinearOrFreeDrawWithLineSegment = (
|
const intersectLinearOrFreeDrawWithLineSegment = (
|
||||||
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
|
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
|
||||||
segment: LineSegment<GlobalPoint>,
|
segment: LineSegment<GlobalPoint>,
|
||||||
onlyFirst = false,
|
onlyFirst = false,
|
||||||
): GlobalPoint[] => {
|
): GlobalPoint[] => {
|
||||||
|
// NOTE: This is the only one which return the decomposed elements
|
||||||
|
// rotated! This is due to taking advantage of roughjs definitions.
|
||||||
const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
|
const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
|
||||||
const intersections = [];
|
const intersections: GlobalPoint[] = [];
|
||||||
|
|
||||||
for (const l of lines) {
|
for (const l of lines) {
|
||||||
const intersection = lineSegmentIntersectionPoints(l, segment);
|
const intersection = lineSegmentIntersectionPoints(l, segment);
|
||||||
@ -275,6 +343,19 @@ const intersectLinearOrFreeDrawWithLineSegment = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const c of curves) {
|
for (const c of curves) {
|
||||||
|
// Optimize by doing a cheap bounding box check first
|
||||||
|
const b1 = getCubicBezierCurveBound(c[0], c[1], c[2], c[3]);
|
||||||
|
const b2 = [
|
||||||
|
Math.min(segment[0][0], segment[1][0]),
|
||||||
|
Math.min(segment[0][1], segment[1][1]),
|
||||||
|
Math.max(segment[0][0], segment[1][0]),
|
||||||
|
Math.max(segment[0][1], segment[1][1]),
|
||||||
|
] as Bounds;
|
||||||
|
|
||||||
|
if (!doBoundsIntersect(b1, b2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const hits = curveIntersectLineSegment(c, segment);
|
const hits = curveIntersectLineSegment(c, segment);
|
||||||
|
|
||||||
if (hits.length > 0) {
|
if (hits.length > 0) {
|
||||||
@ -292,7 +373,7 @@ const intersectLinearOrFreeDrawWithLineSegment = (
|
|||||||
const intersectRectanguloidWithLineSegment = (
|
const intersectRectanguloidWithLineSegment = (
|
||||||
element: ExcalidrawRectanguloidElement,
|
element: ExcalidrawRectanguloidElement,
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
l: LineSegment<GlobalPoint>,
|
segment: LineSegment<GlobalPoint>,
|
||||||
offset: number = 0,
|
offset: number = 0,
|
||||||
onlyFirst = false,
|
onlyFirst = false,
|
||||||
): GlobalPoint[] => {
|
): GlobalPoint[] => {
|
||||||
@ -300,48 +381,43 @@ const intersectRectanguloidWithLineSegment = (
|
|||||||
// To emulate a rotated rectangle we rotate the point in the inverse angle
|
// To emulate a rotated rectangle we rotate the point in the inverse angle
|
||||||
// instead. It's all the same distance-wise.
|
// instead. It's all the same distance-wise.
|
||||||
const rotatedA = pointRotateRads<GlobalPoint>(
|
const rotatedA = pointRotateRads<GlobalPoint>(
|
||||||
l[0],
|
segment[0],
|
||||||
center,
|
center,
|
||||||
-element.angle as Radians,
|
-element.angle as Radians,
|
||||||
);
|
);
|
||||||
const rotatedB = pointRotateRads<GlobalPoint>(
|
const rotatedB = pointRotateRads<GlobalPoint>(
|
||||||
l[1],
|
segment[1],
|
||||||
center,
|
center,
|
||||||
-element.angle as Radians,
|
-element.angle as Radians,
|
||||||
);
|
);
|
||||||
|
const rotatedIntersector = lineSegment(rotatedA, rotatedB);
|
||||||
|
|
||||||
// Get the element's building components we can test against
|
// Get the element's building components we can test against
|
||||||
const [sides, corners] = deconstructRectanguloidElement(element, offset);
|
const [sides, corners] = deconstructRectanguloidElement(element, offset);
|
||||||
|
|
||||||
const intersections: GlobalPoint[] = [];
|
const intersections: GlobalPoint[] = [];
|
||||||
|
|
||||||
for (const s of sides) {
|
lineIntersections(
|
||||||
const intersection = lineSegmentIntersectionPoints(
|
sides,
|
||||||
lineSegment(rotatedA, rotatedB),
|
rotatedIntersector,
|
||||||
s,
|
intersections,
|
||||||
);
|
center,
|
||||||
if (intersection) {
|
element.angle,
|
||||||
intersections.push(pointRotateRads(intersection, center, element.angle));
|
onlyFirst,
|
||||||
|
);
|
||||||
|
|
||||||
if (onlyFirst) {
|
if (onlyFirst && intersections.length > 0) {
|
||||||
return intersections;
|
return intersections;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const t of corners) {
|
curveIntersections(
|
||||||
const hits = curveIntersectLineSegment(t, lineSegment(rotatedA, rotatedB));
|
corners,
|
||||||
|
rotatedIntersector,
|
||||||
if (hits.length > 0) {
|
intersections,
|
||||||
for (const j of hits) {
|
center,
|
||||||
intersections.push(pointRotateRads(j, center, element.angle));
|
element.angle,
|
||||||
}
|
onlyFirst,
|
||||||
|
);
|
||||||
if (onlyFirst) {
|
|
||||||
return intersections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections;
|
return intersections;
|
||||||
};
|
};
|
||||||
@ -366,38 +442,32 @@ const intersectDiamondWithLineSegment = (
|
|||||||
// points. It's all the same distance-wise.
|
// points. It's all the same distance-wise.
|
||||||
const rotatedA = pointRotateRads(l[0], center, -element.angle as Radians);
|
const rotatedA = pointRotateRads(l[0], center, -element.angle as Radians);
|
||||||
const rotatedB = pointRotateRads(l[1], center, -element.angle as Radians);
|
const rotatedB = pointRotateRads(l[1], center, -element.angle as Radians);
|
||||||
|
const rotatedIntersector = lineSegment(rotatedA, rotatedB);
|
||||||
|
|
||||||
const [sides, corners] = deconstructDiamondElement(element, offset);
|
const [sides, corners] = deconstructDiamondElement(element, offset);
|
||||||
|
|
||||||
const intersections: GlobalPoint[] = [];
|
const intersections: GlobalPoint[] = [];
|
||||||
|
|
||||||
for (const s of sides) {
|
lineIntersections(
|
||||||
const intersection = lineSegmentIntersectionPoints(
|
sides,
|
||||||
lineSegment(rotatedA, rotatedB),
|
rotatedIntersector,
|
||||||
s,
|
intersections,
|
||||||
);
|
center,
|
||||||
if (intersection) {
|
element.angle,
|
||||||
intersections.push(pointRotateRads(intersection, center, element.angle));
|
onlyFirst,
|
||||||
|
);
|
||||||
|
|
||||||
if (onlyFirst) {
|
if (onlyFirst && intersections.length > 0) {
|
||||||
return intersections;
|
return intersections;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const t of corners) {
|
curveIntersections(
|
||||||
const hits = curveIntersectLineSegment(t, lineSegment(rotatedA, rotatedB));
|
corners,
|
||||||
|
rotatedIntersector,
|
||||||
if (hits.length > 0) {
|
intersections,
|
||||||
for (const j of hits) {
|
center,
|
||||||
intersections.push(pointRotateRads(j, center, element.angle));
|
element.angle,
|
||||||
}
|
onlyFirst,
|
||||||
|
);
|
||||||
if (onlyFirst) {
|
|
||||||
return intersections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections;
|
return intersections;
|
||||||
};
|
};
|
||||||
|
@ -90,6 +90,12 @@ const setElementShapesCacheEntry = <T extends ExcalidrawElement>(
|
|||||||
shapes.set(offset, shape);
|
shapes.set(offset, shape);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the **rotated** components of freedraw, line or arrow elements.
|
||||||
|
*
|
||||||
|
* @param element The linear element to deconstruct
|
||||||
|
* @returns The rotated in components.
|
||||||
|
*/
|
||||||
export function deconstructLinearOrFreeDrawElement(
|
export function deconstructLinearOrFreeDrawElement(
|
||||||
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
|
element: ExcalidrawLinearElement | ExcalidrawFreeDrawElement,
|
||||||
): [LineSegment<GlobalPoint>[], Curve<GlobalPoint>[]] {
|
): [LineSegment<GlobalPoint>[], Curve<GlobalPoint>[]] {
|
||||||
@ -171,11 +177,11 @@ export function deconstructLinearOrFreeDrawElement(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the building components of a rectanguloid element in the form of
|
* Get the building components of a rectanguloid element in the form of
|
||||||
* line segments and curves.
|
* line segments and curves **unrotated**.
|
||||||
*
|
*
|
||||||
* @param element Target rectanguloid element
|
* @param element Target rectanguloid element
|
||||||
* @param offset Optional offset to expand the rectanguloid shape
|
* @param offset Optional offset to expand the rectanguloid shape
|
||||||
* @returns Tuple of line segments (0) and curves (1)
|
* @returns Tuple of **unrotated** line segments (0) and curves (1)
|
||||||
*/
|
*/
|
||||||
export function deconstructRectanguloidElement(
|
export function deconstructRectanguloidElement(
|
||||||
element: ExcalidrawRectanguloidElement,
|
element: ExcalidrawRectanguloidElement,
|
||||||
@ -310,12 +316,12 @@ export function deconstructRectanguloidElement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the building components of a diamond element in the form of
|
* Get the **unrotated** building components of a diamond element
|
||||||
* line segments and curves as a tuple, in this order.
|
* in the form of line segments and curves as a tuple, in this order.
|
||||||
*
|
*
|
||||||
* @param element The element to deconstruct
|
* @param element The element to deconstruct
|
||||||
* @param offset An optional offset
|
* @param offset An optional offset
|
||||||
* @returns Tuple of line segments (0) and curves (1)
|
* @returns Tuple of line **unrotated** segments (0) and curves (1)
|
||||||
*/
|
*/
|
||||||
export function deconstructDiamondElement(
|
export function deconstructDiamondElement(
|
||||||
element: ExcalidrawDiamondElement,
|
element: ExcalidrawDiamondElement,
|
||||||
|
@ -4,12 +4,12 @@ import {
|
|||||||
polygonFromPoints,
|
polygonFromPoints,
|
||||||
lineSegment,
|
lineSegment,
|
||||||
polygonIncludesPointNonZero,
|
polygonIncludesPointNonZero,
|
||||||
doBoundsIntersect,
|
|
||||||
} from "@excalidraw/math";
|
} from "@excalidraw/math";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type Bounds,
|
type Bounds,
|
||||||
computeBoundTextPosition,
|
computeBoundTextPosition,
|
||||||
|
doBoundsIntersect,
|
||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
getElementBounds,
|
getElementBounds,
|
||||||
intersectElementWithLineSegment,
|
intersectElementWithLineSegment,
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { type Bounds } from "@excalidraw/element";
|
|
||||||
|
|
||||||
import { isPoint, pointDistance, pointFrom, pointFromVector } from "./point";
|
import { isPoint, pointDistance, pointFrom, pointFromVector } from "./point";
|
||||||
import { vector, vectorNormal, vectorNormalize, vectorScale } from "./vector";
|
import { vector, vectorNormal, vectorNormalize, vectorScale } from "./vector";
|
||||||
import { LegendreGaussN24CValues, LegendreGaussN24TValues } from "./constants";
|
import { LegendreGaussN24CValues, LegendreGaussN24TValues } from "./constants";
|
||||||
import { doBoundsIntersect } from "./utils";
|
|
||||||
|
|
||||||
import type { Curve, GlobalPoint, LineSegment, LocalPoint } from "./types";
|
import type { Curve, GlobalPoint, LineSegment, LocalPoint } from "./types";
|
||||||
|
|
||||||
@ -105,19 +102,6 @@ export const bezierEquation = <Point extends GlobalPoint | LocalPoint>(
|
|||||||
export function curveIntersectLineSegment<
|
export function curveIntersectLineSegment<
|
||||||
Point extends GlobalPoint | LocalPoint,
|
Point extends GlobalPoint | LocalPoint,
|
||||||
>(c: Curve<Point>, l: LineSegment<Point>): Point[] {
|
>(c: Curve<Point>, l: LineSegment<Point>): Point[] {
|
||||||
// Optimize by doing a cheap bounding box check first
|
|
||||||
const b1 = curveBounds(c);
|
|
||||||
const b2 = [
|
|
||||||
Math.min(l[0][0], l[1][0]),
|
|
||||||
Math.min(l[0][1], l[1][1]),
|
|
||||||
Math.max(l[0][0], l[1][0]),
|
|
||||||
Math.max(l[0][1], l[1][1]),
|
|
||||||
] as Bounds;
|
|
||||||
|
|
||||||
if (!doBoundsIntersect(b1, b2)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const line = (s: number) =>
|
const line = (s: number) =>
|
||||||
pointFrom<Point>(
|
pointFrom<Point>(
|
||||||
l[0][0] + s * (l[1][0] - l[0][0]),
|
l[0][0] + s * (l[1][0] - l[0][0]),
|
||||||
@ -295,15 +279,6 @@ export function curveTangent<Point extends GlobalPoint | LocalPoint>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function curveBounds<Point extends GlobalPoint | LocalPoint>(
|
|
||||||
c: Curve<Point>,
|
|
||||||
): Bounds {
|
|
||||||
const [P0, P1, P2, P3] = c;
|
|
||||||
const x = [P0[0], P1[0], P2[0], P3[0]];
|
|
||||||
const y = [P0[1], P1[1], P2[1], P3[1]];
|
|
||||||
return [Math.min(...x), Math.min(...y), Math.max(...x), Math.max(...y)];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function curveCatmullRomQuadraticApproxPoints(
|
export function curveCatmullRomQuadraticApproxPoints(
|
||||||
points: GlobalPoint[],
|
points: GlobalPoint[],
|
||||||
tension = 0.5,
|
tension = 0.5,
|
||||||
|
@ -10,6 +10,12 @@ export function rectangle<P extends GlobalPoint | LocalPoint>(
|
|||||||
return [topLeft, bottomRight] as Rectangle<P>;
|
return [topLeft, bottomRight] as Rectangle<P>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rectangleFromNumberSequence<
|
||||||
|
Point extends LocalPoint | GlobalPoint,
|
||||||
|
>(minX: number, minY: number, maxX: number, maxY: number) {
|
||||||
|
return rectangle(pointFrom<Point>(minX, minY), pointFrom<Point>(maxX, maxY));
|
||||||
|
}
|
||||||
|
|
||||||
export function rectangleIntersectLineSegment<
|
export function rectangleIntersectLineSegment<
|
||||||
Point extends LocalPoint | GlobalPoint,
|
Point extends LocalPoint | GlobalPoint,
|
||||||
>(r: Rectangle<Point>, l: LineSegment<Point>): Point[] {
|
>(r: Rectangle<Point>, l: LineSegment<Point>): Point[] {
|
||||||
@ -22,3 +28,12 @@ export function rectangleIntersectLineSegment<
|
|||||||
.map((s) => lineSegmentIntersectionPoints(l, s))
|
.map((s) => lineSegmentIntersectionPoints(l, s))
|
||||||
.filter((i): i is Point => !!i);
|
.filter((i): i is Point => !!i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rectangleIntersectRectangle<
|
||||||
|
Point extends LocalPoint | GlobalPoint,
|
||||||
|
>(rectangle1: Rectangle<Point>, rectangle2: Rectangle<Point>): boolean {
|
||||||
|
const [[minX1, minY1], [maxX1, maxY1]] = rectangle1;
|
||||||
|
const [[minX2, minY2], [maxX2, maxY2]] = rectangle2;
|
||||||
|
|
||||||
|
return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { type Bounds } from "@excalidraw/element";
|
|
||||||
|
|
||||||
export const PRECISION = 10e-5;
|
export const PRECISION = 10e-5;
|
||||||
|
|
||||||
export const clamp = (value: number, min: number, max: number) => {
|
export const clamp = (value: number, min: number, max: number) => {
|
||||||
@ -33,17 +31,3 @@ export const isFiniteNumber = (value: any): value is number => {
|
|||||||
|
|
||||||
export const isCloseTo = (a: number, b: number, precision = PRECISION) =>
|
export const isCloseTo = (a: number, b: number, precision = PRECISION) =>
|
||||||
Math.abs(a - b) < precision;
|
Math.abs(a - b) < precision;
|
||||||
|
|
||||||
export const doBoundsIntersect = (
|
|
||||||
bounds1: Bounds | null,
|
|
||||||
bounds2: Bounds | null,
|
|
||||||
): boolean => {
|
|
||||||
if (bounds1 == null || bounds2 == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [minX1, minY1, maxX1, maxY1] = bounds1;
|
|
||||||
const [minX2, minY2, maxX2, maxY2] = bounds2;
|
|
||||||
|
|
||||||
return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
|
|
||||||
};
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user