/** * 检查两条线段是否相交 * @param {Array} a1 线段1起点 [x, y] * @param {Array} a2 线段1终点 [x, y] * @param {Array} b1 线段2起点 [x, y] * @param {Array} b2 线段2终点 [x, y] * @returns {boolean} 是否相交 */ function doLinesIntersect(a1, a2, b1, b2) { // 计算向量叉积 const ccw = (p1, p2, p3) => (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]); // 检查线段 a1a2 和 b1b2 是否跨立 const ccw1 = ccw(a1, a2, b1); const ccw2 = ccw(a1, a2, b2); const ccw3 = ccw(b1, b2, a1); const ccw4 = ccw(b1, b2, a2); // 跨立实验 + 共线检查 if ( (ccw1 * ccw2 < 0 && ccw3 * ccw4 < 0) || // 一般情况:跨立 (ccw1 === 0 && isPointOnSegment(a1, a2, b1)) || // 共线情况 (ccw2 === 0 && isPointOnSegment(a1, a2, b2)) || (ccw3 === 0 && isPointOnSegment(b1, b2, a1)) || (ccw4 === 0 && isPointOnSegment(b1, b2, a2)) ) { //console.log("doLinesIntersect ccw", ccw1, ccw2, ccw3, ccw4) return true; } return false; } /** * 检查点是否在线段上(共线时使用) */ function isPointOnSegment(p1, p2, p) { const minX = Math.min(p1[0], p2[0]); const maxX = Math.max(p1[0], p2[0]); const minY = Math.min(p1[1], p2[1]); const maxY = Math.max(p1[1], p2[1]); return ( p[0] >= minX && p[0] <= maxX && p[1] >= minY && p[1] <= maxY ); } /** * 检查路径是否自相交 * @param {Array} points 路径点数组 [[x1, y1], [x2, y2], ...] * @returns {boolean} 是否自相交 */ export function hasSelfIntersection(points) { const len = points.length -1 if (len < 3) return false; // 至少 4 个点才可能自相交 for (let i = 0; i < len; i++) { //console.log("point", i, points[i]) for (let j = i + 2; j < len; j++) { // 跳过相邻线段(相邻线段只会在端点相交,不算自相交) //console.log("point2", j, points[j]) if (i === (j + 1) % len|| j === (i + 1) % len) continue; const a1 = points[i]; const a2 = points[i + 1]; const b1 = points[j]; const b2 = points[j + 1]; // console.log("doLinesIntersect", a1, a2, b1, b2) if (doLinesIntersect(a1, a2, b1, b2)) { return true; } } } return false; }