点在多边形内判断的一个简洁方法
在一个开源脚本了偶然看到这么几行,如下:
function Polygon_contains(point)
{
var i, j, status=false;
for (i=0, j=this.numpoints-1; i<this.numpoints; j=i++) {
if ((((this.points[i].y<=point.y) && (point.y<this.points[j].y)) || ((this.points[j].y<=point.y) && (point.y<this.points[i].y))) && (point.x < (this.points[j].x - this.points[i].x) * (point.y - this.points[i].y) / (this.points[j].y - this.points[i].y) + this.points[i].x))
status = !status;
}
return status;
}
仔细分析了一下,虽然简单,可道理和铅垂线法差不多,但是省去了求交,统计交点个数等过程。
主要逻辑都在那个if条件语句
(((this.points[i].y<=point.y) && (point.y<this.points[j].y)) || ((this.points[j].y<=point.y) && (point.y<this.points[i].y))) 就是判断点point在,过 i 点的水平线和过 j 点的水平线之间(临界条件是一端闭合一端开)
(point.x < (this.points[j].x - this.points[i].x) * (point.y - this.points[i].y) / (this.points[j].y - this.points[i].y) + this.points[i].x) 是判断点点point在线段 ij 的坐标,注意这里的线段 ij 不分方向。我们应该添加少许代码以适应 ij 竖直的情况,而且好像根据斜率的正负,好像要分情况考虑。写一个函数判断点是否在线段左侧:
private bool PointLeft(CPoint p, CPoint i, CPoint j)
{
if (i.X == j.X)
{
return p.X < i.X;
}
double deltY = j.Y - i.Y;
double deltX = j.X - i.X;
if ((deltX >= 0 & deltY > 0) || (deltX <= 0 && deltY < 0))
{
return p.Y > deltY / deltX * (p.X - i.X) + i.Y;
}
else
{
return p.Y < deltY / deltX * (p.X - i.X) + i.Y;
}
}
刚开始假设点在外面,没符合这个条件,里外就反一下,最后status为真就在多边形内。
经过检验,对带环的多边形、逆、顺多边形和凸凹多边形都有效。
添加少许代码就可检验点是否在边上或和某个节点重合。