点在多边形内判断的一个简洁方法

在一个开源脚本了偶然看到这么几行,如下:

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为真就在多边形内。

经过检验,对带环的多边形、逆、顺多边形和凸凹多边形都有效。

添加少许代码就可检验点是否在边上或和某个节点重合。

posted @ 2008-12-30 20:22  xiangeboy  阅读(1936)  评论(1)    收藏  举报