C# 多边形中的C点
我试图确定一个点是否在多边形内。多边形由点对象数组定义。我可以很容易地确定点是否在多边形的有界框内,但我不确定如何判断它是否在实际多边形内。如果可能的话,我只想使用C#和WinForms。我不想调用OpenGL或其他东西来完成这个简单的任务 以下是我目前掌握的代码:C# 多边形中的C点,c#,.net,algorithm,C#,.net,Algorithm,我试图确定一个点是否在多边形内。多边形由点对象数组定义。我可以很容易地确定点是否在多边形的有界框内,但我不确定如何判断它是否在实际多边形内。如果可能的话,我只想使用C#和WinForms。我不想调用OpenGL或其他东西来完成这个简单的任务 以下是我目前掌握的代码: private void CalculateOuterBounds() { //m_aptVertices is a Point[] which holds the vertices of the polygon.
private void CalculateOuterBounds()
{
//m_aptVertices is a Point[] which holds the vertices of the polygon.
// and X/Y min/max are just ints
Xmin = Xmax = m_aptVertices[0].X;
Ymin = Ymax = m_aptVertices[0].Y;
foreach(Point pt in m_aptVertices)
{
if(Xmin > pt.X)
Xmin = pt.X;
if(Xmax < pt.X)
Xmax = pt.X;
if(Ymin > pt.Y)
Ymin = pt.Y;
if(Ymax < pt.Y)
Ymax = pt.Y;
}
}
public bool Contains(Point pt)
{
bool bContains = true; //obviously wrong at the moment :)
if(pt.X < Xmin || pt.X > Xmax || pt.Y < Ymin || pt.Y > Ymax)
bContains = false;
else
{
//figure out if the point is in the polygon
}
return bContains;
}
private void calculateOutbounds()
{
//m_aptVertices是一个点[],它包含多边形的顶点。
//和X/Y最小值/最大值只是整数
Xmin=Xmax=m_aptv属性[0].X;
Ymin=Ymax=m_aptV系数[0].Y;
foreach(以m_aptV为单位的点pt)
{
如果(Xmin>pt.X)
Xmin=pt.X;
如果(Xmaxpt.Y)
Ymin=pt.Y;
if(YmaxXmax | pt.YYmax)
b内容=假;
其他的
{
//确定点是否在多边形中
}
返回b内容;
}
您可以使用光线投射算法。这在维基百科页面上有很好的描述
这就像计算光线从外部到该点接触多边形边界的次数一样简单。如果接触偶数次,则该点位于多边形外部。如果接触次数为奇数,则该点位于内部
计数光线接触的次数,检查光线与多边形边的交点。
< P>参见C++中,并可以以同样的方式在C中完成。< /P> 对于凸多边形来说太容易了: 如果多边形是凸的,则可以 将多边形视为“路径” 第一个顶点。有一点在讨论中 此多边形的内部(如果是) 总是站在所有人的同一边 构成路径的线段 给定P0之间的线段 (x0,y0)和P1(x1,y1),另一点 P(x,y)具有以下关系 到线段。计算(y-y0) (x1-x0)-(x-x0)(y1-y0) 如果它小于0,则p为 线段的右侧(如果较大) 如果大于0,则在左侧,如果等于 0,则它位于线段上 这是它的c#代码,我没有检查边缘情况 public static bool IsInPolygon(Point[] poly, Point point)
{
var coef = poly.Skip(1).Select((p, i) =>
(point.Y - poly[i].Y)*(p.X - poly[i].X)
- (point.X - poly[i].X) * (p.Y - poly[i].Y))
.ToList();
if (coef.Any(p => p == 0))
return true;
for (int i = 1; i < coef.Count(); i++)
{
if (coef[i] * coef[i - 1] < 0)
return false;
}
return true;
}
关于linq查询的说明:
poly.Skip(1)
==>从poly
列表的位置1
开始创建一个新列表,然后通过
(point.Y-poly[i].Y)*(p.X-poly[i].X)-(point.X-poly[i].X)*(p.Y-poly[i].Y)
我们将计算方向(参考段落中提到)。
类似示例(另一个操作):
完整的算法和C代码可在
将其转换为c#/winforms将是一件微不足道的事情。在我的项目中,接受的答案对我来说不起作用。我最终使用了找到的代码
公共静态布尔值为多边形(点[]多边形,点p)
{
点p1,p2;
bool-inside=false;
如果(多边形长度<3)
{
返回内部;
}
var oldPoint=新点(
多边形[poly.Length-1].X,多边形[poly.Length-1].Y);
对于(int i=0;ioldPoint.X)
{
p1=旧点;
p2=新点;
}
其他的
{
p1=新点;
p2=旧点;
}
如果((newPoint.X
最好的方法是:
/// <summary>
/// Determines if the given point is inside the polygon
/// </summary>
/// <param name="polygon">the vertices of polygon</param>
/// <param name="testPoint">the given point</param>
/// <returns>true if the point is inside the polygon; otherwise, false</returns>
public static bool IsPointInPolygon4(PointF[] polygon, PointF testPoint)
{
bool result = false;
int j = polygon.Count() - 1;
for (int i = 0; i < polygon.Count(); i++)
{
if (polygon[i].Y < testPoint.Y && polygon[j].Y >= testPoint.Y || polygon[j].Y < testPoint.Y && polygon[i].Y >= testPoint.Y)
{
if (polygon[i].X + (testPoint.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) * (polygon[j].X - polygon[i].X) < testPoint.X)
{
result = !result;
}
}
j = i;
}
return result;
}
//
///确定给定点是否在多边形内
///
///多边形的顶点
///给定点
///如果点位于多边形内部,则为true;否则为false
公共静态布尔值IsPointInPolygon4(PointF[]多边形,PointF测试点)
{
布尔结果=假;
int j=polygon.Count()-1;
对于(int i=0;i=testPoint.Y | |多边形[j].Y=testPoint.Y)
{
如果(多边形[i].X+(测试点.Y-多边形[i].Y)/(多边形[j].Y-多边形[i].Y)*(多边形[j].X-多边形[i].X)
我的答案如下:
我把C代码转换成C#并使其正常工作
static bool pnpoly(PointD[] poly, PointD pnt )
{
int i, j;
int nvert = poly.Length;
bool c = false;
for (i = 0, j = nvert - 1; i < nvert; j = i++)
{
if (((poly[i].Y > pnt.Y) != (poly[j].Y > pnt.Y)) &&
(pnt.X < (poly[j].X - poly[i].X) * (pnt.Y - poly[i].Y) / (poly[j].Y - poly[i].Y) + poly[i].X))
c = !c;
}
return c;
}
static bool pnpoly(PointD[]poly,PointD pnt)
{
int i,j;
int nvert=多边形长度;
boolc=假;
对于(i=0,j=nvert-1;ipnt.Y)!=(poly[j].Y>pnt.Y))&&
(pnt.X<(poly[j].X-poly[i].X)*(pnt.Y-poly[i].Y)/(poly[j].Y-poly[i].Y)+poly[i].X)
c=!c;
}
返回c;
}
您可以使用以下示例对其进行测试:
PointD[] pts = new PointD[] { new PointD { X = 1, Y = 1 },
new PointD { X = 1, Y = 2 },
new PointD { X = 2, Y = 2 },
new PointD { X = 2, Y = 3 },
new PointD { X = 3, Y = 3 },
new PointD { X = 3, Y = 1 }};
List<bool> lst = new List<bool>();
lst.Add(pnpoly(pts, new PointD { X = 2, Y = 2 }));
lst.Add(pnpoly(pts, new PointD { X = 2, Y = 1.9 }));
lst.Add(pnpoly(pts, new PointD { X = 2.5, Y = 2.5 }));
lst.Add(pnpoly(pts, new PointD { X = 1.5, Y = 2.5 }));
lst.Add(pnpoly(pts, new PointD { X = 5, Y = 5 }));
PointD[]pts=newpointd[]{newpointd{X=1,Y=1},
新点d{X=1,Y=2},
新点d{X=2,Y=2},
新点d{X=2,Y=3},
新点d{X=3,Y=3},
新点d{X=3,Y=1};
List lst=新列表();
lst.Add(pnpoly(pts,新点d{X=2,Y=2}));
lst.Add(pnpoly(pts,新点d{X=2,Y=1.9}));
lst.Add(pnpoly(pts,新点d{X=2.5,Y=2.5}));
lst.Add(pnpoly(pts,新点d{X=1.5,Y=2.5}));
lst.Add(pnpoly(pts,新点d{X=5,Y=5}));
我推荐Kai Hormann(爱尔兰根大学)和Alexan撰写的这篇精彩的15页论文
/// <summary>
/// Determines if the given point is inside the polygon
/// </summary>
/// <param name="polygon">the vertices of polygon</param>
/// <param name="testPoint">the given point</param>
/// <returns>true if the point is inside the polygon; otherwise, false</returns>
public static bool IsPointInPolygon4(PointF[] polygon, PointF testPoint)
{
bool result = false;
int j = polygon.Count() - 1;
for (int i = 0; i < polygon.Count(); i++)
{
if (polygon[i].Y < testPoint.Y && polygon[j].Y >= testPoint.Y || polygon[j].Y < testPoint.Y && polygon[i].Y >= testPoint.Y)
{
if (polygon[i].X + (testPoint.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) * (polygon[j].X - polygon[i].X) < testPoint.X)
{
result = !result;
}
}
j = i;
}
return result;
}
static bool pnpoly(PointD[] poly, PointD pnt )
{
int i, j;
int nvert = poly.Length;
bool c = false;
for (i = 0, j = nvert - 1; i < nvert; j = i++)
{
if (((poly[i].Y > pnt.Y) != (poly[j].Y > pnt.Y)) &&
(pnt.X < (poly[j].X - poly[i].X) * (pnt.Y - poly[i].Y) / (poly[j].Y - poly[i].Y) + poly[i].X))
c = !c;
}
return c;
}
PointD[] pts = new PointD[] { new PointD { X = 1, Y = 1 },
new PointD { X = 1, Y = 2 },
new PointD { X = 2, Y = 2 },
new PointD { X = 2, Y = 3 },
new PointD { X = 3, Y = 3 },
new PointD { X = 3, Y = 1 }};
List<bool> lst = new List<bool>();
lst.Add(pnpoly(pts, new PointD { X = 2, Y = 2 }));
lst.Add(pnpoly(pts, new PointD { X = 2, Y = 1.9 }));
lst.Add(pnpoly(pts, new PointD { X = 2.5, Y = 2.5 }));
lst.Add(pnpoly(pts, new PointD { X = 1.5, Y = 2.5 }));
lst.Add(pnpoly(pts, new PointD { X = 5, Y = 5 }));
public static bool IsInPolygon(this Point point, IEnumerable<Point> polygon)
{
bool result = false;
var a = polygon.Last();
foreach (var b in polygon)
{
if ((b.X == point.X) && (b.Y == point.Y))
return true;
if ((b.Y == a.Y) && (point.Y == a.Y) && (a.X <= point.X) && (point.X <= b.X))
return true;
if ((b.Y < point.Y) && (a.Y >= point.Y) || (a.Y < point.Y) && (b.Y >= point.Y))
{
if (b.X + (point.Y - b.Y) / (a.Y - b.Y) * (a.X - b.X) <= point.X)
result = !result;
}
a = b;
}
return result;
}
public static bool IsInPolygon(this List<Point> poly, Point point)
{
var coef = poly.Skip(1).Select((p, i) =>
(point.y - poly[i].y) * (p.x - poly[i].x)
- (point.x - poly[i].x) * (p.y - poly[i].y));
var coefNum = coef.GetEnumerator();
if (coef.Any(p => p == 0))
return true;
int lastCoef = coefNum.Current,
count = coef.Count();
coefNum.MoveNext();
do
{
if (coefNum.Current - lastCoef < 0)
return false;
lastCoef = coefNum.Current;
}
while (coefNum.MoveNext());
return true;
}
public static bool IsPointInPolygon(Point point, IList<Point> polygon)
{
var intersects = new List<int>();
var a = polygon.Last();
foreach (var b in polygon)
{
if (b.X == point.X && b.Y == point.Y)
{
return true;
}
if (b.X == a.X && point.X == a.X && point.X >= Math.Min(a.Y, b.Y) && point.Y <= Math.Max(a.Y, b.Y))
{
return true;
}
if (b.Y == a.Y && point.Y == a.Y && point.X >= Math.Min(a.X, b.X) && point.X <= Math.Max(a.X, b.X))
{
return true;
}
if ((b.Y < point.Y && a.Y >= point.Y) || (a.Y < point.Y && b.Y >= point.Y))
{
var px = (int)(b.X + 1.0 * (point.Y - b.Y) / (a.Y - b.Y) * (a.X - b.X));
intersects.Add(px);
}
a = b;
}
intersects.Sort();
return intersects.IndexOf(point.X) % 2 == 0 || intersects.Count(x => x < point.X) % 2 == 1;
}
public static bool IsOriginInPolygon(double[,] cpyArr){
var sum = 0.0;
var tolerance = 1e-4;
for (int i = 0; i < cpyArr.GetLength(0)- 1; i++)
{
//convert vertex point pairs to complex numbers for simplified coding
var c2 = new Complex(cpyArr[i+1, 0], cpyArr[i+1, 1]);
var c1 = new Complex(cpyArr[i, 0], cpyArr[i, 1]);
//find the rotation angle from c1 to c2 when viewed from the origin
var phaseDiff = Complex.Divide(c2, c1).Phase;
//add the rotation angle to the sum
sum += phaseDiff;
//immediately exit the loop if the origin is on the edge of polygon or it is one of the vertices of the polygon
if (Math.Abs( Math.Abs(phaseDiff) - Math.PI ) < tolerance || c1.Magnitude < tolerance || c2.Magnitude < tolerance)
{
sum = Math.PI * 2; break;
}
}
return Math.Abs((Math.PI*2 ) - Math.Abs(sum)) < tolerance;
}