凸包生成(二分法)

琢磨了几天,终于将二分法凸包生成搞定了。

下图是自己随便绘制的线段,通过这些线段的节点从而计算出一个凸包。

这个图是利用二分法生成的凸包。 

下面将生成凸包的原理以及代码进行介绍:


    /* @接口 生成凸包
     * @参数 Point2dArrray 点集
     * @返回 Point2dArrray 凸包上的点
     * @邮箱 575814050@qq.com
     * @时间 2019年5月29号
     */

Point2dArray convexHull(const Point2dArray &node)
{
    Point2dArray temp = quickSort(node, true);
    DoxPoint2d ptMin = temp.first();
    DoxPoint2d ptMax = temp.last();
    Point2dArray lNode, rNode, ret;
    splitPonins(node, ptMin, ptMax, lNode, rNode);
    ret.append(ptMin); ret.append(convexHull(lNode, ptMin, ptMax));
    ret.append(ptMax); ret.append(convexHull(rNode, ptMax, ptMin));
    return ret;
}

1、首先对传入的点集进行快速排序

2、然后取出最大点ptMax与最小的点ptMin,以这个两个点的连线作为分界线

3、利用向量叉乘原理,分别计算出在线段的左侧以及右侧的点集

4、将最小的点ptMin加到凸包点集中,然后计算左侧点集的凸包

5、将最大的点ptMax加到凸包点集中,然后计算右侧的点集凸包


    /* @接口 计算点集凸包
     * @参数 DoxPoint2d 分界线的起点
     * @参数 DoxPoint2d 分界线的终点
     * @返回 Point2dArrray 凸包上的点集
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 575814050@qq.com
     * @时间 2019年5月29号
     */

Point2dArray convexHull(const Point2dArray &node, const DoxPoint2d &spt, const DoxPoint2d &ept)
{
    Point2dArray lNode, rNode, ret;
    DoxPoint2d tpt = findPolePoint(node, spt, ept);
    splitPonins(node, spt, tpt, lNode, rNode);
    if(lNode.length() == 0) { ret.append(tpt); }
    else ret.append(convexHull(lNode, spt, tpt));

    ret.append(tpt); lNode.clear(); rNode.clear();
    splitPonins(node, tpt, ept, lNode, rNode);
    if(lNode.length() == 0) { ret.append(tpt);}
    else ret.append(convexHull(lNode, tpt, ept));
    return ret;
}

1、计算点集中离分界线最远的点tpt

2、将分界线的起点spt与tpt构成新的分界线

3、然后再点集按照新的分界线进行左右分开

4、如果左边点集中的点的个数为0,那么将最远的点tpt作为凸包上的点加到返回值的点集中,否则继续1-4步

5、将最远的点tpt与分界线终点ept构成新的分界线

6、然后再点集按照新的分界线进行左右分开

7、如果左边点集中的点的个数为0,那么将最远的点tpt作为凸包上的点加到返回值的点集中,否则继续1-6步

下面是一些辅助函数:


    /* @接口 查找点集中里线段的极点(最远或最近)
     * @参数 Point2dArray 点集
     * @参数 DoxPoint2d 线段的起点
     * @参数 DoxPoint2d 线段的终点
     * @返回 DoxPoint2d 找到的点
     * @邮箱 575814050@qq.com
     * @时间 2019年5月30号
     */
DoxPoint2d findPolePoint(const Point2dArray &, const DoxPoint2d &, const DoxPoint2d &, bool Furthest = true);
{
    double val = Furthest ? -9999 : 9999;
    DoxPoint2d pole;
    for(int idx = 0; idx < node.length(); ++idx)
    {
        DoxPoint2d pt = node[idx];
        double temp = fabs(crossMultiply(spt, pt, ept));
        if((Furthest && temp > val) || ((!Furthest) && temp < val))
        {
            pole = pt;
            val = temp;
        }
    }
    return pole;
}

注释:计算的原理是根据三个点构成的面积取最大的。

/* @接口 用两个点将点集进行划分
 * @参数 DoxPoint2d 起点
 * @参数 DoxPoint2d 终点
 * @参数 Point2dArrray 站在起点,看着终点,左边所有的点
 * @参数 Point2dArrray 站在起点,看着终点,右边所有的点
 * @返回 bool 成功返回值为true,否则返回值为false
 * @邮箱 575814050@qq.com
 * @时间 2019年5月30号
 */
void splitPonins(const Point2dArray &node, const DoxPoint2d &spt, const DoxPoint2d &ept, Point2dArray &lNode, Point2dArray &rNode)
{
    for(int idx = 0; idx < node.length(); ++idx)
    {
        DoxPoint2d pt = node[idx];
        double val = crossMultiply(ept, spt, pt);
        if(val > 0) lNode.append(pt);
        else if(val < 0) rNode.append(pt);
    }
}
/* @接口 计算出来是一个面积
 * @参数
 * @参数
 * @参数
 * @返回 大于0:ep在矢量opsp的逆时针方向;
         等于0:opspep三点共线;
         小于0:ep在矢量opsp的顺时针方向
 * @邮箱 575814050@qq.com
 * @时间 2019年5月30号
 */
double crossMultiply(const DoxPoint2d &spt, const DoxPoint2d &mpt, const DoxPoint2d &ept)
{
    DoxPoint2d pt1(spt._x - mpt._x, spt._y - mpt._y);
    DoxPoint2d pt2(ept._x - mpt._x, ept._y - mpt._y);
    return crossMultiply(pt1, pt2);
}
double crossMultiply(const DoxPoint2d &spt, const DoxPoint2d &ept)
{
    return spt._x * ept._y - spt._y * ept._x;
}
 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值