import { contourToSvgPath } from './contour'; /** * 卡片切割路径 */ export interface CardPath { pageIndex: number; cardIndex: number; points: [number, number][]; centerX: number; centerY: number; pathD: string; startPoint: [number, number]; endPoint: [number, number]; } /** * 生成空走路径(抬刀移动路径) * @param cardPaths 卡片切割路径 * @param a4Height A4 纸高度(用于坐标转换) */ export function generateTravelPaths( cardPaths: CardPath[], a4Height: number ): [number, number][][] { const travelPaths: [number, number][][] = []; // 起点:左上角 (0, a4Height) - 注意 SVG 坐标 Y 向下,plotter 坐标 Y 向上 const startPoint: [number, number] = [0, a4Height]; if (cardPaths.length === 0) { return travelPaths; } // 从起点到第一张卡的起点 travelPaths.push([startPoint, cardPaths[0].startPoint]); // 卡片之间的移动 for (let i = 0; i < cardPaths.length - 1; i++) { const currentEnd = cardPaths[i].endPoint; const nextStart = cardPaths[i + 1].startPoint; travelPaths.push([currentEnd, nextStart]); } // 从最后一张卡返回起点 travelPaths.push([cardPaths[cardPaths.length - 1].endPoint, startPoint]); return travelPaths; } /** * 将旅行路径转换为 SVG path 命令 */ export function travelPathsToSvg(travelPaths: [number, number][][]): string { return travelPaths.map(path => contourToSvgPath(path, false)).join(' '); } /** * 计算所有卡片轮廓的总边界框 */ export function calculateTotalBounds(cardPaths: CardPath[]): { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number; } { if (cardPaths.length === 0) { return { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 0, height: 0 }; } let minX = Infinity; let minY = Infinity; let maxX = -Infinity; let maxY = -Infinity; for (const cardPath of cardPaths) { for (const [x, y] of cardPath.points) { minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x); maxY = Math.max(maxY, y); } } return { minX, minY, maxX, maxY, width: maxX - minX, height: maxY - minY }; }