帮助这个算法

时间:2010-08-09 18:08:57

标签: c++ c algorithm

我有一个算法可以找到一个点是否在多边形内。

 int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
 {
     int i, j, c = 0;
     for (i = 0, j = npts-1; i < npts; j = i++) {
         if ((((yp[i] <= y) && (y < yp[j])) ||
             ((yp[j] <= y) && (y < yp[i]))) &&
             (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
             c = !c;
     }
     return c;
 }

我唯一的问题是假设一个奇怪的缠绕规则。我的意思是,如果多边形是自相交的,那么它被认为是“空”的某些部分将返回false。我需要的是即使它自相交,多边形内的任何东西都会返回true。

由于

2 个答案:

答案 0 :(得分:5)

小心:此答案错误。我现在没时间修复它,但看到评论。

这会将光线从点投射到无穷远,并检查每个多边形边缘的交点。每次找到交集时,都会切换标记c

c = !c;

所以偶数个交叉点意味着偶数个切换,所以c最后会为0。奇数个交叉点意味着奇数个切换,因此c将为1。

如果任何交叉点发生,你想要的是设置c标志:

c = 1;

为了更好的衡量,您可以完全消除c,并提前终止:

 int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y)
 {
     int i, j;
     for (i = 0, j = npts-1; i < npts; j = i++) {
         if ((((yp[i] <= y) && (y < yp[j])) ||
             ((yp[j] <= y) && (y < yp[i]))) &&
             (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
             return 1;
     }
     return 0;
 }

答案 1 :(得分:1)

将原始算法转换为英语:您要确定点右侧的多边形线段数是偶数还是奇数。如果它是偶数(包括零)你的观点在外面,如果奇怪你的观点在里面。这意味着如果右侧有两个段,左侧有两个段,则多边形内的点

您需要做的是更改算法,以便检查两侧的段;如果点的两边都有一个段,则该点在多边形内。

 int CGlEngineFunctions::PointInPoly(int npts, float *xp, float *yp, float x, float y) 
 { 
     int i, j;
     bool hasSegmentLeft = false;
     bool hasSegmentRight = false;
     for (i = 0, j = npts-1; i < npts; j = i++) { 
         if ((((yp[i] <= y) && (y < yp[j])) || 
             ((yp[j] <= y) && (y < yp[i]))))
         {
             if (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])
             {
                 hasSegmentRight = true;
                 if (hasSegmentLeft)  // short circuit early return
                     return true;
             }
             else
             {
                 hasSegmentLeft = true;
                 if (hasSegmentRight)  // short circuit early return
                     return true;
             }
     } 
     return hasSegmentLeft && hasSegmentRight; 
 }

P.S。 for语句构造是一种处理循环列表的非常聪明的方法,它包含在开头;我以前从未见过它。

相关问题