mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
More intersection detection functions
This commit is contained in:
parent
b7f504796b
commit
6e67aa3a3c
4 changed files with 75 additions and 12 deletions
|
@ -3,7 +3,9 @@ import {
|
|||
ellipseSegmentInterceptPoints,
|
||||
ellipseIncludesPoint,
|
||||
ellipseTouchesPoint,
|
||||
ellipseIntersectsLine,
|
||||
} from "./ellipse";
|
||||
import { line } from "./line";
|
||||
import { point } from "./point";
|
||||
import { segment } from "./segment";
|
||||
import type { Ellipse, GlobalPoint } from "./types";
|
||||
|
@ -47,7 +49,7 @@ describe("point and ellipse", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("line and ellipse", () => {
|
||||
describe("segment and ellipse", () => {
|
||||
it("detects outside segment", () => {
|
||||
const e = ellipse(point(0, 0), 2, 2);
|
||||
|
||||
|
@ -77,3 +79,32 @@ describe("line and ellipse", () => {
|
|||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("line and ellipse", () => {
|
||||
const e = ellipse(point(0, 0), 2, 2);
|
||||
|
||||
it("detects outside line", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(
|
||||
e,
|
||||
line<GlobalPoint>(point(-10, -10), point(10, -10)),
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
it("detects line intersecting ellipse", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(e, line<GlobalPoint>(point(0, -1), point(0, 1))),
|
||||
).toEqual([point(0, 2), point(0, -2)]);
|
||||
expect(
|
||||
ellipseIntersectsLine(
|
||||
e,
|
||||
line<GlobalPoint>(point(-100, 0), point(-10, 0)),
|
||||
).map(([x, y]) => point(Math.round(x), Math.round(y))),
|
||||
).toEqual([point(2, 0), point(-2, 0)]);
|
||||
});
|
||||
it("detects line touching ellipse", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(e, line<GlobalPoint>(point(-2, -2), point(2, -2))),
|
||||
).toEqual([point(0, -2)]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { point, pointDistance, pointFromVector } from "./point";
|
||||
import type { Ellipse, GenericPoint, Segment } from "./types";
|
||||
import { point, pointDistance, pointFromVector, pointsEqual } from "./point";
|
||||
import type { Ellipse, GenericPoint, Line, Segment } from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
import {
|
||||
vector,
|
||||
|
@ -180,3 +180,37 @@ export function ellipseSegmentInterceptPoints<Point extends GenericPoint>(
|
|||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
export function ellipseIntersectsLine<Point extends GenericPoint>(
|
||||
{ center, halfWidth, halfHeight }: Ellipse<Point>,
|
||||
[g, h]: Line<Point>,
|
||||
): Point[] {
|
||||
const [cx, cy] = center;
|
||||
const x1 = g[0] - cx;
|
||||
const y1 = g[1] - cy;
|
||||
const x2 = h[0] - cx;
|
||||
const y2 = h[1] - cy;
|
||||
const a =
|
||||
Math.pow(x2 - x1, 2) / Math.pow(halfWidth, 2) +
|
||||
Math.pow(y2 - y1, 2) / Math.pow(halfHeight, 2);
|
||||
const b =
|
||||
2 *
|
||||
((x1 * (x2 - x1)) / Math.pow(halfWidth, 2) +
|
||||
(y1 * (y2 - y1)) / Math.pow(halfHeight, 2));
|
||||
const c =
|
||||
Math.pow(x1, 2) / Math.pow(halfWidth, 2) +
|
||||
Math.pow(y1, 2) / Math.pow(halfHeight, 2) -
|
||||
1;
|
||||
const t1 = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
|
||||
const t2 = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
|
||||
const candidates = [
|
||||
point<Point>(x1 + t1 * (x2 - x1) + cx, y1 + t1 * (y2 - y1) + cy),
|
||||
point<Point>(x1 + t2 * (x2 - x1) + cx, y1 + t2 * (y2 - y1) + cy),
|
||||
].filter((p) => !isNaN(p[0]) && !isNaN(p[1]));
|
||||
|
||||
if (candidates.length === 2 && pointsEqual(candidates[0], candidates[1])) {
|
||||
return [candidates[0]];
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ellipseIntersectsLine } from "./ellipse";
|
||||
import { point, pointCenter, pointRotateRads } from "./point";
|
||||
import { segmentIncludesPoint } from "./segment";
|
||||
import type { GenericPoint, Line, Radians, Segment } from "./types";
|
||||
|
@ -93,3 +94,5 @@ export function lineIntersectsSegment<Point extends GenericPoint>(
|
|||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
export const lineInterceptsEllipse = ellipseIntersectsLine;
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
pointRotateRads,
|
||||
pointsEqual,
|
||||
} from "./point";
|
||||
import type { GenericPoint, Segment, Radians, Line } from "./types";
|
||||
import type { GenericPoint, Segment, Radians } from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
import {
|
||||
vectorAdd,
|
||||
|
@ -180,15 +180,10 @@ export function segmentDistanceToPoint<Point extends GenericPoint>(
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection point between a segment and a line, if any
|
||||
* Returns the intersection point of a segment and a line
|
||||
*
|
||||
* @param s
|
||||
* @param l
|
||||
* @param s
|
||||
* @returns
|
||||
*/
|
||||
export function segmentIntersectsLine<Point extends GenericPoint>(
|
||||
s: Segment<Point>,
|
||||
l: Line<Point>,
|
||||
): Point | null {
|
||||
return lineIntersectsSegment(l, s);
|
||||
}
|
||||
export const segmentIntersectsLine = lineIntersectsSegment;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue