zoukankan      html  css  js  c++  java
  • 多边形点集排序--针对凸多边形,按逆时针方向进行排序[转]

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

     

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

  • 相关阅读:
    Linux getcwd()的实现【转】
    关于__GNU_SOURCE 这个宏---如何开启【转】
    UBI 文件系统移植 sys 设备信息【转】
    Linux USB驱动框架分析【转】
    局部变量、全局变量、堆、堆栈、静态和全局【转】
    C语言字节对齐问题详解【转】
    usb驱动的基本结构和函数简介【转】
    makefile函数集锦【转】
    非常好!!!Linux源代码阅读——内核引导【转】
    JQuery日记6.9 Promise/A之Callbacks
  • 原文地址:https://www.cnblogs.com/xiexiaokui/p/3989053.html
Copyright © 2011-2022 走看看