/** * PositionPresets Component * * Provides a 3x3 grid of buttons to quickly position the pattern * at predefined locations within the hoop (corners, edge centers, and center) */ import type { MachineInfo } from "../../types/machine"; import type { PesPatternData } from "../../formats/import/pesImporter"; import { calculatePatternCenter } from "./patternCanvasHelpers"; import { calculateRotatedBounds } from "../../utils/rotationUtils"; export type PositionPreset = | "top-left" | "top-center" | "top-right" | "center-left" | "center" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right"; interface PositionPresetsProps { pesData: PesPatternData; patternRotation: number; machineInfo: MachineInfo; onPositionSelect: (offset: { x: number; y: number }) => void; disabled: boolean; } /** * Calculate the offset needed to position the pattern at a given preset location. * * The offset represents the pattern center's position in world coordinates. * When offset is {0,0}, the pattern center is at the hoop center. */ function calculatePresetOffset( preset: PositionPreset, pesData: PesPatternData, patternRotation: number, machineInfo: MachineInfo, ): { x: number; y: number } { // Use rotated bounds if rotation is applied const bounds = patternRotation !== 0 ? calculateRotatedBounds(pesData.bounds, patternRotation) : pesData.bounds; const center = calculatePatternCenter(bounds); const hoopHalfW = machineInfo.maxWidth / 2; const hoopHalfH = machineInfo.maxHeight / 2; // Distance from pattern center to each edge const leftHalf = center.x - bounds.minX; const rightHalf = bounds.maxX - center.x; const topHalf = center.y - bounds.minY; const bottomHalf = bounds.maxY - center.y; const xPositions = { left: -hoopHalfW + leftHalf, center: 0, right: hoopHalfW - rightHalf, }; const yPositions = { top: -hoopHalfH + topHalf, center: 0, bottom: hoopHalfH - bottomHalf, }; switch (preset) { case "top-left": return { x: xPositions.left, y: yPositions.top }; case "top-center": return { x: xPositions.center, y: yPositions.top }; case "top-right": return { x: xPositions.right, y: yPositions.top }; case "center-left": return { x: xPositions.left, y: yPositions.center }; case "center": return { x: xPositions.center, y: yPositions.center }; case "center-right": return { x: xPositions.right, y: yPositions.center }; case "bottom-left": return { x: xPositions.left, y: yPositions.bottom }; case "bottom-center": return { x: xPositions.center, y: yPositions.bottom }; case "bottom-right": return { x: xPositions.right, y: yPositions.bottom }; } } const presetGrid: { preset: PositionPreset; label: string }[][] = [ [ { preset: "top-left", label: "Top Left" }, { preset: "top-center", label: "Top Center" }, { preset: "top-right", label: "Top Right" }, ], [ { preset: "center-left", label: "Center Left" }, { preset: "center", label: "Center" }, { preset: "center-right", label: "Center Right" }, ], [ { preset: "bottom-left", label: "Bottom Left" }, { preset: "bottom-center", label: "Bottom Center" }, { preset: "bottom-right", label: "Bottom Right" }, ], ]; export function PositionPresets({ pesData, patternRotation, machineInfo, onPositionSelect, disabled, }: PositionPresetsProps) { const handleClick = (preset: PositionPreset) => { const offset = calculatePresetOffset( preset, pesData, patternRotation, machineInfo, ); onPositionSelect(offset); }; return (