Rectangle distance and tests

This commit is contained in:
Mark Tolmacs 2024-09-25 15:04:46 +02:00
parent 9a8aabbeca
commit 47cc842415
No known key found for this signature in database
5 changed files with 72 additions and 25 deletions

View file

@ -0,0 +1,39 @@
import { point } from "./point";
import { rectangle, rectangleDistanceFromPoint } from "./rectangle";
describe("rectangle distance", () => {
it("finds the shortest distance", () => {
expect(
rectangleDistanceFromPoint(
rectangle(point(-1, -1), point(1, 1)),
point(2, 0),
),
).toBe(1);
expect(
rectangleDistanceFromPoint(
rectangle(point(-1, -1), point(1, 1)),
point(0, 2),
),
).toBe(1);
expect(
rectangleDistanceFromPoint(
rectangle(point(-1, -1), point(1, 1)),
point(-2, 0),
),
).toBe(1);
expect(
rectangleDistanceFromPoint(
rectangle(point(-1, -1), point(1, 1)),
point(0, -2),
),
).toBe(1);
});
it("finds the corner as closest point", () => {
expect(
rectangleDistanceFromPoint(
rectangle(point(-1, -1), point(1, 1)),
point(2, 2),
),
).toBe(Math.sqrt(2));
});
});

View file

@ -1,19 +1,19 @@
import { invariant } from "../excalidraw/utils";
import { point } from "./point";
import { segment, segmentDistanceToPoint } from "./segment";
import type { GenericPoint, Rectangle } from "./types";
export function rectangle<P extends GenericPoint>(
a: P,
b: P,
c: P,
d: P,
topLeft: P,
bottomRight: P,
): Rectangle<P> {
return [a, b, c, d] as Rectangle<P>;
return [topLeft, bottomRight] as Rectangle<P>;
}
export function rectangleFromQuad<P extends GenericPoint>(
quad: [a: P, b: P, c: P, d: P],
export function rectangleFromPair<P extends GenericPoint>(
pair: [a: P, b: P],
): Rectangle<P> {
return quad as Rectangle<P>;
return pair as Rectangle<P>;
}
export function rectangleFromArray<P extends GenericPoint>(
@ -26,3 +26,17 @@ export function rectangleFromArray<P extends GenericPoint>(
return pointArray as Rectangle<P>;
}
export function rectangleDistanceFromPoint<Point extends GenericPoint>(
r: Rectangle<Point>,
p: Point,
): number {
const sides = [
segment(point(r[0][0], r[0][1]), point(r[1][0], r[0][1])),
segment(point(r[1][0], r[0][1]), point(r[1][0], r[1][1])),
segment(point(r[1][0], r[1][1]), point(r[0][0], r[1][1])),
segment(point(r[0][0], r[1][1]), point(r[0][0], r[0][1])),
];
return Math.min(...sides.map((side) => segmentDistanceToPoint(p, side)));
}

View file

@ -1,4 +1,3 @@
import { invariant } from "../excalidraw/utils";
import {
isPoint,
pointCenter,
@ -23,10 +22,9 @@ import {
* @returns The line segment delineated by the points
*/
export function segment<P extends GenericPoint>(a: P, b: P): Segment<P> {
invariant(
!pointsEqual(a, b),
"The start and end points of the segment cannot match",
);
if (pointsEqual(a, b)) {
console.warn("The start and end points of the segment cannot match");
}
return [a, b] as Segment<P>;
}

View file

@ -88,7 +88,7 @@ export type Triangle<P extends GenericPoint> = [a: P, b: P, c: P] & {
/**
* A rectangular shape represented by 4 points at its corners
*/
export type Rectangle<P extends GenericPoint> = [a: P, b: P, c: P, d: P] & {
export type Rectangle<P extends GenericPoint> = [a: P, b: P] & {
_brand: "excalimath__rectangle";
};