Attempt at optimizing focus point calc

This commit is contained in:
Mark Tolmacs 2024-09-27 20:27:10 +02:00
parent 5cbd6e63a0
commit 34ec751501
No known key found for this signature in database
3 changed files with 63 additions and 24 deletions

View file

@ -73,6 +73,11 @@ import {
pointDistanceSq,
clamp,
radians,
vectorScale,
pointFromVector,
vectorRotate,
vectorNormalize,
pointDistance,
} from "../../math";
import { segmentIntersectRectangleElement } from "../../utils/geometry/shape";
import { distanceToBindableElement } from "./distance";
@ -1425,7 +1430,7 @@ const determineFocusPoint = (
GAPoint.from(adjecentPoint),
);
const reverseRelateToCenter = GA.reverse(relateToCenter);
let point;
let p: GA.Point;
switch (element.type) {
case "rectangle":
case "image":
@ -1435,14 +1440,18 @@ const determineFocusPoint = (
case "embeddable":
case "frame":
case "magicframe":
point = findFocusPointForRectangulars(element, focus, adjecentPointRel);
p = findFocusPointForRectanguloidElement(
element,
focus,
adjecentPointRel,
);
break;
case "ellipse":
point = findFocusPointForEllipse(element, focus, adjecentPointRel);
p = findFocusPointForEllipse(element, focus, adjecentPointRel);
break;
}
return pointFromPair(
GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, point)),
GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, p)),
);
};
@ -1692,7 +1701,7 @@ const findFocusPointForEllipse = (
return GA.point(x, (-m * x - 1) / n);
};
const findFocusPointForRectangulars = (
const findFocusPointForRectanguloidElement = (
element:
| ExcalidrawRectangleElement
| ExcalidrawImageElement
@ -1705,23 +1714,34 @@ const findFocusPointForRectangulars = (
relativeDistance: number,
// The point for which we're trying to find the focus point, relative
// to the element center.
point: GA.Point,
gaPoint: GA.Point,
): GA.Point => {
const relativeDistanceAbs = Math.abs(relativeDistance);
const orientation = Math.sign(relativeDistance);
const corners = getCorners(element, relativeDistanceAbs);
const relP = pointFromPair<GlobalPoint>(GAPoint.toTuple(gaPoint));
const center = point<GlobalPoint>(
element.x + element.width / 2,
element.y + element.height / 2,
);
const p = point<GlobalPoint>(center[0] + relP[0], center[1] + relP[1]);
const ret = pointFromVector(
vectorScale(
vectorRotate(
vectorNormalize(vectorFromPoint(p, center)),
radians(Math.PI / 2),
),
Math.sign(relativeDistance) *
Math.min(
pointDistance(point<GlobalPoint>(element.x, element.y), center) *
Math.abs(relativeDistance),
element.width / 2,
element.height / 2,
),
),
center,
);
let maxDistance = 0;
let tangentPoint: null | GA.Point = null;
corners.forEach((corner) => {
const distance = orientation * GALine.through(point, corner)[1];
if (distance > maxDistance) {
maxDistance = distance;
tangentPoint = corner;
}
});
return tangentPoint!;
return GA.point(ret[0] - center[0], ret[1] - center[1]);
};
export const bindingProperties: Set<BindableProp | BindingProp> = new Set([
"boundElements",
"frameId",

View file

@ -46,8 +46,11 @@ export function pointFromPair<Point extends GenericPoint>(
* @param v The vector to convert
* @returns The point the vector points at with origin 0,0
*/
export function pointFromVector<P extends GenericPoint>(v: Vector): P {
return v as unknown as P;
export function pointFromVector<P extends GenericPoint>(
v: Vector,
offset: P = point(0, 0),
): P {
return point<P>(offset[0] + v[0], offset[1] + v[1]);
}
/**
@ -96,9 +99,12 @@ export function pointRotateRads<Point extends GenericPoint>(
[cx, cy]: Point,
angle: Radians,
): Point {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return point(
(x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
(x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy,
(x - cx) * cos - (y - cy) * sin + cx,
(x - cx) * sin + (y - cy) * cos + cy,
);
}

View file

@ -1,4 +1,4 @@
import type { GenericPoint, Vector } from "./types";
import type { GenericPoint, Radians, Vector } from "./types";
/**
* Create a vector from the x and y coordiante elements.
@ -139,3 +139,16 @@ export const vectorNormalize = (v: Vector): Vector => {
return vector(v[0] / m, v[1] / m);
};
/**
* Rotate a vector by the given radians
* @param v Target vector
* @param a Angle to rotate in radians
* @returns The rotated vector
*/
export const vectorRotate = (v: Vector, a: Radians): Vector => {
const cos = Math.cos(a);
const sin = Math.sin(a);
return vector(v[0] * cos - v[1] * sin, v[0] * sin + v[1] * cos);
};