射线法判断点是否在多边形内的关键代码

来源:互联网 发布:本地域名服务器在哪 编辑:程序博客网 时间:2024/04/19 17:31

 

完全实例代码。如需进一步了解,及了解更新情况请登陆独傲村里的GIS版块,支持下载

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

 

namespace RadialPointInPolygon

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void btnIsPointInPolygon_Click(object sender, EventArgs e)

        {

            Point p = new Point(0, 1);

            Point[] V={new Point(1, 2),new Point(1, 0),new Point(3, 3)};//程序中仅以这几个点为例

            //V[0] = new Point(1, 2);

            //V[1] = new Point(1, 0);

            //V[2] = new Point(3, 3);

 

            if (IsPointInPolygon(p, V, 3) == true)

            {

                MessageBox.Show("点在多边形内");

            }

            else MessageBox.Show("点在多边形外");

        }

 

        /// <summary>

        /// 判断点是否在多边形内

        /// </summary>

        /// <param name="P"></param>

        /// <param name="V"></param>

        /// <param name="n"></param>

        /// <returns></returns>

        private Boolean IsPointInPolygon(Point P, Point[] V, int n)

        //统计穿越次数,为奇数时返回true,在多边形内。n为边数。

        {

            int cn = 0;  //the crossing number counter.

            Rectangle outRec = OutRectangle(V);

 

            if (n < 3) return false;//最多两个点时

 

            else if ((P.X <= outRec.X + outRec.Width) && P.X >= outRec.X && P.Y >= outRec.Y && P.Y <= outRec.Y + outRec.Height)

                //在外包矩形中时.

            {

                //set a horizontal beam from P to W.

                Point W = new Point(P.X + outRec.Width + 1, P.Y);

                int j = 0, k1 = 0, k2 = 0;

 

                for (int i = 0; i < n; i++)//for里面的这段代码参考网上的代码写出的

                {

                    j = (i + 1) % n; //i下一个数为j

                    if (IsLineIntersect(V[i], V[j], P, W) == true) //如果线与线相交

                    {

                        cn++;

                    }

                    else if (V[i].Y == W.Y) //点在水平射线上

                    {

 

                        k1 = (n + i - 1) % n;//k1为当前点的前一个点的index

                        while (k1 != i && V[k1].Y == W.Y) //如果前一个点也在射线上

 

                            k1 = (n + k1 - 1) % n; //k1返回到起点

 

                        k2 = (i + 1) % n; //k2为当前点的下一个点

                        while (k2 != i && V[k2].Y == W.Y) //如果下一个点也在射线上

 

                            k2 = (k2 + 1) % n;//k2到k2的下一个点

 

                        if (k1 != k2 && IsPointSameSide(P, W, V[k1], V[k2]) == false)//k1和k2处点不在同一侧

 

                            cn++;

 

                        if (k2 <= i)

 

                            break;

 

                        i = k2; //i从k2处开始继续走

 

                    }

                }

                if (cn % 2 == 1) return true;

                else return false;

 

            }

 

            else return false;//如果不在外包矩形中,直接返回false。

        }

 

        /// <summary>

        /// 求多边形的外包矩形

        /// </summary>

        /// <param name="v"></param>

        /// <returns></returns>

        private Rectangle OutRectangle(Point[] v)

        {

            double min_x=v[0].X , min_y=v[0].Y , max_x=v[0].X , max_y=v[0].Y ;

            int x, y, w, h;

            for (int i = 0; i < v.Length; i++)

            {

                if (v[i].X > max_x) max_x = v[i].X;

                if (v[i].X < min_x) min_x = v[i].X;

                if (v[i].Y > max_y) max_y = v[i].Y;

                if (v[i].Y < min_y) min_y = v[i].Y;

            }

            x=Convert.ToInt32 (min_x);

            y=Convert.ToInt32 (min_y);

            w=Convert .ToInt32 (max_x -min_x)+1;

            h=Convert.ToInt32 (max_y -min_y )+1;

            Rectangle rec=new Rectangle(x,y,w,h);

            return rec;

        }

 

        /// <summary>

        /// 判断两点是否在线的同侧

        /// </summary>

        /// <param name="p1"></param>

        /// <param name="p2"></param>

        /// <param name="l_start"></param>

        /// <param name="l_end"></param>

        /// <returns></returns>

        private Boolean IsPointSameSide(Point p1, Point p2, Point l_start, Point l_end)

        {

            double result1,result2,result;

 

            Point s1=new Point(0,0);

            Point s2 = new Point(0, 0);

            Point e = new Point(0, 0);

 

            s1.X = p1.X - l_start.X;

            s1.Y = p1.Y - l_start.Y;

 

            s2.X = p2.X - l_start.X;

            s2.Y = p2.Y - l_start.Y;

 

            e.X = l_end.X- l_start.X;

            e.Y = l_end.Y - l_start.Y;

 

            result1 =VectorCrossProduct(s1,e);//矢量叉乘

            result2 = VectorCrossProduct(s2,e);

            result = (result1 * result2);

            if (result > 0) return true;//大于0在同侧

            else return false;

        }

 

        /// <summary>

        /// 判断两线相交

        /// </summary>

        /// <param name="s1_start"></param>

        /// <param name="s1_end"></param>

        /// <param name="s2_start"></param>

        /// <param name="s2_end"></param>

        /// <returns></returns>

        private Boolean IsLineIntersect(Point s1_start, Point s1_end, Point s2_start, Point s2_end)

        {

            if ((!IsPointSameSide(s1_start, s1_end, s2_start, s2_end)) == true &&

                (!IsPointSameSide(s2_start, s2_end, s1_start, s1_end)) == true)

                return true;

            else return false;

 

        }

 

        /// <summary>

        /// 两矢量叉乘

        /// </summary>

        /// <param name="p"></param>

        /// <param name="q"></param>

        /// <returns></returns>

        private double VectorCrossProduct(Point p, Point q)

        {

            double result = 0;

            result = p.X * q.Y - q.X * p.Y;

            return result;

        }

 

 

    }

}

 

原创粉丝点击