SOURCE

/**
 * 点对象
 * @typedef {Object} Point
 * @property {number} x - X坐标
 * @property {number} y - Y坐标
 */

/**
 * 生成5条倾斜模型采集航线(0°, 45°, 90°, 135°, 自由航线)
 * @param {Point[]} polygon - 多边形顶点数组(顺时针或逆时针顺序)
 * @param {number} spacing - 航线间隔距离
 * @param {number} [overlap=0.3] - 航线重叠率(0-1),默认30%
 * @returns {Object} 包含5条航线的对象
 */
function generateFiveTiltedFlightPaths(polygon, spacing, overlap = 0.3) {
    // 1. 生成0°航线(正北方向)
    const path0 = generateTiltedFlightPath(polygon, spacing, 0, overlap);
    
    // 2. 生成45°航线
    const path45 = generateTiltedFlightPath(polygon, spacing, 45, overlap);
    
    // 3. 生成90°航线(正东方向)
    const path90 = generateTiltedFlightPath(polygon, spacing, 90, overlap);
    
    // 4. 生成135°航线
    const path135 = generateTiltedFlightPath(polygon, spacing, 135, overlap);
    
    // 5. 生成自由航线(沿多边形最长边方向)
    const freeAngle = calculateOptimalAngle(polygon);
    const pathFree = generateTiltedFlightPath(polygon, spacing, freeAngle, overlap);
    
    return {
        path0: { angle: 0, points: path0 },
        path45: { angle: 45, points: path45 },
        path90: { angle: 90, points: path90 },
        path135: { angle: 135, points: path135 },
        pathFree: { angle: freeAngle, points: pathFree }
    };
}

/**
 * 生成倾斜航线
 * @param {Point[]} polygon - 多边形顶点数组
 * @param {number} spacing - 航线间隔
 * @param {number} angle - 倾斜角度(度数)
 * @param {number} overlap - 重叠率
 * @returns {Point[]} 航线点数组
 */
function generateTiltedFlightPath(polygon, spacing, angle, overlap) {
    const radians = angle * Math.PI / 180;
    const cosAngle = Math.cos(radians);
    const sinAngle = Math.sin(radians);
    
    // 计算多边形旋转后的边界
    const bounds = getRotatedBounds(polygon, radians);
    
    // 计算有效间距(考虑重叠)
    const effectiveSpacing = spacing * (1 - overlap);
    
    // 生成扫描线位置
    const scanLines = [];
    for (let y = bounds.minY; y <= bounds.maxY; y += effectiveSpacing) {
        scanLines.push(y);
    }
    
    const flightPath = [];
    
    // 处理每条扫描线
    scanLines.forEach(y => {
        // 获取多边形与当前扫描线的交点
        const intersections = getPolygonIntersections(polygon, y, radians);
        
        // 交点按x坐标排序
        intersections.sort((a, b) => a.x - b.x);
        
        // 在每对交点之间生成航点
        for (let i = 0; i < intersections.length; i += 2) {
            if (i + 1 < intersections.length) {
                const start = intersections[i];
                const end = intersections[i + 1];
                
                // 计算两点间距离
                const dx = end.x - start.x;
                const dy = end.y - start.y;
                const length = Math.sqrt(dx * dx + dy * dy);
                
                // 计算需要生成的航点数量
                const pointCount = Math.ceil(length / spacing);
                
                // 生成航点
                for (let j = 0; j <= pointCount; j++) {
                    const t = j / pointCount;
                    const point = {
                        x: start.x + t * dx,
                        y: start.y + t * dy
                    };
                    flightPath.push(point);
                }
            }
        }
    });
    
    return flightPath;
}

/**
 * 计算多边形旋转后的边界
 * @param {Point[]} polygon - 多边形顶点
 * @param {number} radians - 旋转弧度
 * @returns {Object} 边界 {minX, maxX, minY, maxY}
 */
function getRotatedBounds(polygon, radians) {
    const cosAngle = Math.cos(radians);
    const sinAngle = Math.sin(radians);
    
    let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
    
    polygon.forEach(p => {
        // 旋转点坐标
        const x = p.x * cosAngle + p.y * sinAngle;
        const y = -p.x * sinAngle + p.y * cosAngle;
        
        minX = Math.min(minX, x);
        maxX = Math.max(maxX, x);
        minY = Math.min(minY, y);
        maxY = Math.max(maxY, y);
    });
    
    return { minX, maxX, minY, maxY };
}

/**
 * 获取多边形与扫描线的交点
 * @param {Point[]} polygon - 多边形顶点
 * @param {number} y - 扫描线y坐标(旋转后坐标系)
 * @param {number} radians - 旋转弧度
 * @returns {Point[]} 交点数组
 */
function getPolygonIntersections(polygon, y, radians) {
    const cosAngle = Math.cos(radians);
    const sinAngle = Math.sin(radians);
    
    // 旋转多边形到水平位置
    const rotatedPolygon = polygon.map(p => ({
        x: p.x * cosAngle + p.y * sinAngle,
        y: -p.x * sinAngle + p.y * cosAngle
    }));
    
    const intersections = [];
    
    // 检查每条边与扫描线的交点
    for (let i = 0; i < rotatedPolygon.length; i++) {
        const p1 = rotatedPolygon[i];
        const p2 = rotatedPolygon[(i + 1) % rotatedPolygon.length];
        
        // 忽略水平边
        if (Math.abs(p1.y - p2.y) < 1e-6) continue;
        
        // 检查边是否跨越扫描线
        if ((p1.y <= y && p2.y > y) || (p2.y <= y && p1.y > y)) {
            // 计算交点x坐标
            const t = (y - p1.y) / (p2.y - p1.y);
            const x = p1.x + t * (p2.x - p1.x);
            
            // 旋转回原始坐标系
            intersections.push({
                x: x * cosAngle - y * sinAngle,
                y: x * sinAngle + y * cosAngle
            });
        }
    }
    
    return intersections;
}

/**
 * 计算最优自由航线角度(沿多边形最长边方向)
 * @param {Point[]} polygon - 多边形顶点
 * @returns {number} 最优角度(度数)
 */
function calculateOptimalAngle(polygon) {
    let maxLength = 0;
    let optimalAngle = 0;
    
    // 检查每条边
    for (let i = 0; i < polygon.length; i++) {
        const p1 = polygon[i];
        const p2 = polygon[(i + 1) % polygon.length];
        
        const dx = p2.x - p1.x;
        const dy = p2.y - p1.y;
        const length = Math.sqrt(dx * dx + dy * dy);
        
        if (length > maxLength) {
            maxLength = length;
            // 计算边与x轴的夹角(度数)
            optimalAngle = Math.atan2(dy, dx) * 180 / Math.PI;
        }
    }
    
    return optimalAngle;
}

// 示例用法
const polygon = [
    { x: 0, y: 0 },
    { x: 100, y: 0 },
    { x: 120, y: 50 },
    { x: 80, y: 80 },
    { x: 20, y: 60 }
];

const spacing = 20;
const overlap = 0.2; // 20%重叠

const flightPaths = generateFiveTiltedFlightPaths(polygon, spacing, overlap);
console.log("航线点数:", flightPaths);
// console.log("0°航线点数:", flightPaths.path0.points.length,flightPaths.path0.points);
// console.log("45°航线点数:", flightPaths.path45.points.length,flightPaths.path45.points);
// console.log("90°航线点数:", flightPaths.path90.points.length,flightPaths.path90.points);
// console.log("135°航线点数:", flightPaths.path135.points.length,flightPaths.path135.points);
// console.log("自由航线角度:", flightPaths.pathFree.angle, "° 点数:", flightPaths.pathFree.points.length,flightPaths.pathFree.points);

// 可视化示例(假设有绘图函数)
// drawPolygon(polygon);
// drawFlightPath(flightPaths.path0.points, 'red');
// drawFlightPath(flightPaths.path45.points, 'blue');
// drawFlightPath(flightPaths.path90.points, 'green');
// drawFlightPath(flightPaths.path135.points, 'purple');
// drawFlightPath(flightPaths.pathFree.points, 'orange');
console 命令行工具 X clear

                    
>
console