C# 多边形中的C点

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.

我试图确定一个点是否在多边形内。多边形由点对象数组定义。我可以很容易地确定点是否在多边形的有界框内,但我不确定如何判断它是否在实际多边形内。如果可能的话,我只想使用C#和WinForms。我不想调用OpenGL或其他东西来完成这个简单的任务

以下是我目前掌握的代码:

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;
 }