yushff

code the world。

导航

判断点是否在多边形之内的方法

Posted on 2012-05-30 17:09  yushff  阅读(561)  评论(0编辑  收藏  举报

 一.按角度 (转帖:hustcybyhy0611。特此感谢)

1.将多边形的N个顶点与待判断点相连组成一条直线,根据直线的倾斜角将这个N个顶点按照顺时针(或逆时针)的顺序排序. 
2.求相邻两个顶点与待判断点边线的两条直线的顺时针方向的夹角,如果对握有的顶点,这个夹角小于180度,则这个点位于多边形内部. 
这个问题与求平面点集的凸包类似。(此方法不太适合凹多边形)

先写一个辅助类:

 

[c-sharp] view plaincopy
  1. public class Line : IComparable<Line>  
  2.     {  
  3.         #region Members  
  4.   
  5.         private PointF start;  
  6.         private PointF end;  
  7.  
  8.         #endregion  
  9.  
  10.         #region Constructors  
  11.   
  12.         public Line(PointF start, PointF end)  
  13.         {  
  14.             this.start = start;  
  15.             this.end = end;  
  16.         }  
  17.  
  18.         #endregion  
  19.  
  20.         #region Properties  
  21.   
  22.         public PointF Start  
  23.         {  
  24.             get  
  25.             {  
  26.                 return start;  
  27.             }  
  28.             set  
  29.             {  
  30.                 start = value;  
  31.             }  
  32.         }  
  33.   
  34.         public PointF End  
  35.         {  
  36.             get  
  37.             {  
  38.                 return end;  
  39.             }  
  40.             set  
  41.             {  
  42.                 end = value;  
  43.             }  
  44.         }  
  45.   
  46.         public double Angle  
  47.         {  
  48.             get  
  49.             {  
  50.                 double dX = End.X - Start.X;  
  51.                 double dY = End.Y - Start.Y;  
  52.   
  53.                 double angle = Math.Atan(dY / dX) * 180 / Math.PI;  
  54.   
  55.                 if (dX < 0)  
  56.                 {  
  57.                     angle += 180;  
  58.                 }  
  59.   
  60.                 if (angle < 0)  
  61.                 {  
  62.                     angle += 360;  
  63.                 }  
  64.   
  65.                 return angle;  
  66.             }  
  67.         }  
  68.  
  69.         #endregion  
  70.  
  71.         #region Functions  
  72.   
  73.         public double IncludedAngleWith(Line line)  
  74.         {  
  75.             double angle = line.Angle;  
  76.             if (angle < this.Angle)  
  77.             {  
  78.                 angle += 360;  
  79.             }  
  80.   
  81.             return angle - this.Angle;  
  82.         }  
  83.   
  84.         public int CompareTo(Line line)  
  85.         {  
  86.             if (this.Angle < line.Angle)  
  87.             {  
  88.                 return -1;  
  89.             }  
  90.             else if (this.Angle == line.Angle)  
  91.             {  
  92.                 return 0;  
  93.             }  
  94.             else  
  95.             {  
  96.                 return 1;  
  97.             }  
  98.         }  
  99.  
  100.         #endregion  
  101.     }  

 

下面是判断算法:

 

[c-sharp] view plaincopy
  1. public bool Contains(PointF[] vertexArray, PointF point)  
  2.         {  
  3.             Line[] lineArray = new Line[vertexArray.Length];  
  4.             for (int index = 0; index < vertexArray.Length; index++)  
  5.             {  
  6.                 if (vertexArray[index] == point)        //判断点与顶点重合  
  7.                 {  
  8.                     return false;  
  9.                 }  
  10.   
  11.                 lineArray[index] = new Line(point, vertexArray[index]);  
  12.             }  
  13.   
  14.             Array.Sort(lineArray);  
  15.   
  16.             for (int index = 0; index < lineArray.Length - 1; index++)  
  17.             {  
  18.                 if (lineArray[index].IncludedAngleWith(lineArray[index + 1]) >= 180)  
  19.                 {  
  20.                     return false;  
  21.                 }  
  22.             }  
  23.   
  24.             if (lineArray[lineArray.Length - 1].IncludedAngleWith(lineArray[0]) >= 180)  
  25.             {  
  26.                 return false;  
  27.             }  
  28.   
  29.             return true;  
  30.         }  

 

测试代码:

 

[c-sharp] view plaincopy
  1. string str = "124.89874,46.6286V124.9001,46.62973V124.90287,46.62741V124.90409,46.62783V124.90334,46.63028V124.9055,46.63044V124.90629,46.62796V124.90775,46.62792V124.90868,46.63011V124.91089,46.62931V124.90943,46.62751V124.91182,46.62706V124.91257,46.62905V124.91506,46.62812V124.91281,46.6268V124.91459,46.62619V124.91557,46.6277V124.91708,46.62586V124.91468,46.6257V124.91497,46.62477V124.91703,46.62384V124.91497,46.62261V124.91356,46.62387V124.91309,46.62194V124.91506,46.62232V124.91511,46.62081V124.91286,46.62097V124.91271,46.62029V124.91482,46.61975V124.91398,46.61833V124.91187,46.61942V124.91117,46.61872V124.91075,46.61701V124.90746,46.61714V124.90976,46.61878V124.90639,46.61868V124.90559,46.61717V124.90142,46.61772V124.90498,46.61888V124.90212,46.61946V124.90085,46.61807V124.89921,46.61952V124.90151,46.62013V124.90109,46.62152V124.89813,46.62013V124.8979,46.62223V124.90067,46.622V124.90001,46.62351V124.89663,46.62281V124.89663,46.62441V124.89917,46.62445V124.89903,46.62545V124.89588,46.62567V124.89584,46.62702V124.89903,46.62638V124.89982,46.62725";  
  2.             string[] s1 = str.Split('V');  
  3.   
  4.             PointF[] ps = new PointF[s1.Length];  
  5.             for (int i = 0; i < s1.Length; i++)  
  6.             {  
  7.                 string[] s2 = s1[i].Split(',');  
  8.                 PointF pf = new PointF(float.Parse(s2[0]), float.Parse(s2[1]));  
  9.                 ps[i] = pf;  
  10.             }  
  11.   
  12.             float f1=0;     
  13.             float f2=0;  
  14.   
  15.             if (this.Contains(ps, new PointF(f1,f2)))  
  16.             {  
  17.                 MessageBox.Show("在范围内");  
  18.             }  
  19.             else  
  20.             {  
  21.                 MessageBox.Show("不在范围内");  
  22.             }  

 

 

 

二.用c#内置函数:(面对复杂的多边形处理上可能不太好)

 

[c-sharp] view plaincopy
  1. string str = "124.89874,46.6286V124.9001,46.62973V124.90287,46.62741V124.90409,46.62783V124.90334,46.63028V124.9055,46.63044V124.90629,46.62796V124.90775,46.62792V124.90868,46.63011V124.91089,46.62931V124.90943,46.62751V124.91182,46.62706V124.91257,46.62905V124.91506,46.62812V124.91281,46.6268V124.91459,46.62619V124.91557,46.6277V124.91708,46.62586V124.91468,46.6257V124.91497,46.62477V124.91703,46.62384V124.91497,46.62261V124.91356,46.62387V124.91309,46.62194V124.91506,46.62232V124.91511,46.62081V124.91286,46.62097V124.91271,46.62029V124.91482,46.61975V124.91398,46.61833V124.91187,46.61942V124.91117,46.61872V124.91075,46.61701V124.90746,46.61714V124.90976,46.61878V124.90639,46.61868V124.90559,46.61717V124.90142,46.61772V124.90498,46.61888V124.90212,46.61946V124.90085,46.61807V124.89921,46.61952V124.90151,46.62013V124.90109,46.62152V124.89813,46.62013V124.8979,46.62223V124.90067,46.622V124.90001,46.62351V124.89663,46.62281V124.89663,46.62441V124.89917,46.62445V124.89903,46.62545V124.89588,46.62567V124.89584,46.62702V124.89903,46.62638V124.89982,46.62725";  
  2.             string[] s1 = str.Split('V');  
  3.   
  4.             PointF[] ps = new PointF[s1.Length];  
  5.             for (int i = 0; i < s1.Length; i++)  
  6.             {  
  7.                 string[] s2 = s1[i].Split(',');  
  8.                 PointF pf = new PointF(float.Parse(s2[0]), float.Parse(s2[1]));  
  9.                 ps[i] = pf;  
  10.             }  
  11.   
  12.   
  13.   
  14.             System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();  
  15.               
  16.             Region r = new Region();  
  17.   
  18.             gp.Reset();  
  19.             gp.AddPolygon(ps);  
  20.             r.MakeEmpty();  
  21.             r.Union(gp);  
  22.   
  23.             float f1=0;     
  24.             float f2=0;  
  25.               
  26.             if (r.IsVisible(new PointF(f1,f2)))  
  27.             {  
  28.                 MessageBox.Show("在范围内");  
  29.             }  
  30.             else  
  31.             {  
  32.                 MessageBox.Show("不在范围内");  
  33.             }  

 

 

三.射线法判断(本人感觉这个方法较好)

 

[c-sharp] view plaincopy
  1. public int isLeft(Point P0, Point P1,Point P2)  
  2. {  
  3.     int abc= ((P1.X - P0.X) * (P2.Y - P0.Y) - (P2.X - P0.X) * (P1.Y - P0.Y));  
  4.     return abc;  
  5.                                                   
  6. }  
  7.   
  8. private bool PointInFences(Point pnt1, Point[] fencePnts)  
  9. {  
  10.   
  11.     int wn = 0,j=0; //wn 计数器 j第二个点指针  
  12.     for (int i = 0; i < fencePnts.Length; i++)  
  13.     {//开始循环  
  14.              if (i == fencePnts.Length - 1)  
  15.                  j = 0;//如果 循环到最后一点 第二个指针指向第一点  
  16.              else  
  17.                  j = j + 1; //如果不是 ,则找下一点  
  18.   
  19.   
  20.         if (fencePnts[i].Y <= pnt1.Y) // 如果多边形的点 小于等于 选定点的 Y 坐标  
  21.         {  
  22.             if (fencePnts[j].Y > pnt1.Y) // 如果多边形的下一点 大于于 选定点的 Y 坐标  
  23.             {  
  24.                 if (isLeft(fencePnts[i], fencePnts[j], pnt1) > 0)  
  25.                 {  
  26.                     wn++;  
  27.                 }  
  28.             }  
  29.         }  
  30.         else  
  31.         {  
  32.             if (fencePnts[j].Y <= pnt1.Y)  
  33.             {  
  34.                 if (isLeft(fencePnts[i], fencePnts[j], pnt1) < 0)  
  35.                 {  
  36.                     wn--;  
  37.                 }  
  38.             }  
  39.         }  
  40.     }  
  41.     if (wn == 0)  
  42.         return false;  
  43.     else  
  44.         return true;  

From: http://blog.csdn.net/lqh_it/article/details/4667394