Fix diamond distance

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2024-09-28 09:09:14 +02:00
parent 34ec751501
commit c41486abd1
No known key found for this signature in database
4 changed files with 74 additions and 53 deletions

View file

@ -12,7 +12,7 @@ import {
segment, segment,
segmentDistanceToPoint, segmentDistanceToPoint,
} from "../../math"; } from "../../math";
import { getCornerRadius } from "../shapes"; import { getCornerRadius, getDiamondPoints } from "../shapes";
import type { import type {
ExcalidrawBindableElement, ExcalidrawBindableElement,
ExcalidrawDiamondElement, ExcalidrawDiamondElement,
@ -128,18 +128,19 @@ export const distanceToRectangleElement = (
*/ */
const createDiamondSide = ( const createDiamondSide = (
s: Segment<GlobalPoint>, s: Segment<GlobalPoint>,
r: number, startRadius: number,
endRadius: number,
): Segment<GlobalPoint> => { ): Segment<GlobalPoint> => {
if (r === 0) { const a = ellipseSegmentInterceptPoints(
return s; ellipse(s[0], startRadius, startRadius),
} s,
)[0];
const b = ellipseSegmentInterceptPoints(
ellipse(s[1], endRadius, endRadius),
s,
)[0];
const t = (4 * r) / Math.sqrt(2); return segment(a, b);
return segment(
ellipseSegmentInterceptPoints(ellipse(s[0], t, t), s)[0],
ellipseSegmentInterceptPoints(ellipse(s[1], t, t), s)[0],
);
}; };
/** /**
@ -154,7 +155,10 @@ const createDiamondSide = (
* @returns * @returns
*/ */
const createDiamondArc = (start: GlobalPoint, end: GlobalPoint, r: number) => { const createDiamondArc = (start: GlobalPoint, end: GlobalPoint, r: number) => {
const c = point((start[0] + end[0]) / 2, start[1]); const c = point<GlobalPoint>(
(start[0] + end[0]) / 2,
(start[1] + end[1]) / 2,
);
return arc( return arc(
c, c,
@ -176,41 +180,58 @@ export const distanceToDiamondElement = (
element: ExcalidrawDiamondElement, element: ExcalidrawDiamondElement,
p: GlobalPoint, p: GlobalPoint,
): number => { ): number => {
const center = point<GlobalPoint>( const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
element.x + element.width / 2, getDiamondPoints(element);
element.y + element.height / 2, const center = point<GlobalPoint>((topX + bottomX) / 2, (topY + bottomY) / 2);
); const verticalRadius = getCornerRadius(Math.abs(topX - leftX), element);
const roundness = getCornerRadius( const horizontalRadius = getCornerRadius(Math.abs(rightY - topY), element);
Math.min(element.width, element.height),
element,
);
// Rotate the point to the inverse direction to simulate the rotated diamond // Rotate the point to the inverse direction to simulate the rotated diamond
// points. It's all the same distance-wise. // points. It's all the same distance-wise.
const rotatedPoint = pointRotateRads(p, center, radians(-element.angle)); const rotatedPoint = pointRotateRads(p, center, radians(-element.angle));
const [top, right, bottom, left]: GlobalPoint[] = [ const [top, right, bottom, left]: GlobalPoint[] = [
point(element.x + element.width / 2, element.y), point(element.x + topX, element.y + topY),
point(element.x + element.width, element.y + element.height / 2), point(element.x + rightX, element.y + rightY),
point(element.x + element.width / 2, element.y + element.height), point(element.x + bottomX, element.y + bottomY),
point(element.x, element.y + element.height / 2), point(element.x + leftX, element.y + leftY),
]; ];
const topRight = createDiamondSide(segment(top, right), roundness);
const bottomRight = createDiamondSide(segment(right, bottom), roundness); const topRight = createDiamondSide(
const bottomLeft = createDiamondSide(segment(bottom, left), roundness); segment(top, right),
const topLeft = createDiamondSide(segment(left, top), roundness); verticalRadius,
horizontalRadius,
);
const bottomRight = createDiamondSide(
segment(bottom, right),
verticalRadius,
horizontalRadius,
);
const bottomLeft = createDiamondSide(
segment(bottom, left),
verticalRadius,
horizontalRadius,
);
const topLeft = createDiamondSide(
segment(top, left),
verticalRadius,
horizontalRadius,
);
const arcs = element.roundness
? [
createDiamondArc(topLeft[0], topRight[0], verticalRadius), // TOP
createDiamondArc(topRight[1], bottomRight[1], horizontalRadius), // RIGHT
createDiamondArc(bottomRight[0], bottomLeft[0], verticalRadius), // BOTTOM
createDiamondArc(bottomLeft[1], topLeft[1], horizontalRadius), // LEFT
]
: [];
return Math.min( return Math.min(
...[ ...[
...[topRight, bottomRight, bottomLeft, topLeft].map((s) => ...[topRight, bottomRight, bottomLeft, topLeft].map((s) =>
segmentDistanceToPoint(rotatedPoint, s), segmentDistanceToPoint(rotatedPoint, s),
), ),
...(roundness > 0 ...arcs.map((a) => arcDistanceFromPoint(a, rotatedPoint)),
? [
createDiamondArc(topLeft[1], topRight[0], roundness),
createDiamondArc(topRight[1], bottomRight[0], roundness),
createDiamondArc(bottomRight[1], bottomLeft[0], roundness),
createDiamondArc(bottomLeft[1], topLeft[0], roundness),
].map((a) => arcDistanceFromPoint(a, rotatedPoint))
: []),
], ],
); );
}; };

View file

@ -21,7 +21,6 @@ export {
getCommonBounds, getCommonBounds,
getClosestElementBounds, getClosestElementBounds,
} from "./bounds"; } from "./bounds";
export { getDiamondPoints } from "../scene/Shape";
export { export {
OMIT_SIDES_FOR_MULTIPLE_ELEMENTS, OMIT_SIDES_FOR_MULTIPLE_ELEMENTS,

View file

@ -30,7 +30,7 @@ import {
type GlobalPoint, type GlobalPoint,
type LocalPoint, type LocalPoint,
} from "../../math"; } from "../../math";
import { getCornerRadius } from "../shapes"; import { getCornerRadius, getDiamondPoints } from "../shapes";
const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth]; const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth];
@ -278,21 +278,6 @@ const getArrowheadShapes = (
} }
}; };
export const getDiamondPoints = (element: ExcalidrawElement) => {
// Here we add +1 to avoid these numbers to be 0
// otherwise rough.js will throw an error complaining about it
const topX = Math.floor(element.width / 2) + 1;
const topY = 0;
const rightX = element.width;
const rightY = Math.floor(element.height / 2) + 1;
const bottomX = topX;
const bottomY = element.height;
const leftX = 0;
const leftY = rightY;
return [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY];
};
/** /**
* Generates the roughjs shape for given element. * Generates the roughjs shape for given element.
* *

View file

@ -42,6 +42,7 @@ import { getBoundTextElement } from "./element/textElement";
import type { import type {
Bounds, Bounds,
ElementsMap, ElementsMap,
ExcalidrawDiamondElement,
ExcalidrawElement, ExcalidrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
NonDeleted, NonDeleted,
@ -472,3 +473,18 @@ export const getCornerRadius = (x: number, element: ExcalidrawElement) => {
return 0; return 0;
}; };
export const getDiamondPoints = (element: ExcalidrawDiamondElement) => {
// Here we add +1 to avoid these numbers to be 0
// otherwise rough.js will throw an error complaining about it
const topX = Math.floor(element.width / 2) + 1;
const topY = 0;
const rightX = element.width;
const rightY = Math.floor(element.height / 2) + 1;
const bottomX = topX;
const bottomY = element.height;
const leftX = 0;
const leftY = rightY;
return [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY];
};