This commit is contained in:
2025-12-01 17:42:42 +01:00
commit e9b0e9d856
26 changed files with 3438 additions and 0 deletions

81
src/lib/geometry.ts Normal file
View File

@@ -0,0 +1,81 @@
export interface Point {
x: number;
y: number;
}
export function calculateCenterOffset(
corner: string,
deltaWidth: number,
deltaHeight: number,
rotation: number
): Point {
const rad = (rotation * Math.PI) / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
let localDx = 0;
let localDy = 0;
if (corner.includes('w')) localDx = -deltaWidth / 2;
else if (corner.includes('e')) localDx = deltaWidth / 2;
if (corner.includes('n')) localDy = -deltaHeight / 2;
else if (corner.includes('s')) localDy = deltaHeight / 2;
return {
x: localDx * cos - localDy * sin,
y: localDx * sin + localDy * cos
};
}
export function constrainToAspectRatio(
newWidth: number,
newHeight: number,
aspectRatio: number
): { width: number; height: number } {
const newRatio = newWidth / newHeight;
if (newRatio > aspectRatio) {
return { width: newHeight * aspectRatio, height: newHeight };
} else {
return { width: newWidth, height: newWidth / aspectRatio };
}
}
export function detectRotationCorner(
localX: number,
localY: number,
halfWidth: number,
halfHeight: number,
zoneRadius: number
): string | null {
const corners: Record<string, Point> = {
nw: { x: -halfWidth, y: -halfHeight },
ne: { x: halfWidth, y: -halfHeight },
sw: { x: -halfWidth, y: halfHeight },
se: { x: halfWidth, y: halfHeight }
};
const isInsideBounds =
localX >= -halfWidth &&
localX <= halfWidth &&
localY >= -halfHeight &&
localY <= halfHeight;
if (isInsideBounds) return null;
for (const [name, corner] of Object.entries(corners)) {
const dx = localX - corner.x;
const dy = localY - corner.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist > zoneRadius || dist < 3) continue;
const isOutwardX = (name.includes('w') && dx < 0) || (name.includes('e') && dx > 0);
const isOutwardY = (name.includes('n') && dy < 0) || (name.includes('s') && dy > 0);
if (isOutwardX || isOutwardY) return name;
}
return null;
}