cuiqian2004
2025-09-12 d87c256a957a6a5c3b40eaf9c52ec68f2fc22c97
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
 * 检查两条线段是否相交
 * @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;
}