CGAL AlphaShape算法提取有序边界

本文介绍了如何利用CGAL库中的Alpha_shape_2类来计算二维点集的Alpha Shape,并通过计算各段端点的重心和正切值排序,得到有序边界。首先构建点集,然后计算Alpha Shape并获取边段,接着计算边段端点的重心,通过正切值排序实现边段的有序化。最后,通过排序后的索引构建有序边界。
摘要由CSDN通过智能技术生成

使用该算法的初衷是想找到一个二维点集的有序边界,调用到CGAL中的Alpha_shape2。但是CGAL中的Alpha_shape2获取到的segment是随机的,也就是各个端点是无序的,如下图:

无序边界点

 而我们需要的是有序边界,如下图所示:

有序边界

/*
1. 计算Alpha_Shape2
2. 获取segment端点坐标存入points_in_segment
3. 计算points_in_segment vector内所有点的重心barycenter
4. 构造aBary vector,aBary[i] = atan2(points_in_segment[i].y - barycenter.y, points_in_segment[i].x - barycenter.x);
5. 对aBary排序
*/

// alpha shape
typedef K::FT                                                FT;
typedef K::Point_2                                           Point2f;
typedef K::Segment_2                                         Segment2f;
typedef CGAL::Alpha_shape_2<Triangulation_2>                 Alpha_shape_2;

std::list<Point2f> points;
//构造输入点集,下略
...
Alpha_shape_2 A(points.begin(), points.end(),
                FTA(10000),
                Alpha_shape_2::GENERAL);
std::vector<Segment2f> segments;
alpha_edges(A, std::back_inserter(segments));
std::cout << "Alpha Shape computed" << std::endl;
std::cout << segments.size() << " alpha shape edges" << std::endl;
std::cout << "Optimal alpha: " << *A.find_optimal_alpha(1) << std::endl;

//获取segment端点坐标
std::vector<Point2f> points_in_segment;
float sumX,sumY = 0.f;
for (auto& seg : segments) {
    Point2f p1 (seg.vertex(0).x(),seg.vertex(0).y());
    points_in_segment.push_back(p1);
    sumX = seg.vertex(0).x() + sumX;
    sumY = seg.vertex(0).y() + sumY;
}
///alpha_shape2的线段结果是无序的  因此后面需要排序
//获取重心坐标
Point2f barycenter(sumX/points_in_segment.size(), sumY/points_in_segment.size());

std::vector<float> aBary;
std::vector<int> aBaryIndex;
aBary.clear();
aBaryIndex.clear();
for (int j = 0; j < points_in_segment.size(); ++j) {
    aBary.push_back(atan2(points_in_segment[j].y() - barycenter.y(), points_in_segment[j].x() - barycenter.x()));//计算每一段segment端点与重心之间的正切值
    aBaryIndex.push_back(j);
}

//对正切值按照降序排序,返回索引vector
aBaryIndex = Utility::sort_indexes_decline(aBary);

//获取有序边界
std::vector<Point2f> polygon;
for (int j = 0; j < aBaryIndex.size(); ++j) {
    polygon.push_back(points_in_segment[aBaryIndex[j]]);
}
/**
* @Description: 按照vector内数值大小进行索引降序排序
* @Param:
* @return: 排序后的索引数组
* @Author: Mr.Zhou
* @Date: 2020/9/25
*/
std::vector<int> sort_indexes_decline(const std::vector<float> &v)
{
    // 初始化索引向量
    std::vector<int> idx(v.size());
    //使用iota对向量赋0~?的连续值
    std::iota(idx.begin(), idx.end(), 0);
    // 通过比较v的值对索引idx进行排序
    sort(idx.begin(), idx.end(),
         [&v](int i1, int i2) {return v[i1] > v[i2]; });
    return idx;
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值