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 {
|
||||
curveIntersectLineSegment,
|
||||
isPointWithinBounds,
|
||||
line,
|
||||
lineSegment,
|
||||
lineSegmentIntersectionPoints,
|
||||
pointFrom,
|
||||
@ -12,7 +15,7 @@ import {
|
||||
|
||||
import {
|
||||
ellipse,
|
||||
ellipseLineIntersectionPoints,
|
||||
ellipseSegmentInterceptPoints,
|
||||
} from "@excalidraw/math/ellipse";
|
||||
|
||||
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 { isPathALoop } from "./shapes";
|
||||
import { getElementBounds } from "./bounds";
|
||||
import { getCommonBounds, getElementBounds } from "./bounds";
|
||||
import {
|
||||
hasBoundTextElement,
|
||||
isIframeLikeElement,
|
||||
@ -82,12 +85,21 @@ export const hitElementItself = ({
|
||||
threshold = 10,
|
||||
frameNameBound = null,
|
||||
}: HitTestArgs) => {
|
||||
let hit = shouldTestInside(element)
|
||||
// First check if the element is in the bounding box because it's MUCH faster
|
||||
// than checking if the point is in the element's shape
|
||||
let hit = hitElementBoundingBox(
|
||||
point,
|
||||
element,
|
||||
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);
|
||||
: isPointOnShape(point, element, threshold)
|
||||
: false;
|
||||
|
||||
// hit test against a frame's name
|
||||
if (!hit && frameNameBound) {
|
||||
@ -173,13 +185,16 @@ export const intersectElementWithLineSegment = (
|
||||
case "iframe":
|
||||
case "embeddable":
|
||||
case "frame":
|
||||
case "selection":
|
||||
case "magicframe":
|
||||
return intersectRectanguloidWithLineSegment(element, line, offset);
|
||||
case "diamond":
|
||||
return intersectDiamondWithLineSegment(element, line, offset);
|
||||
case "ellipse":
|
||||
return intersectEllipseWithLineSegment(element, line, offset);
|
||||
default:
|
||||
case "line":
|
||||
case "freedraw":
|
||||
case "arrow":
|
||||
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 rotatedB = pointRotateRads(l[1], center, -element.angle as Radians);
|
||||
|
||||
return ellipseLineIntersectionPoints(
|
||||
return ellipseSegmentInterceptPoints(
|
||||
ellipse(center, element.width / 2 + offset, element.height / 2 + offset),
|
||||
line(rotatedA, rotatedB),
|
||||
lineSegment(rotatedA, rotatedB),
|
||||
).map((p) => pointRotateRads(p, center, element.angle));
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user