Fast fail path for hit testing
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
parent
04e1bf0bc4
commit
52205031ab
@ -1,8 +1,11 @@
|
|||||||
import { isTransparent, elementCenterPoint } from "@excalidraw/common";
|
import {
|
||||||
|
isTransparent,
|
||||||
|
elementCenterPoint,
|
||||||
|
arrayToMap,
|
||||||
|
} from "@excalidraw/common";
|
||||||
import {
|
import {
|
||||||
curveIntersectLineSegment,
|
curveIntersectLineSegment,
|
||||||
isPointWithinBounds,
|
isPointWithinBounds,
|
||||||
line,
|
|
||||||
lineSegment,
|
lineSegment,
|
||||||
lineSegmentIntersectionPoints,
|
lineSegmentIntersectionPoints,
|
||||||
pointFrom,
|
pointFrom,
|
||||||
@ -12,7 +15,7 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ellipse,
|
ellipse,
|
||||||
ellipseLineIntersectionPoints,
|
ellipseSegmentInterceptPoints,
|
||||||
} from "@excalidraw/math/ellipse";
|
} from "@excalidraw/math/ellipse";
|
||||||
|
|
||||||
import { isPointInShape, isPointOnShape } from "@excalidraw/utils/collision";
|
import { isPointInShape, isPointOnShape } from "@excalidraw/utils/collision";
|
||||||
@ -22,7 +25,7 @@ import type { GlobalPoint, LineSegment, Radians } from "@excalidraw/math";
|
|||||||
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
||||||
|
|
||||||
import { isPathALoop } from "./shapes";
|
import { isPathALoop } from "./shapes";
|
||||||
import { getElementBounds } from "./bounds";
|
import { getCommonBounds, getElementBounds } from "./bounds";
|
||||||
import {
|
import {
|
||||||
hasBoundTextElement,
|
hasBoundTextElement,
|
||||||
isIframeLikeElement,
|
isIframeLikeElement,
|
||||||
@ -82,12 +85,21 @@ export const hitElementItself = ({
|
|||||||
threshold = 10,
|
threshold = 10,
|
||||||
frameNameBound = null,
|
frameNameBound = null,
|
||||||
}: HitTestArgs) => {
|
}: HitTestArgs) => {
|
||||||
let hit = shouldTestInside(element)
|
// First check if the element is in the bounding box because it's MUCH faster
|
||||||
? // Since `inShape` tests STRICTLY againt the insides of a shape
|
// than checking if the point is in the element's shape
|
||||||
// we would need `onShape` as well to include the "borders"
|
let hit = hitElementBoundingBox(
|
||||||
isPointInShape(point, element) ||
|
point,
|
||||||
isPointOnShape(point, element, threshold)
|
element,
|
||||||
: isPointOnShape(point, element, threshold);
|
arrayToMap([element]),
|
||||||
|
threshold,
|
||||||
|
)
|
||||||
|
? shouldTestInside(element)
|
||||||
|
? // Since `inShape` tests STRICTLY againt the insides of a shape
|
||||||
|
// we would need `onShape` as well to include the "borders"
|
||||||
|
isPointInShape(point, element) ||
|
||||||
|
isPointOnShape(point, element, threshold)
|
||||||
|
: isPointOnShape(point, element, threshold)
|
||||||
|
: false;
|
||||||
|
|
||||||
// hit test against a frame's name
|
// hit test against a frame's name
|
||||||
if (!hit && frameNameBound) {
|
if (!hit && frameNameBound) {
|
||||||
@ -173,13 +185,16 @@ export const intersectElementWithLineSegment = (
|
|||||||
case "iframe":
|
case "iframe":
|
||||||
case "embeddable":
|
case "embeddable":
|
||||||
case "frame":
|
case "frame":
|
||||||
|
case "selection":
|
||||||
case "magicframe":
|
case "magicframe":
|
||||||
return intersectRectanguloidWithLineSegment(element, line, offset);
|
return intersectRectanguloidWithLineSegment(element, line, offset);
|
||||||
case "diamond":
|
case "diamond":
|
||||||
return intersectDiamondWithLineSegment(element, line, offset);
|
return intersectDiamondWithLineSegment(element, line, offset);
|
||||||
case "ellipse":
|
case "ellipse":
|
||||||
return intersectEllipseWithLineSegment(element, line, offset);
|
return intersectEllipseWithLineSegment(element, line, offset);
|
||||||
default:
|
case "line":
|
||||||
|
case "freedraw":
|
||||||
|
case "arrow":
|
||||||
throw new Error(`Unimplemented element type '${element.type}'`);
|
throw new Error(`Unimplemented element type '${element.type}'`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -301,8 +316,8 @@ const intersectEllipseWithLineSegment = (
|
|||||||
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);
|
||||||
|
|
||||||
return ellipseLineIntersectionPoints(
|
return ellipseSegmentInterceptPoints(
|
||||||
ellipse(center, element.width / 2 + offset, element.height / 2 + offset),
|
ellipse(center, element.width / 2 + offset, element.height / 2 + offset),
|
||||||
line(rotatedA, rotatedB),
|
lineSegment(rotatedA, rotatedB),
|
||||||
).map((p) => pointRotateRads(p, center, element.angle));
|
).map((p) => pointRotateRads(p, center, element.angle));
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user