* @description 射线法判断点是否在多边形内部 * @param {Object} p 待判断的点,格式:{ x: X 坐标, y: Y 坐标 } * @param {Array} poly 多边形顶点,数组成员的格式同 p * @return {String} 点 p 和多边形 poly 的几何关系 */function rayCasting(p, poly) { var px = p.x, py = p.y, flag = false for(var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) { var sx = poly[i].x, sy = poly[i].y, tx = poly[j].x, ty = poly[j].y // 点与多边形顶点重合 if((sx === px && sy === py) || (tx === px && ty === py)) { return 'on' // 判断线段两端点是否在射线两侧 if((sy < py && ty >= py) || (sy >= py && ty < py)) { // 线段上与射线 Y 坐标相同的点的 X 坐标 var x = sx + (py - sy) * (tx - sx) / (ty - sy) // 点在多边形的边上 if(x === px) { return 'on' // 射线穿过多边形的边界 if(x > px) { flag = !flag // 射线穿过多边形边界的次数为奇数时点在多边形内 return flag ? 'in' : 'out'} 除了射线法还有很多其他的方法,下面再介绍一种 回转数法 。 平面中的闭合曲线关于一个点的 回转数 (又叫卷绕数),代表了曲线绕过该点的总次数。下面这张图动态演示了回转数的概念:图中红色曲线关于点(人所在位置)的回转数为 2。 回转数是拓扑学中的一个基本概念,具有很重要的性质和用途。本文并不打算在这一点上展开论述,这需要具备相当的数学知识,否则会非常乏味和难以理解。我们暂时只需要记住回转数的一个特性就行了: 当回转数为 0 时,点在闭合曲线外部 (回转数大于 0 时所代表的含义,大家可以自己想一想,还是很有趣的)。 对于给定的点和多边形,回转数应该怎么计算呢? * @description 回转数法判断点是否在多边形内部 * @param {Object} p 待判断的点,格式:{ x: X 坐标, y: Y 坐标 } * @param {Array} poly 多边形顶点,数组成员的格式同 p * @return {String} 点 p 和多边形 poly 的几何关系 */function windingNumber(p, poly) { var px = p.x, py = p.y, sum = 0 for(var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) { var sx = poly[i].x, sy = poly[i].y, tx = poly[j].x, ty = poly[j].y // 点与多边形顶点重合或在多边形的边上 if((sx - px) * (px - tx) >= 0 && (sy - py) * (py - ty) >= 0 && (px - sx) * (ty - sy) === (py - sy) * (tx - sx)) { return 'on' // 点与相邻顶点连线的夹角 var angle = Math.atan2(sy - py, sx - px) - Math.atan2(ty - py, tx - px) // 确保夹角不超出取值范围(-π 到 π) if(angle >= Math.PI) { angle = angle - Math.PI * 2 } else if(angle <= -Math.PI) { angle = angle + Math.PI * 2 sum += angle // 计算回转数并判断点和多边形的几何关系 return Math.round(sum / Math.PI) === 0 ? 'out' : 'in'} 也有人问到像下面这种复杂多边形有没有办法?答案是肯定的。至于为什么,就留给大家思考吧。