[图形学]凸包生成附C++实现

凸包(Convex Hull)是一个计算几何(图形学)中的概念,简单的来说就是对于一个给定的点集,我们需要求得一个凸多边形把给定的点集全部包含起来。

先附上我的结果

如上图可以看到用绿色的线连成的一个凸多边形,就是一个凸包,它包含点集中所有的点。

一、算法流程

1、求出点集中满足min(x-y)、min(x+y)、max(x-y)、max(x+y)的四个点,并按逆时针(或者顺时针)方向组成一个点的链表。这4个点是离散点中与包含离散点的外接矩形的4个角点最近的点。这4个点构成的多边形作为初始凸包。

2、对于每个凸包上的点I和他的后续点为J,计算矢量线段IJ右侧的所有点到IJ的距离(若顺时针链表则计算左侧的点),求出距离最大的点K。

3、若存在K,则将K插入I到I之后 、J之前, 并将K赋给J(即更新矢量线段IJ = IK)。

4、重复2、3步,直到点集中没有在线段IJ右侧的点为止。

5、将J赋给I,J取其后续点,重复2、3、4步。

6、当凸包中任意相邻两点连线的右侧不存在离散点时,结束点集凸包求取过程。

二、我的实现

void ConvexHull::generateHull(Vector<Point> pts)
{
    List<Point> othpts; 
    List<Point> hullpts; //保存凸包点的位置
    for(int i =0; i< pts.size(); i++)
    {
        othpts.push_back(pts[i]);
    }
    //求出如下四点:min(x-y)、min(x+y)、max(x-y)、max(x+y)并顺次放入一个数组,组成初始凸包,这里构建一个顺时针凸包
    Sort::quickSort(pts,0,pts.size()-1,cmpXsubY);

    hullpts.push_back(pts[0]);
    hullpts.push_back(pts[pts.size()-1]);
    othpts.removeOne(pts[0]);
    othpts.removeOne(pts[pts.size()-1]);
    Sort::quickSort(pts,0,pts.size()-1,cmpXandY);
    if(!hullpts.contains(pts[0]))
    {
        hullpts.insert(1,pts[0]);
    }
    if(!hullpts.contains(pts[pts.size()-1]))
    {
        hullpts.push_back(pts[pts.size()-1]);
    }
   
    for( int i =0; i< hullpts.size();i++)
    {
        hullpts[i].print();
    }
    othpts.removeOne(pts[0]);
    othpts.removeOne(pts[pts.size()-1]);
    int i = 0;
   

    while(i<hullpts.size())  //遍历全部凸包
    {
        Line cline;//取凸包的一条线
        if(i == hullpts.size() -1 ) //最后一个点,连接第一个点
        {
            cline.init(hullpts[i],hullpts[0]);
        }else
        {
             cline.init(hullpts[i],hullpts[i+1]);
        }
        float maxdis = 0;
        bool over = true;
        int maxdisIndex = 0;

        for( int m = 0; m< othpts.size(); m++)
        {
            if(IsRightPoint(othpts[m],cline))  //这里注意,本应该是在左侧寻找,但是我使用的屏幕中的坐标系(y轴朝下),因此要做一个转换
            {
                float dist = PointToLine(othpts[m],cline); //点到直线的距离

                if(dist > maxdis)
                {
                    maxdis = dist;
                    maxdisIndex = m;
                    over =false; //有外侧点,就不结束,
                }
            }
        }
        if(over == true) //结束,下次迭代则去找凸包的下一个线
        {
            i++;
        }else{// 不结束,下次迭代仍然在i点开始,不过下一个点会更新成外侧距离最大点位置
            hullpts.insert(i+1,othpts[maxdisIndex]);
            over = true;
        }

    }

}

猜你喜欢

转载自blog.csdn.net/qq_31804159/article/details/81432847