一.按角度 (转帖:hustcyb,yhy0611。特此感谢)
1.将多边形的N个顶点与待判断点相连组成一条直线,根据直线的倾斜角将这个N个顶点按照顺时针(或逆时针)的顺序排序.
2.求相邻两个顶点与待判断点边线的两条直线的顺时针方向的夹角,如果对握有的顶点,这个夹角小于180度,则这个点位于多边形内部.
这个问题与求平面点集的凸包类似。(此方法不太适合凹多边形)
先写一个辅助类:
- public class Line : IComparable<Line>
- {
- #region Members
- private PointF start;
- private PointF end;
- #endregion
- #region Constructors
- public Line(PointF start, PointF end)
- {
- this.start = start;
- this.end = end;
- }
- #endregion
- #region Properties
- public PointF Start
- {
- get
- {
- return start;
- }
- set
- {
- start = value;
- }
- }
- public PointF End
- {
- get
- {
- return end;
- }
- set
- {
- end = value;
- }
- }
- public double Angle
- {
- get
- {
- double dX = End.X - Start.X;
- double dY = End.Y - Start.Y;
- double angle = Math.Atan(dY / dX) * 180 / Math.PI;
- if (dX < 0)
- {
- angle += 180;
- }
- if (angle < 0)
- {
- angle += 360;
- }
- return angle;
- }
- }
- #endregion
- #region Functions
- public double IncludedAngleWith(Line line)
- {
- double angle = line.Angle;
- if (angle < this.Angle)
- {
- angle += 360;
- }
- return angle - this.Angle;
- }
- public int CompareTo(Line line)
- {
- if (this.Angle < line.Angle)
- {
- return -1;
- }
- else if (this.Angle == line.Angle)
- {
- return 0;
- }
- else
- {
- return 1;
- }
- }
- #endregion
- }
下面是判断算法:
- public bool Contains(PointF[] vertexArray, PointF point)
- {
- Line[] lineArray = new Line[vertexArray.Length];
- for (int index = 0; index < vertexArray.Length; index++)
- {
- if (vertexArray[index] == point) //判断点与顶点重合
- {
- return false;
- }
- lineArray[index] = new Line(point, vertexArray[index]);
- }
- Array.Sort(lineArray);
- for (int index = 0; index < lineArray.Length - 1; index++)
- {
- if (lineArray[index].IncludedAngleWith(lineArray[index + 1]) >= 180)
- {
- return false;
- }
- }
- if (lineArray[lineArray.Length - 1].IncludedAngleWith(lineArray[0]) >= 180)
- {
- return false;
- }
- return true;
- }
测试代码:
- 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";
- string[] s1 = str.Split('V');
- PointF[] ps = new PointF[s1.Length];
- for (int i = 0; i < s1.Length; i++)
- {
- string[] s2 = s1[i].Split(',');
- PointF pf = new PointF(float.Parse(s2[0]), float.Parse(s2[1]));
- ps[i] = pf;
- }
- float f1=0;
- float f2=0;
- if (this.Contains(ps, new PointF(f1,f2)))
- {
- MessageBox.Show("在范围内");
- }
- else
- {
- MessageBox.Show("不在范围内");
- }
二.用c#内置函数:(面对复杂的多边形处理上可能不太好)
- 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";
- string[] s1 = str.Split('V');
- PointF[] ps = new PointF[s1.Length];
- for (int i = 0; i < s1.Length; i++)
- {
- string[] s2 = s1[i].Split(',');
- PointF pf = new PointF(float.Parse(s2[0]), float.Parse(s2[1]));
- ps[i] = pf;
- }
- System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
- Region r = new Region();
- gp.Reset();
- gp.AddPolygon(ps);
- r.MakeEmpty();
- r.Union(gp);
- float f1=0;
- float f2=0;
- if (r.IsVisible(new PointF(f1,f2)))
- {
- MessageBox.Show("在范围内");
- }
- else
- {
- MessageBox.Show("不在范围内");
- }
三.射线法判断(本人感觉这个方法较好)
- public int isLeft(Point P0, Point P1,Point P2)
- {
- int abc= ((P1.X - P0.X) * (P2.Y - P0.Y) - (P2.X - P0.X) * (P1.Y - P0.Y));
- return abc;
- }
- private bool PointInFences(Point pnt1, Point[] fencePnts)
- {
- int wn = 0,j=0; //wn 计数器 j第二个点指针
- for (int i = 0; i < fencePnts.Length; i++)
- {//开始循环
- if (i == fencePnts.Length - 1)
- j = 0;//如果 循环到最后一点 第二个指针指向第一点
- else
- j = j + 1; //如果不是 ,则找下一点
- if (fencePnts[i].Y <= pnt1.Y) // 如果多边形的点 小于等于 选定点的 Y 坐标
- {
- if (fencePnts[j].Y > pnt1.Y) // 如果多边形的下一点 大于于 选定点的 Y 坐标
- {
- if (isLeft(fencePnts[i], fencePnts[j], pnt1) > 0)
- {
- wn++;
- }
- }
- }
- else
- {
- if (fencePnts[j].Y <= pnt1.Y)
- {
- if (isLeft(fencePnts[i], fencePnts[j], pnt1) < 0)
- {
- wn--;
- }
- }
- }
- }
- if (wn == 0)
- return false;
- else
- return true;