mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Replace intersection code
This commit is contained in:
parent
411deae176
commit
0c02972695
18 changed files with 507 additions and 687 deletions
|
@ -1,5 +1,11 @@
|
|||
import { radians } from "./angle";
|
||||
import { arc, arcIncludesPoint, arcSegmentInterceptPoints } from "./arc";
|
||||
import {
|
||||
arc,
|
||||
arcIncludesPoint,
|
||||
arcLineInterceptPoints,
|
||||
arcSegmentInterceptPoints,
|
||||
} from "./arc";
|
||||
import { line } from "./line";
|
||||
import { point } from "./point";
|
||||
import { segment } from "./segment";
|
||||
|
||||
|
@ -31,7 +37,7 @@ describe("point on arc", () => {
|
|||
});
|
||||
|
||||
describe("intersection", () => {
|
||||
it("should report correct interception point", () => {
|
||||
it("should report correct interception point for segment", () => {
|
||||
expect(
|
||||
arcSegmentInterceptPoints(
|
||||
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
|
||||
|
@ -40,7 +46,7 @@ describe("intersection", () => {
|
|||
).toEqual([point(0.894427190999916, 0.447213595499958)]);
|
||||
});
|
||||
|
||||
it("should report both interception points when present", () => {
|
||||
it("should report both interception points when present for segment", () => {
|
||||
expect(
|
||||
arcSegmentInterceptPoints(
|
||||
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
|
||||
|
@ -51,4 +57,25 @@ describe("intersection", () => {
|
|||
point(0.9, 0.4358898943540668),
|
||||
]);
|
||||
});
|
||||
|
||||
it("should report correct interception point for line", () => {
|
||||
expect(
|
||||
arcLineInterceptPoints(
|
||||
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
|
||||
line(point(2, 1), point(0, 0)),
|
||||
),
|
||||
).toEqual([point(0.894427190999916, 0.447213595499958)]);
|
||||
});
|
||||
|
||||
it("should report both interception points when present for line", () => {
|
||||
expect(
|
||||
arcLineInterceptPoints(
|
||||
arc(point(0, 0), 1, radians(-Math.PI / 4), radians(Math.PI / 4)),
|
||||
line(point(0.9, -2), point(0.9, 2)),
|
||||
),
|
||||
).toEqual([
|
||||
point(0.9, 0.4358898943540668),
|
||||
point(0.9, -0.4358898943540668),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,10 +2,11 @@ import { cartesian2Polar, normalizeRadians, radians } from "./angle";
|
|||
import {
|
||||
ellipse,
|
||||
ellipseDistanceFromPoint,
|
||||
ellipseLineIntersectionPoints,
|
||||
ellipseSegmentInterceptPoints,
|
||||
} from "./ellipse";
|
||||
import { point, pointDistance } from "./point";
|
||||
import type { GenericPoint, Segment, Radians, Arc } from "./types";
|
||||
import type { GenericPoint, Segment, Radians, Arc, Line } from "./types";
|
||||
import { PRECISION } from "./utils";
|
||||
|
||||
/**
|
||||
|
@ -85,7 +86,7 @@ export function arcDistanceFromPoint<Point extends GenericPoint>(
|
|||
|
||||
/**
|
||||
* Returns the intersection point(s) of a line segment represented by a start
|
||||
* point and end point and a symmetric arc.
|
||||
* point and end point and a symmetric arc
|
||||
*/
|
||||
export function arcSegmentInterceptPoints<Point extends GenericPoint>(
|
||||
a: Readonly<Arc<Point>>,
|
||||
|
@ -106,3 +107,31 @@ export function arcSegmentInterceptPoints<Point extends GenericPoint>(
|
|||
: a.startAngle <= candidateAngle || a.endAngle >= candidateAngle;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection point(s) of a line segment represented by a start
|
||||
* point and end point and a symmetric arc
|
||||
*
|
||||
* @param a
|
||||
* @param l
|
||||
* @returns
|
||||
*/
|
||||
export function arcLineInterceptPoints<Point extends GenericPoint>(
|
||||
a: Readonly<Arc<Point>>,
|
||||
l: Readonly<Line<Point>>,
|
||||
): Point[] {
|
||||
return ellipseLineIntersectionPoints(
|
||||
ellipse(a.center, a.radius, a.radius),
|
||||
l,
|
||||
).filter((candidate) => {
|
||||
const [candidateRadius, candidateAngle] = cartesian2Polar(
|
||||
point(candidate[0] - a.center[0], candidate[1] - a.center[1]),
|
||||
);
|
||||
|
||||
return a.startAngle < a.endAngle
|
||||
? Math.abs(a.radius - candidateRadius) < PRECISION &&
|
||||
a.startAngle <= candidateAngle &&
|
||||
a.endAngle >= candidateAngle
|
||||
: a.startAngle <= candidateAngle || a.endAngle >= candidateAngle;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
ellipseSegmentInterceptPoints,
|
||||
ellipseIncludesPoint,
|
||||
ellipseTouchesPoint,
|
||||
ellipseIntersectsLine,
|
||||
ellipseLineIntersectionPoints,
|
||||
} from "./ellipse";
|
||||
import { line } from "./line";
|
||||
import { point } from "./point";
|
||||
|
@ -85,7 +85,7 @@ describe("line and ellipse", () => {
|
|||
|
||||
it("detects outside line", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(
|
||||
ellipseLineIntersectionPoints(
|
||||
e,
|
||||
line<GlobalPoint>(point(-10, -10), point(10, -10)),
|
||||
),
|
||||
|
@ -93,10 +93,10 @@ describe("line and ellipse", () => {
|
|||
});
|
||||
it("detects line intersecting ellipse", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(e, line<GlobalPoint>(point(0, -1), point(0, 1))),
|
||||
ellipseLineIntersectionPoints(e, line<GlobalPoint>(point(0, -1), point(0, 1))),
|
||||
).toEqual([point(0, 2), point(0, -2)]);
|
||||
expect(
|
||||
ellipseIntersectsLine(
|
||||
ellipseLineIntersectionPoints(
|
||||
e,
|
||||
line<GlobalPoint>(point(-100, 0), point(-10, 0)),
|
||||
).map(([x, y]) => point(Math.round(x), Math.round(y))),
|
||||
|
@ -104,7 +104,7 @@ describe("line and ellipse", () => {
|
|||
});
|
||||
it("detects line touching ellipse", () => {
|
||||
expect(
|
||||
ellipseIntersectsLine(e, line<GlobalPoint>(point(-2, -2), point(2, -2))),
|
||||
ellipseLineIntersectionPoints(e, line<GlobalPoint>(point(-2, -2), point(2, -2))),
|
||||
).toEqual([point(0, -2)]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -181,7 +181,7 @@ export function ellipseSegmentInterceptPoints<Point extends GenericPoint>(
|
|||
return intersections;
|
||||
}
|
||||
|
||||
export function ellipseIntersectsLine<Point extends GenericPoint>(
|
||||
export function ellipseLineIntersectionPoints<Point extends GenericPoint>(
|
||||
{ center, halfWidth, halfHeight }: Ellipse<Point>,
|
||||
[g, h]: Line<Point>,
|
||||
): Point[] {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { line, lineIntersectsLine, lineIntersectsSegment } from "./line";
|
||||
import { line, lineLineIntersectionPoint, lineSegmentIntersectionPoints } from "./line";
|
||||
import { point } from "./point";
|
||||
import { segment } from "./segment";
|
||||
|
||||
describe("line-line intersections", () => {
|
||||
it("should correctly detect intersection at origin", () => {
|
||||
expect(
|
||||
lineIntersectsLine(
|
||||
lineLineIntersectionPoint(
|
||||
line(point(-5, -5), point(5, 5)),
|
||||
line(point(5, -5), point(-5, 5)),
|
||||
),
|
||||
|
@ -14,7 +14,7 @@ describe("line-line intersections", () => {
|
|||
|
||||
it("should correctly detect intersection at non-origin", () => {
|
||||
expect(
|
||||
lineIntersectsLine(
|
||||
lineLineIntersectionPoint(
|
||||
line(point(0, 0), point(10, 10)),
|
||||
line(point(10, 0), point(0, 10)),
|
||||
),
|
||||
|
@ -23,7 +23,7 @@ describe("line-line intersections", () => {
|
|||
|
||||
it("should correctly detect parallel lines", () => {
|
||||
expect(
|
||||
lineIntersectsLine(
|
||||
lineLineIntersectionPoint(
|
||||
line(point(0, 0), point(0, 10)),
|
||||
line(point(10, 0), point(10, 10)),
|
||||
),
|
||||
|
@ -34,7 +34,7 @@ describe("line-line intersections", () => {
|
|||
describe("line-segment intersections", () => {
|
||||
it("should correctly detect intersection", () => {
|
||||
expect(
|
||||
lineIntersectsSegment(
|
||||
lineSegmentIntersectionPoints(
|
||||
line(point(0, 0), point(5, 0)),
|
||||
segment(point(2, -2), point(3, 2)),
|
||||
),
|
||||
|
@ -42,7 +42,7 @@ describe("line-segment intersections", () => {
|
|||
});
|
||||
it("should correctly detect non-intersection", () => {
|
||||
expect(
|
||||
lineIntersectsSegment(
|
||||
lineSegmentIntersectionPoints(
|
||||
line(point(0, 0), point(5, 0)),
|
||||
segment(point(3, 1), point(4, 4)),
|
||||
),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ellipseIntersectsLine } from "./ellipse";
|
||||
import { ellipseLineIntersectionPoints } from "./ellipse";
|
||||
import { point, pointCenter, pointRotateRads } from "./point";
|
||||
import { segmentIncludesPoint } from "./segment";
|
||||
import type { GenericPoint, Line, Radians, Segment } from "./types";
|
||||
|
@ -60,7 +60,7 @@ export function lineRotate<Point extends GenericPoint>(
|
|||
* @param b Another line to intersect
|
||||
* @returns The intersection point
|
||||
*/
|
||||
export function lineIntersectsLine<Point extends GenericPoint>(
|
||||
export function lineLineIntersectionPoint<Point extends GenericPoint>(
|
||||
[[x1, y1], [x2, y2]]: Line<Point>,
|
||||
[[x3, y3], [x4, y4]]: Line<Point>,
|
||||
): Point | null {
|
||||
|
@ -83,11 +83,11 @@ export function lineIntersectsLine<Point extends GenericPoint>(
|
|||
* @param s
|
||||
* @returns
|
||||
*/
|
||||
export function lineIntersectsSegment<Point extends GenericPoint>(
|
||||
export function lineSegmentIntersectionPoints<Point extends GenericPoint>(
|
||||
l: Line<Point>,
|
||||
s: Segment<Point>,
|
||||
): Point | null {
|
||||
const candidate = lineIntersectsLine(l, line(s[0], s[1]));
|
||||
const candidate = lineLineIntersectionPoint(l, line(s[0], s[1]));
|
||||
if (!candidate || !segmentIncludesPoint(candidate, s)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -95,4 +95,4 @@ export function lineIntersectsSegment<Point extends GenericPoint>(
|
|||
return candidate;
|
||||
}
|
||||
|
||||
export const lineInterceptsEllipse = ellipseIntersectsLine;
|
||||
export const lineInterceptsEllipse = ellipseLineIntersectionPoints;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { lineIntersectsSegment } from "./line";
|
||||
import { lineSegmentIntersectionPoints } from "./line";
|
||||
import {
|
||||
isPoint,
|
||||
pointCenter,
|
||||
|
@ -186,4 +186,4 @@ export function segmentDistanceToPoint<Point extends GenericPoint>(
|
|||
* @param s
|
||||
* @returns
|
||||
*/
|
||||
export const segmentIntersectsLine = lineIntersectsSegment;
|
||||
export const segmentLineIntersectionPoints = lineSegmentIntersectionPoints;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue