C#判断点与多边形位置关系(旋转法、射线法)

    基于C#窗体应用程序,通过用户自定义的多边形与点,判断点与多边形的关系。

一、射线法

1 射线法原理

    用交点个数的奇偶性来判定目标点是否在目标多边形内部,由目标点出发,向任意方向作射线,统计与目标多边形的交点个数。一般情况下,交点个数若为偶数则在多边形外部;若为奇数则在多边形内部。当出现点在边上,所作射线与多边形的边重合时应另作处理。

2 射线法的优缺点

    优点:算法简单,容易实现;易于改进结合。

    缺点:要对每一条边都需要做两次以上的乘法运算,涉及大量的求教运算;很难处理一些临界性的问题,对于特殊情况(射线法过定点的情况,点在边上的情况,射线所水平边的情况)的处理能力不足,易出错,稳定性较差,灵活性低。

3 射线法代码

            int num = newploy.Count;
            水平射线法
            正常情况与多边形的交点为偶数的话在多边形外(一进一出),奇数的话在多边形内
            特殊情况1:点为多边形顶点,点在多边形上
            特殊情况2:射线经过多边形顶点
            bool flag = true;
            for (int i = 0; i < num; i++)
            {
                //点为多边形顶点
                if ((p == newploy[i]) || (p == newploy[(i + 1) % num]))
                    return 0;
                else if ((p.Y >= newploy[i].Y && p.Y < newploy[(i + 1) % num].Y) || 
                    (p.Y >= newploy[(i + 1) % num].Y && p.Y < newploy[i].Y))
                {
                    double x = (double)(newploy[i].X - newploy[(i + 1) % num].X) * (p.Y - newploy[i].Y)
                        / (newploy[i].Y - newploy[(i + 1) % num].Y) + newploy[i].X;
                    if (Math.Abs(x - p.X) < 1e-4)
                        return 0;
                    if (x > p.X)
                        flag = !flag;
                }
            }
            return flag ? 1 : -1;

二、旋转法

1 旋转法原理

    用角度值来判定目标点是否在目标多边形内部,由目标点出发,引线延伸到多边形的每一个顶点,按逆时针方向进行,完成多边形的封闭(由起始点开始回到起始点)。如果点到顶点的角度之和为o,则点位于多边形之外,超过T的以其补角的负值进行叠加。若所有角度之和非零则目标点位于多边形内或多边形上。

2 旋转法的优缺点

    优点:旋转法算法周全,对于特殊情况的处理灵活判断准确不易出错。旋转法是判断点在多边形内外的最流行的算法之一,用程序语言表示较射线法更简洁,更容易理解和掌握,且精度较高
    缺点:旋转法算法判断条件较复杂,相比射线法实现较为困难;需要计算大量的反三角函数,时间复杂度较大,且当点落于多边形的边上时,算法会恒认为其在多边形的内部;处理凹多边形时存在歧义。

3 旋转法代码

            for (int i = 0; i < newploy.Count; i++)
            {
                //计算点到多边形顶点的距离
                double res1 = TwoPDistance(p.X, newploy[i].X, p.Y, newploy[i].Y);
                Arraylist.Add(res1);
            }
            for (int j = 0; j < newploy.Count; j++)
            {
                double a = j + 1 < newploy.Count ? TwoPDistance(newploy[j].X, newploy[j + 1].X, newploy[j].Y, newploy[j + 1].Y)
                    : TwoPDistance(newploy[0].X, newploy[j].X, newploy[0].Y, newploy[j].Y);
                if(j+1 < newploy.Count)
                {
                    temp = Angle(a, Convert.ToDouble(Arraylist[j]), Convert.ToDouble(Arraylist[j + 1]));
                    if (temp >= 180)
                    {
                        temp = -(180 - temp);
                    }
                    sumAngle += temp;
                }
                else
                {
                    temp1 = Angle(a, Convert.ToDouble(Arraylist[j]), Convert.ToDouble(Arraylist[0]));
                    if (temp1 >= 180)
                    {
                        temp1 = -(180 - temp1);
                    }
                    sumAngle += temp1;
                }
            }
            double res = Math.Abs(sumAngle);

public ArrayList Arraylist = new ArrayList();

其中Angle()是用来计算角度的函数、TwoPDistance()是用来计算两点间距离的函数。

三、实现效果

C#判断点与多边形位置关系(旋转法、射线法)_第1张图片

 C#判断点与多边形位置关系(旋转法、射线法)_第2张图片

C#判断点与多边形位置关系(旋转法、射线法)_第3张图片 

C#判断点与多边形位置关系(旋转法、射线法)_第4张图片

 

 原创内容 

请勿抄袭

欢迎留言

你可能感兴趣的:(算法)