在查看“CGAL AlphaShape算法提取有序边界”相关博客(例:https://blog.csdn.net/kw123472/article/details/122176426?spm=1001.2014.3001.5501)后发现很多人不知道怎么从CGAL提取的边界散点中提取按顺序排列的边界集合,进而导致新增了“对无序散点进行有序排列”的算法需求,其实CGAL本身就提供了有序的先验信息;
官网实例代码:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Alpha_shape_2.h>
#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/algorithm.h>
#include <fstream>
#include <iostream>
#include <list>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
typedef K::Point_2 Point;
typedef K::Segment_2 Segment;
typedef CGAL::Alpha_shape_vertex_base_2<K> Vb;
typedef CGAL::Alpha_shape_face_base_2<K> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> Tds;
typedef CGAL::Delaunay_triangulation_2<K,Tds> Triangulation_2;
typedef CGAL::Alpha_shape_2<Triangulation_2> Alpha_shape_2;
typedef Alpha_shape_2::Alpha_shape_edges_iterator Alpha_shape_edges_iterator;
template <class OutputIterator>
void alpha_edges( const Alpha_shape_2& A, OutputIterator out)
{
Alpha_shape_edges_iterator it = A.alpha_shape_edges_begin(),
end = A.alpha_shape_edges_end();
for( ; it!=end; ++it)
*out++ = A.segment(*it);
}
template <class OutputIterator>
bool file_input(OutputIterator out)
{
std::ifstream is("data/fin", std::ios::in);
if(is.fail())
{
std::cerr << "unable to open file for input" << std::endl;
return false;
}
int n;
is >> n;
std::cout << "Reading " << n << " points from file" << std::endl;
std::copy_n(std::istream_iterator<Point>(is), n, out);
return true;
}
// Reads a list of points and returns a list of segments
// corresponding to the Alpha shape.
int main()
{
std::list<Point> points;
if(! file_input(std::back_inserter(points)))
return -1;
Alpha_shape_2 A(points.begin(), points.end(),
FT(10000),
Alpha_shape_2::GENERAL);
std::vector<Segment> 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;
return 0;
}
Alpha shape返回的结果都存在segments这个集合里面,通过观察Segment结构体后会发现,这是一个线段,其中存在两个点,线段起点和终点,其实边界顺序就已经知道了;
伪代码如下:
struct point2{
double x;
double y;
}
std::vector<point2> hull;
std::vector<bool> bUse;
bUse.resize(segments.size(),false);
point2 lastPoint;
bool pair =true;
while(pair){
pair=false;
for(int =0;i<segments.size();i++){
if(bUse[i])continue;
point2 begin =point2(segments[i].vector(0).x,segments[i].vector(0).y);
point2 end =point2(segments[i].vector(1).x,segments[i].vector(1).y);
if(i==0){
bUse[i]=true;
hull.push_back(begin);
hull.push_back(end);
lastPoint =end;
pair =true;
break;
}
if(abs(begin.x-lastPoint.x)<0.00001&&abs(begin.y-lastPoint.y)<0.00001){
bUse[i]=true;
hull.push_back(end);
lastPoint =end;
pair =true;
break;
}
if(abs(end.x-lastPoint.x)<0.00001&&abs(end.y-lastPoint.y)<0.00001){
bUse[i]=true;
hull.push_back(begin);
lastPoint =begin;
pair =true;
break;
}
}
}
大致意思就是遍历所有线段将首尾相连,最后得到的hull向量即有序的点集;(纯手撸代码,如有错误还望包涵)
再论“对无序散点进行有序排列”的算法,目前看到最多的是以下策略:
– 先计算所有点的重心,再计算每个点与重心点的极角,进行排序;
这样做对凸多边形有用,但是对于凹多边形,用重心和顶点连线计算的正切值,貌似不一定是有序的!
例如"S"型点集,重心则在外部;
若有好的方法希望不吝赐教;