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,
|
ellipseSegmentInterceptPoints,
|
||||||
ellipseIncludesPoint,
|
ellipseIncludesPoint,
|
||||||
ellipseTouchesPoint,
|
ellipseTouchesPoint,
|
||||||
|
ellipseIntersectsLine,
|
||||||
} from "./ellipse";
|
} from "./ellipse";
|
||||||
|
import { line } from "./line";
|
||||||
import { point } from "./point";
|
import { point } from "./point";
|
||||||
import { segment } from "./segment";
|
import { segment } from "./segment";
|
||||||
import type { Ellipse, GlobalPoint } from "./types";
|
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", () => {
|
it("detects outside segment", () => {
|
||||||
const e = ellipse(point(0, 0), 2, 2);
|
const e = ellipse(point(0, 0), 2, 2);
|
||||||
|
|
||||||
|
@ -77,3 +79,32 @@ describe("line and ellipse", () => {
|
||||||
).toEqual([]);
|
).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 { point, pointDistance, pointFromVector, pointsEqual } from "./point";
|
||||||
import type { Ellipse, GenericPoint, Segment } from "./types";
|
import type { Ellipse, GenericPoint, Line, Segment } from "./types";
|
||||||
import { PRECISION } from "./utils";
|
import { PRECISION } from "./utils";
|
||||||
import {
|
import {
|
||||||
vector,
|
vector,
|
||||||
|
@ -180,3 +180,37 @@ export function ellipseSegmentInterceptPoints<Point extends GenericPoint>(
|
||||||
|
|
||||||
return intersections;
|
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 { point, pointCenter, pointRotateRads } from "./point";
|
||||||
import { segmentIncludesPoint } from "./segment";
|
import { segmentIncludesPoint } from "./segment";
|
||||||
import type { GenericPoint, Line, Radians, Segment } from "./types";
|
import type { GenericPoint, Line, Radians, Segment } from "./types";
|
||||||
|
@ -93,3 +94,5 @@ export function lineIntersectsSegment<Point extends GenericPoint>(
|
||||||
|
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const lineInterceptsEllipse = ellipseIntersectsLine;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
pointRotateRads,
|
pointRotateRads,
|
||||||
pointsEqual,
|
pointsEqual,
|
||||||
} from "./point";
|
} from "./point";
|
||||||
import type { GenericPoint, Segment, Radians, Line } from "./types";
|
import type { GenericPoint, Segment, Radians } from "./types";
|
||||||
import { PRECISION } from "./utils";
|
import { PRECISION } from "./utils";
|
||||||
import {
|
import {
|
||||||
vectorAdd,
|
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 l
|
||||||
|
* @param s
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function segmentIntersectsLine<Point extends GenericPoint>(
|
export const segmentIntersectsLine = lineIntersectsSegment;
|
||||||
s: Segment<Point>,
|
|
||||||
l: Line<Point>,
|
|
||||||
): Point | null {
|
|
||||||
return lineIntersectsSegment(l, s);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue