多邊形點集排序--針對凸多邊形,按逆時針方向進行排序[轉]


多邊形點集排序--針對凸多邊形,按逆時針方向進行排序[轉]

 

http://www.cnblogs.com/loveclumsybaby/p/3420795.html

原文是C++下的,原文地址:http://www.cnblogs.com/dwdxdy/p/3230156.html

稍微的改了為C#的,呵呵

主要方法:

1 public static void ClockwiseSortPoints(List<Point3D> vPoints)

2 {

3 //計算重心

4 Point3D center = new Point3D();

5 double X = 0, Y = 0;

6 for (int i = 0; i < vPoints.Count; i++) {

7 X += vPoints[i].X;

8 Y += vPoints[i].Y;

9 }

10 center.X = (int)X / vPoints.Count;

11 center.Y = (int)Y / vPoints.Count;

12

13 //冒泡排序

14 for (int i = 0; i < vPoints.Count - 1; i++) {

15 for (int j = 0; j < vPoints.Count - i - 1; j++) {

16 if (PointCmp(vPoints[j], vPoints[j + 1], center)) {

17 Point3D tmp = vPoints[j];

18 vPoints[j] = vPoints[j + 1];

19 vPoints[j + 1] = tmp;

20 }

21 }

22 }

23 }

輔助方法:

1 //若點a大於點b,即點a在點b順時針方向,返回true,否則返回false

2 static bool PointCmp(Point3D a, Point3D b, Point3D center)

3 {

4 if (a.X >= 0 && b.X < 0)

5 return true;

6 if (a.X == 0 && b.X == 0)

7 return a.Y > b.Y;

8 //向量OA和向量OB的叉積

9 int det = Convert.ToInt32((a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y));

10 if (det < 0)

11 return true;

12 if (det > 0)

13 return false;

14 //向量OA和向量OB共線,以距離判斷大小

15 double d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);

16 double d2 = (b.X - center.X) * (b.X - center.Y) + (b.Y - center.Y) * (b.Y - center.Y);

17 return d1 > d2;

18 }

   

【計算幾何】多邊形點集排序

http://www.cnblogs.com/dwdxdy/p/3230156.html

問題描述:已知多邊形點集C={P1,P2,...,PN},其排列順序是雜亂,依次連接這N個點,無法形成確定的多邊形,需要對點集C進行排序后,再繪制多邊形。

點集排序過程中,關鍵在於如何定義點的大小關系。

以按逆時針排序為例,算法步驟如下:

定義:點A在點B的逆時針方向,則點A大於點B

1.計算點集的重心O,以重心作為逆時針旋轉的中心點。

2.計算點之間的大小關系。

大小關系的計算,可由兩種方法進行計算。

方法1

以重心O作一條平行於X軸的單位向量OX,然后依次計算OPiOX的夾角,根據夾角的大小,確定點之間的大小關系。

OPiOX夾角越大,說明點Pi越小,如圖所示。

方法2

根據向量叉積的定義,向量OPiOPj的叉積大於0,則向量OPj在向量OPi的逆時針方向,即點Pj小於點Pi

依據方法2,多邊形點集排序的代碼如下:

1 typedef struct Point

2 {

3 int x;

4 int y;

5 }Point;

6 //若點a大於點b,即點a在點b順時針方向,返回true,否則返回false

7 bool PointCmp(const Point &a,const Point &b,const Point &center)

8 {

9 if (a.x >= 0 && b.x < 0)

10 return true;

11 if (a.x == 0 && b.x == 0)

12 return a.y > b.y;

13 //向量OA和向量OB的叉積

14 int det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);

15 if (det < 0)

16 return true;

17 if (det > 0)

18 return false;

19 //向量OA和向量OB共線,以距離判斷大小

20 int d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);

21 int d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);

22 return d1 > d2;

23 }

24 void ClockwiseSortPoints(std::vector<Point> &vPoints)

25 {

26 //計算重心

27 cv::Point center;

28 double x = 0,y = 0;

29 for (int i = 0;i < vPoints.size();i++)

30 {

31 x += vPoints[i].x;

32 y += vPoints[i].y;

33 }

34 center.x = (int)x/vPoints.size();

35 center.y = (int)y/vPoints.size();

36

37 //冒泡排序

38 for(int i = 0;i < vPoints.size() - 1;i++)

39 {

40 for (int j = 0;j < vPoints.size() - i - 1;j++)

41 {

42 if (PointCmp(vPoints[j],vPoints[j+1],center))

43 {

44 cv::Point tmp = vPoints[j];

45 vPoints[j] = vPoints[j + 1];

46 vPoints[j + 1] = tmp;

47 }

48 }

49 }

50 }

參考資料:

http://blog.csdn.net/beyond071/article/details/5855171

http://stackoverflow.com/questions/6989100/sort-points-in-clockwise-order

 

 

c#凸多邊形算法學習

http://www.cnblogs.com/hopeless/archive/2009/08/03/1537436.html

 #region 凸多邊形選擇
        /********************************************** 
       
尋找凸包的graham 掃描法 
        PointFSet
為輸入的點集; 
        ch
為輸出的凸包上的點集,按照逆時針方向排列
        n
PointFSet中的點的數目 
        len
為輸出的凸包上的點的個數 
        **********************************************/

        const double INF=1E200; 
        const double EP=1E-10;

        // 返回兩點之間歐氏距離 
        public double distance(PointF p1, PointF p2) 
        { 
           return Math.Sqrt( (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y)); 
        } 
        /****************************************************************************** 
        r=multiplY(sp,ep,op),
得到(sp-op)*(ep-op)的叉積 
        r>0:ep
在矢量opsp的逆時針方向; 
        r=0
opspep三點共線; 
        r<0:ep
在矢量opsp的順時針方向 
        *******************************************************************************/ 
        //
叉積就是2向量形成的平行四邊形的面積 
        public double multiplY(PointF sp,PointF ep,PointF op) 
        { 
              return((sp.X-op.X)*(ep.Y-op.Y)-(ep.X-op.X)*(sp.Y-op.Y)); 
        }
        bool cmp(PointF[] points, PointF a, PointF b)
        {
            //
如果三點在同一直線上,那么按相對於points[0]由近到遠排序
            if (multiplY(points[0], a, b) == 0) return distance(points[0], a) < distance(points[0], b);
            //
如果三點不在同一直線上,那么ab->points[0]的左側,也就是從下向上,從右向左排序
            //
按極角有小到大排序。
            else return multiplY(points[0], a, b) > 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="p"></param>
        /// <param name="r"></param>
        /// <returns></returns>
        public int partition(PointF[] a, int p, int r) 
        { 
           int i=p,j=r+1,k; 
           double ang,dis; 
           PointF R,S; 
           k=(p+r)/2;//
防止快排退化 
           R=a[p]; 
           a[p]=a[k]; 
           a[k]=R; 
           R=a[p]; 
           dis=distance(R,a[0]); 
           while(true) 
           { 
              while(true) 
              { 
                 ++i; 
                 if(i>r) 
                 { 
                    i=r; 
                    break; 
                 } 
                 ang=multiplY(R,a[i],a[0]); 
                 if(ang>0) 
                    break; 
                 else if(ang==0) 
                 { 
                    if(distance(a[i],a[0])>dis) 
                       break; 
                 } 
              } 
              while(true) 
              { 
                 --j; 
                 if(j<p) 
                 { 
                    j=p; 
                    break; 
                 } 
                 ang=multiplY(R,a[j],a[0]); 
                 if(ang<0) 
                    break; 
                 else if(ang==0) 
                 { 
                    if(distance(a[j],a[0])<dis) 
                       break; 
                 } 
              } 
              if(i>=j)break; 
              S=a[i]; 
              a[i]=a[j]; 
              a[j]=S; 
           } 
        a[p]=a[j]; 
        a[j]=R; 
        return j; 
        } 
        /// <summary>
        ///
按角度排序
        /// </summary>
        /// <param name="a"></param>
        /// <param name="p"></param>
        /// <param name="r"></param>
        public void anglesort(PointF[] a,int p,int r) 
        { 
           if(p<r) 
           { 
              int q=partition(a,p,r); 
              anglesort(a,p,q-1); 
              anglesort(a,q+1,r); 
           } 
        } 
        /// <summary>
        /// Graham_scan
        /// </summary>
        /// <param name="PointFSet"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public PointF[] Graham_scan(PointF[] PointFSet,int n) 
        {
           
            PointF[] ch = new PointF[n];
            int len;
            int i,k=0,top=2; 
            PointF tmp; 
            //
選取PointFSetY坐標最小的點PointFSet[k],如果這樣的點有多個,則取最左邊的一個 
            for (i = 1; i < n; i++)
            {
                if (PointFSet[i].Y < PointFSet[k].Y || (PointFSet[i].Y == PointFSet[k].Y) && (PointFSet[i].X < PointFSet[k].X))
                {
                    k = i;
                }
            }
            tmp=PointFSet[0];             
            PointFSet[0]=PointFSet[k]; 
            PointFSet[k]=tmp; //
現在PointFSetY坐標最小的點在PointFSet[0]               
            /*
對頂點按照相對PointFSet[0]的極角從小到大進行排序,極角相同 
                         
的按照距離PointFSet[0]從近到遠進行排序 */               
            anglesort(PointFSet,1,n-1);                
            ch[0]=PointFSet[0];                
            ch[1]=PointFSet[1];                
            ch[2]=PointFSet[2];                
            for (i=3;i<n;i++) 
            {                      
                while (multiplY(PointFSet[i],ch[top],ch[top-1])>0) top--;                      
                    ch[++top]=PointFSet[i];                   
            }                
            len=top+1;
            PointF[] temp = new PointF[len];
            for (int j = 0; j < len; j++)
            {
                temp[j] = ch[j];
            }           
            return temp;
        }

        #endregion 凸多邊形選擇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM