1. 程式人生 > >點在多邊形內算法,C#判斷一個點是否在一個復雜多邊形的內部

點在多邊形內算法,C#判斷一個點是否在一個復雜多邊形的內部

奇數 param list() 如果 集合 c# nal sdn 技術

判斷一點是否在不規則圖像的內部算法,如下圖是由一個個點組成的不規則圖像,判斷某一點是否在不規則矩形內部,先上效果圖

技術分享

算法實現如下,算法簡單,親試有效

    public class PositionAlgorithmHelper
    {
        /// <summary>
        /// 判斷當前位置是否在不規則形狀裏面
        /// </summary>
        /// <param name="nvert">不規則形狀的定點數</param>
        /// <param name="vertx">當前x坐標
</param> /// <param name="verty">當前y坐標</param> /// <param name="testx">不規則形狀x坐標集合</param> /// <param name="testy">不規則形狀y坐標集合</param> /// <returns></returns> public static bool PositionPnpoly(int nvert, List<double> vertx, List<double
> verty, double testx, double testy) { int i, j, c = 0; for (i = 0, j = nvert - 1; i < nvert; j = i++) { if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i])) { c
= 1 + c; ; } } if (c % 2 == 0) { return false; } else { return true; } } }

用上圖坐標進行測試:

    class Program
    {
        static void Main(string[] args)
        {
            test1();
        }

        /// <summary>
        /// test1
        /// </summary>
        public static void test1()
        {
            //不規則圖像坐標
            List<Position> position = new List<Position>();
            position.Add(new Position() { x = 6, y = 0 });
            position.Add(new Position() { x = 10, y = 2 });
            position.Add(new Position() { x = 16, y = 2 });
            position.Add(new Position() { x = 20, y = 6 });
            position.Add(new Position() { x = 14, y = 10 });
            position.Add(new Position() { x = 16, y = 6 });
            position.Add(new Position() { x = 12, y = 6 });
            position.Add(new Position() { x = 14, y = 8 });
            position.Add(new Position() { x = 10, y = 8 });
            position.Add(new Position() { x = 8, y = 6 });
            position.Add(new Position() { x = 12, y = 4 });
            position.Add(new Position() { x = 6, y = 4 });
            position.Add(new Position() { x = 8, y = 2 });

            //用戶當前位置坐標
            List<Position> userPositions = new List<Position>();
            userPositions.Add(new Position() { x = 14, y = 4 });
            userPositions.Add(new Position() { x = 15, y = 4 });
            userPositions.Add(new Position() { x = 10, y = 6 });
            userPositions.Add(new Position() { x = 8, y = 5 });

            //不規則圖像x坐標集合
            List<double> xList = position.Select(x => x.x).ToList();
            //不規則圖像y坐標集合
            List<double> yList = position.Select(x => x.y).ToList();

            foreach (var userPosition in userPositions)
            {
                bool result = PositionAlgorithmHelper.PositionPnpoly(position.Count, xList, yList, userPosition.x, userPosition.y);

                if (result)
                {
                    Console.WriteLine(string.Format("{0},{1}【在】坐標內", userPosition.x, userPosition.y));
                }
                else
                {
                    Console.WriteLine(string.Format("{0},{1}【不在】坐標內", userPosition.x, userPosition.y));
                }
            }
        }
    }

另外兩種方式:

        /// <summary>  
        /// 判斷點是否在多邊形內.  
        /// ----------原理----------  
        /// 註意到如果從P作水平向左的射線的話,如果P在多邊形內部,那麽這條射線與多邊形的交點必為奇數,  
        /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。  
        /// 所以,我們可以順序考慮多邊形的每條邊,求出交點的總個數。還有一些特殊情況要考慮。假如考慮邊(P1,P2),  
        /// 1)如果射線正好穿過P1或者P2,那麽這個交點會被算作2次,處理辦法是如果P的從坐標與P1,P2中較小的縱坐標相同,則直接忽略這種情況  
        /// 2)如果射線水平,則射線要麽與其無交點,要麽有無數個,這種情況也直接忽略。  
        /// 3)如果射線豎直,而P0的橫坐標小於P1,P2的橫坐標,則必然相交。  
        /// 4)再判斷相交之前,先判斷P是否在邊(P1,P2)的上面,如果在,則直接得出結論:P再多邊形內部。  
        /// </summary>  
        /// <param name="checkPoint">要判斷的點</param>  
        /// <param name="polygonPoints">多邊形的頂點</param>  
        /// <returns></returns>  
        public static bool IsInPolygon2(Position checkPoint, List<Position> polygonPoints)
        {
            int counter = 0;
            int i;
            double xinters;
            Position p1, p2;
            int pointCount = polygonPoints.Count;
            p1 = polygonPoints[0];
            for (i = 1; i <= pointCount; i++)
            {
                p2 = polygonPoints[i % pointCount];
                if (checkPoint.y > Math.Min(p1.y, p2.y)//校驗點的Y大於線段端點的最小Y  
                    && checkPoint.y <= Math.Max(p1.y, p2.y))//校驗點的Y小於線段端點的最大Y  
                {
                    if (checkPoint.x <= Math.Max(p1.x, p2.x))//校驗點的X小於等線段端點的最大X(使用校驗點的左射線判斷).  
                    {
                        if (p1.y != p2.y)//線段不平行於X軸  
                        {
                            xinters = (checkPoint.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
                            if (p1.x == p2.x || checkPoint.x <= xinters)
                            {
                                counter++;
                            }
                        }
                    }

                }
                p1 = p2;
            }

            if (counter % 2 == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>  
        /// 判斷點是否在多邊形內.  
        /// ----------原理----------  
        /// 註意到如果從P作水平向左的射線的話,如果P在多邊形內部,那麽這條射線與多邊形的交點必為奇數,  
        /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。  
        /// </summary>  
        /// <param name="checkPoint">要判斷的點</param>  
        /// <param name="polygonPoints">多邊形的頂點</param>  
        /// <returns></returns>  
        public static bool IsInPolygon(Position checkPoint, List<Position> polygonPoints)
        {
            bool inside = false;
            int pointCount = polygonPoints.Count;
            Position p1, p2;
            for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一個點和最後一個點作為第一條線,之後是第一個點和第二個點作為第二條線,之後是第二個點與第三個點,第三個點與第四個點...  
            {
                p1 = polygonPoints[i];
                p2 = polygonPoints[j];
                if (checkPoint.y < p2.y)
                {//p2在射線之上  
                    if (p1.y <= checkPoint.y)
                    {//p1正好在射線中或者射線下方  
                        if ((checkPoint.y - p1.y) * (p2.x - p1.x) > (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側  
                        {
                            //射線與多邊形交點為奇數時則在多邊形之內,若為偶數個交點時則在多邊形之外。  
                            //由於inside初始值為false,即交點數為零。所以當有第一個交點時,則必為奇數,則在內部,此時為inside=(!inside)  
                            //所以當有第二個交點時,則必為偶數,則在外部,此時為inside=(!inside)  
                            inside = (!inside);
                        }
                    }
                }
                else if (checkPoint.y < p1.y)
                {
                    //p2正好在射線中或者在射線下方,p1在射線上  
                    if ((checkPoint.y - p1.y) * (p2.x - p1.x) < (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側  
                    {
                        inside = (!inside);
                    }
                }
            }
            return inside;
        }  

點在多邊形內算法,C#判斷一個點是否在一個復雜多邊形的內部