hopeless

导航

c#凸多边形算法学习

 #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);
            //如果三点不在同一直线上,那么a在b->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;
            // 选取PointFSet中Y坐标最小的点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; // 现在PointFSet中Y坐标最小的点在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 凸多边形选择

posted on 2009-08-03 11:58  hopeless  阅读(1393)  评论(0编辑  收藏  举报