// 多边形的射线检测,参考:https://blog.csdn.net/WilliamSun0122/article/details/77994526 const tolerance = 1e-6; // 三态函数,判断两个double在eps精度下的大小关系 function dcmp(x: number) { if (Math.abs(x) < tolerance) { return 0; } return x < 0 ? -1 : 1; } // 判断点Q是否在p1和p2的线段上 function onSegment(p1: number[], p2: number[], q: number[]) { if ( (q[0] - p1[0]) * (p2[1] - p1[1]) === (p2[0] - p1[0]) * (q[1] - p1[1]) && Math.min(p1[0], p2[0]) <= q[0] && q[0] <= Math.max(p1[0], p2[0]) && Math.min(p1[1], p2[1]) <= q[1] && q[1] <= Math.max(p1[1], p2[1]) ) { return true; } return false; } // 判断点P在多边形内-射线法 export function isPointInPolygon(points: number[][], x: number, y: number) { let isHit = false; const n = points.length; if (n <= 2) { // svg 中点小于 3 个时,不显示,也无法被拾取 return false; } for (let i = 0; i < n; i++) { const p1 = points[i]; const p2 = points[(i + 1) % n]; if (onSegment(p1, p2, [x, y])) { // 点在多边形一条边上 return true; } // 前一个判断min(p1[1],p2[1]) 0 !== dcmp(p2[1] - y) > 0 && dcmp(x - ((y - p1[1]) * (p1[0] - p2[0])) / (p1[1] - p2[1]) - p1[0]) < 0 ) { isHit = !isHit; } } return isHit; }