多边形点集排序--针对凸多边形,按逆时针方向进行排序[转]

多边形点集排序--针对凸多边形,按逆时针方向进行排序[转]

 

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 凸多边形选择

原文地址:https://www.cnblogs.com/xiexiaokui/p/3989053.html