You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.9 KiB
163 lines
4.9 KiB
import { |
|
pointFrom, |
|
lineSegment, |
|
polygon, |
|
pointOnLineSegment, |
|
pointOnPolygon, |
|
polygonIncludesPoint, |
|
segmentsIntersectAt, |
|
} from "@excalidraw/math"; |
|
|
|
import type { |
|
GlobalPoint, |
|
LineSegment, |
|
Polygon, |
|
Radians, |
|
} from "@excalidraw/math"; |
|
|
|
import { pointInEllipse, pointOnEllipse, type Ellipse } from "../src/shape"; |
|
|
|
describe("point and line", () => { |
|
// const l: Line<GlobalPoint> = line(point(1, 0), point(1, 2)); |
|
|
|
// it("point on left or right of line", () => { |
|
// expect(pointLeftofLine(point(0, 1), l)).toBe(true); |
|
// expect(pointLeftofLine(point(1, 1), l)).toBe(false); |
|
// expect(pointLeftofLine(point(2, 1), l)).toBe(false); |
|
|
|
// expect(pointRightofLine(point(0, 1), l)).toBe(false); |
|
// expect(pointRightofLine(point(1, 1), l)).toBe(false); |
|
// expect(pointRightofLine(point(2, 1), l)).toBe(true); |
|
// }); |
|
|
|
const s: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 0), |
|
pointFrom(1, 2), |
|
); |
|
|
|
it("point on the line", () => { |
|
expect(pointOnLineSegment(pointFrom(0, 1), s)).toBe(false); |
|
expect(pointOnLineSegment(pointFrom(1, 1), s, 0)).toBe(true); |
|
expect(pointOnLineSegment(pointFrom(2, 1), s)).toBe(false); |
|
}); |
|
}); |
|
|
|
describe("point and polygon", () => { |
|
const poly: Polygon<GlobalPoint> = polygon( |
|
pointFrom(10, 10), |
|
pointFrom(50, 10), |
|
pointFrom(50, 50), |
|
pointFrom(10, 50), |
|
); |
|
|
|
it("point on polygon", () => { |
|
expect(pointOnPolygon(pointFrom(30, 10), poly)).toBe(true); |
|
expect(pointOnPolygon(pointFrom(50, 30), poly)).toBe(true); |
|
expect(pointOnPolygon(pointFrom(30, 50), poly)).toBe(true); |
|
expect(pointOnPolygon(pointFrom(10, 30), poly)).toBe(true); |
|
expect(pointOnPolygon(pointFrom(30, 30), poly)).toBe(false); |
|
expect(pointOnPolygon(pointFrom(30, 70), poly)).toBe(false); |
|
}); |
|
|
|
it("point in polygon", () => { |
|
const poly: Polygon<GlobalPoint> = polygon( |
|
pointFrom(0, 0), |
|
pointFrom(2, 0), |
|
pointFrom(2, 2), |
|
pointFrom(0, 2), |
|
); |
|
expect(polygonIncludesPoint(pointFrom(1, 1), poly)).toBe(true); |
|
expect(polygonIncludesPoint(pointFrom(3, 3), poly)).toBe(false); |
|
}); |
|
}); |
|
|
|
describe("point and ellipse", () => { |
|
const ellipse: Ellipse<GlobalPoint> = { |
|
center: pointFrom(0, 0), |
|
angle: 0 as Radians, |
|
halfWidth: 2, |
|
halfHeight: 1, |
|
}; |
|
|
|
it("point on ellipse", () => { |
|
[ |
|
pointFrom(0, 1), |
|
pointFrom(0, -1), |
|
pointFrom(2, 0), |
|
pointFrom(-2, 0), |
|
].forEach((p) => { |
|
expect(pointOnEllipse(p, ellipse)).toBe(true); |
|
}); |
|
expect(pointOnEllipse(pointFrom(-1.4, 0.7), ellipse, 0.1)).toBe(true); |
|
expect(pointOnEllipse(pointFrom(-1.4, 0.71), ellipse, 0.01)).toBe(true); |
|
|
|
expect(pointOnEllipse(pointFrom(1.4, 0.7), ellipse, 0.1)).toBe(true); |
|
expect(pointOnEllipse(pointFrom(1.4, 0.71), ellipse, 0.01)).toBe(true); |
|
|
|
expect(pointOnEllipse(pointFrom(1, -0.86), ellipse, 0.1)).toBe(true); |
|
expect(pointOnEllipse(pointFrom(1, -0.86), ellipse, 0.01)).toBe(true); |
|
|
|
expect(pointOnEllipse(pointFrom(-1, -0.86), ellipse, 0.1)).toBe(true); |
|
expect(pointOnEllipse(pointFrom(-1, -0.86), ellipse, 0.01)).toBe(true); |
|
|
|
expect(pointOnEllipse(pointFrom(-1, 0.8), ellipse)).toBe(false); |
|
expect(pointOnEllipse(pointFrom(1, -0.8), ellipse)).toBe(false); |
|
}); |
|
|
|
it("point in ellipse", () => { |
|
[ |
|
pointFrom(0, 1), |
|
pointFrom(0, -1), |
|
pointFrom(2, 0), |
|
pointFrom(-2, 0), |
|
].forEach((p) => { |
|
expect(pointInEllipse(p, ellipse)).toBe(true); |
|
}); |
|
|
|
expect(pointInEllipse(pointFrom(-1, 0.8), ellipse)).toBe(true); |
|
expect(pointInEllipse(pointFrom(1, -0.8), ellipse)).toBe(true); |
|
|
|
expect(pointInEllipse(pointFrom(-1, 1), ellipse)).toBe(false); |
|
expect(pointInEllipse(pointFrom(-1.4, 0.8), ellipse)).toBe(false); |
|
}); |
|
}); |
|
|
|
describe("line and line", () => { |
|
const lineA: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 4), |
|
pointFrom(3, 4), |
|
); |
|
const lineB: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(2, 1), |
|
pointFrom(2, 7), |
|
); |
|
const lineC: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 8), |
|
pointFrom(3, 8), |
|
); |
|
const lineD: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 8), |
|
pointFrom(3, 8), |
|
); |
|
const lineE: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 9), |
|
pointFrom(3, 9), |
|
); |
|
const lineF: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(1, 2), |
|
pointFrom(3, 4), |
|
); |
|
const lineG: LineSegment<GlobalPoint> = lineSegment( |
|
pointFrom(0, 1), |
|
pointFrom(2, 3), |
|
); |
|
|
|
it("intersection", () => { |
|
expect(segmentsIntersectAt(lineA, lineB)).toEqual([2, 4]); |
|
expect(segmentsIntersectAt(lineA, lineC)).toBe(null); |
|
expect(segmentsIntersectAt(lineB, lineC)).toBe(null); |
|
expect(segmentsIntersectAt(lineC, lineD)).toBe(null); // Line overlapping line is not intersection! |
|
expect(segmentsIntersectAt(lineE, lineD)).toBe(null); |
|
expect(segmentsIntersectAt(lineF, lineG)).toBe(null); |
|
}); |
|
});
|
|
|