本文转自https://doc.cgal.org/latest/Alpha_shapes_2/index.html。

Introduction


Assume we are given a set S of points in 2D or 3D and we would like to have something like “the shape formed by these points”. This is quite a vague notion and there are probably many possible interpretations, the α-shape being one of them. Alpha shapes can be used for shape reconstruction from a dense unorganized set of data points. Indeed, an α-shape is demarcated by a frontier, which is a linear approximation of the original shape [1].

As mentioned in Edelsbrunner’s and Mücke’s paper [2], one can intuitively think of an α-shape as the following. Imagine a huge mass of ice-cream making up the space R3 and containing the points as “hard” chocolate pieces. Using one of these sphere-formed ice-cream spoons, we carve out all parts of the ice-cream block we can reach without bumping into chocolate pieces, thereby even carving out holes in the inside (e.g. parts not reachable by simply moving the spoon from the outside). We will eventually end up with a (not necessarily convex) object bounded by caps, arcs and points. If we now straighten all “round” faces to triangles and line segments, we have an intuitive description of what is called the α-shape of S. The drawing above provides an example of this process in 2D (where our ice-cream spoon is simply a circle).

Alpha shapes depend on a parameter α after which they are named. In the ice-cream analogy above, α is the squared radius of the carving spoon. A very small value will allow us to eat up all of the ice-cream except the chocolate points themselves. Thus we already see that the α-shape degenerates to the point-set S for α→0. On the other hand, a huge value of α will prevent us even from moving the spoon between two points since it is too large. So we will never spoon up the ice-cream lying in the inside of the convex hull of S. Hence, the alpha shape becomes the convex hull of S as α→∞.

CGAL offers 2D and 3D alpha shapes. The GUDHI library offers a dD Alpha complex.

Definitions

We distinguish two versions of alpha shapes. Basic alpha shapes are based on the Delaunay triangulation. Weighted alpha shapes are based on its generalization, the regular triangulation (cf. Section Regular Triangulations), replacing the euclidean distance by the power to weighted points.

There is a close connection between alpha shapes and the underlying triangulations. More precisely, the α-complex of S is a subcomplex of this triangulation of S, containing the α-exposed k-simplices, 0≤k≤d. A simplex is said to be α-exposed, if there is an open disk (resp. ball) of radius α\sqrt\alphaα​ through the vertices of the simplex that does not contain any other point of S, for the metric used in the computation of the underlying triangulation. The corresponding α-shape is defined as the underlying interior space of the α-complex (see [2]).

In general, an α-complex is a non-connected and non-pure polytope, meaning that one k-simplex, with 0≤k≤d−1, is not necessarily adjacent to a (k+1)-simplex.

The α-shapes of S form a discrete family, even though they are defined for all real numbers α with 0≤α≤∞. Thus, we can represent the entire family of α-shapes of S by the underlying triangulation of S. In this representation each k-simplex of the underlying triangulation is associated with an interval that specifies for which values of α the k-simplex belongs to the α-shape. Relying on this fact, the family of α-shapes can be computed efficiently and relatively easily. Furthermore, we can select an appropriate α-shape from a finite number of different α-shapes and corresponding α-values.

Functionality

The class Alpha_shape_2

represents the family of α-shapes of points in a plane for all positive α. It maintains the underlying triangulation Dt which represents connectivity and order among squared radius of its faces. Each k-dimensional face of the Dt is associated with an interval that specifies for which values of α the face belongs to the α-shape. There are links between the intervals and the k-dimensional faces of the triangulation.

The class Alpha_shape_2

provides functions to set and get the current α-value, as well as an iterator that enumerates the α-values where the α-shape changes.

It provides iterators to enumerate the vertices and edges that are in the α-shape, and functions that allow to classify vertices, edges and faces with respect to the α-shape. They can be in the interior of a face that belongs or does not belong to the α-shape. They can be singular/regular, that is be on the boundary of the α-shape, but not incident/incident to a triangle of the α-complex.

Finally, it provides a function to determine the α-value such that the α-shape satisfies the following two properties, or at least the second one if there is no such α that both are satisfied:
the number of components equals a number of your choice, and
all data points are either on the boundary or in the interior of the regularized version of the α-shape (no singular edges).
The current implementation is static, that is after its construction points cannot be inserted or removed.

Concepts and Models

We currently do not specify concepts for the underlying triangulation type. Models that work for a basic alpha shape are the classes Delaunay_triangulation_2, Periodic_2_Delaunay_triangulation_2, and Triangulation_hierarchy_2 templated with a Delaunay triangulation. A model that works for a weighted alpha shape is the class Regular_triangulation_2.

1. Alpha Shapes

The triangulation needs a geometric traits class as argument. The requirements of this class are described in the concepts AlphaShapeTraits_2 in the non-weighted case and WeightedAlphaShapeTraits_2 in the weighted case. All CGAL kernels are models of both concepts.

The triangulation data structure of the triangulation has to be a model of the concept TriangulationDataStructure_2, whose vertex and face classes are models of the concepts AlphaShapeVertex_2 and AlphaShapeFace_2, respectively. The classes Alpha_shape_vertex_base_2<Gt, Vb> and Alpha_shape_face_base_2<Gt, Fb> are models of these concepts and can be used for all type of alpha shapes, provided that the template parameters Vb and Fb are appropriately chosen, as we shall see in the following section.

2. Triangulation data structure

Additional requirements are put when using weighted or periodic triangulations as underlying triangulation:

When using a weighted triangulation (Regular_triangulation_2), the vertex and face classes must respectively be models to both AlphaShapeVertex_2 and RegularTriangulationVertexBase_2, and to both AlphaShapeFace_2 and RegularTriangulationFaceBase_2 (see example: Example for Weighted Alpha Shapes).
When using a periodic triangulation (Periodic_2_Delaunay_triangulation_2), the vertex and face classes must respectively be models to both AlphaShapeVertex_2 and Periodic_2TriangulationVertexBase_2, and to both AlphaShapeFace_2 and Periodic_2TriangulationFaceBase_2 (see example: Example for Periodic Alpha Shapes).

Examples

1. Example for Basic Alpha Shapes

The basic alpha shape requires a Delaunay triangulation as underlying triangulation Dt. The Delaunay triangulation class is parameterized with a geometric and a triangulation data structure traits.

For the geometric traits class we can use a CGAL kernel.

For the triangulation data structure traits, we have to choose the vertex and face classes needed for alpha shapes, namely Alpha_shape_vertex_base_2<Gt, Vb> and Alpha_shape_face_base_2<Gt,Fb>. The parameter Vb and Fb must be filled by classes that are models of the TriangulationVertexBase_2 and TriangulationFaceBase_2 concepts. The classes Triangulation_vertex_base_2 and Triangulation_face_base_2 fit these requirements.

The example below illustrates how to construct a basic alpha shape. Note that Triangulation_vertex_base_2 and Triangulation_face_base_2 are the default parameters for Vb and Fb in the classes Alpha_shape_vertex_base_2<Gt, Vb> and Alpha_shape_face_base_2<Gt,Fb>. They are thus omitted in the code below.
File Alpha_shapes_2/ex_alpha_shapes_2.cpp

#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 <CGAL/assertions.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;
}

2. Example for Weighted Alpha Shapes

A weighted alpha shape requires a regular triangulation as underlying triangulation Dt. Here again, we can use the vertex and face Alpha_shape_vertex_base_2<Gt, Vb> and Alpha_shape_face_base_2<Gt,Fb>, but for weighted alpha shapes, Vb and Fb must be models of the concepts RegularTriangulationVertexBase_2 and RegularTriangulationFaceBase_2. The classes Regular_triangulation_vertex_base_2 Regular_triangulation_face_base_2 fit these requirements.

Note that there is no special weighted alpha shape class.

The example below illustrates how to construct a weighted alpha shape.
File Alpha_shapes_2/ex_weighted_alpha_shapes_2.cpp

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Alpha_shape_2.h>
#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Regular_triangulation_2.h>
#include <fstream>
#include <iostream>
#include <list>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT                                               FT;
typedef K::Weighted_point_2                                 Weighted_point;
typedef K::Segment_2                                        Segment;
typedef CGAL::Regular_triangulation_vertex_base_2<K>        Rvb;
typedef CGAL::Alpha_shape_vertex_base_2<K,Rvb>              Vb;
typedef CGAL::Regular_triangulation_face_base_2<K>          Rf;
typedef CGAL::Alpha_shape_face_base_2<K,Rf>                 Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb>         Tds;
typedef CGAL::Regular_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);
}
bool file_input(std::list<Weighted_point>& L)
{std::ifstream is("./data/fin_weighted", 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" << std::endl;for( ; n>0; n--){Weighted_point wp;is >> wp;L.push_back(wp);}return true;
}
// Reads a list of points and returns a list of segments corresponding to
// the weighted Alpha Shape.
int main()
{std::list<Weighted_point> wpoints;if(!file_input(wpoints))return -1;Alpha_shape_2 A(wpoints.begin(), wpoints.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;
}

3. Example for Periodic Alpha Shapes

The following example shows how to use a periodic Delaunay triangulation as underlying triangulation for the alpha shape computation.

In order to define the original domain and to benefit from the built-in heuristic optimizations of the periodic triangulation computation, it is recommended to first construct the triangulation and then construct the alpha shape from it. The alpha shape constructor that takes a point range can be used as well but in this case the original domain cannot be specified and the default unit cube will be chosen and no optimizations will be used.

It is also recommended to switch the triangulation to 1-sheeted covering if possible. Note that a periodic triangulation in 9-sheeted covering space is degenerate. In this case, an exact constructions kernel needs to be used to compute the alpha shapes. Otherwise the results will suffer from round-off problems.

File Alpha_shapes_2/ex_periodic_alpha_shapes_2.cpp

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Periodic_2_Delaunay_triangulation_traits_2.h>
#include <CGAL/Periodic_2_Delaunay_triangulation_2.h>
#include <CGAL/Alpha_shape_2.h>
#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <fstream>
#include <iostream>
// Traits
typedef CGAL::Exact_predicates_inexact_constructions_kernel     K;
typedef CGAL::Periodic_2_Delaunay_triangulation_traits_2<K>     Gt;
// Vertex type
typedef CGAL::Periodic_2_triangulation_vertex_base_2<Gt>        Vb;
typedef CGAL::Alpha_shape_vertex_base_2<Gt, Vb>                 AsVb;
// Cell type
typedef CGAL::Periodic_2_triangulation_face_base_2<Gt>          Cb;
typedef CGAL::Alpha_shape_face_base_2<Gt, Cb>                   AsCb;
typedef CGAL::Triangulation_data_structure_2<AsVb, AsCb>        Tds;
typedef CGAL::Periodic_2_Delaunay_triangulation_2<Gt, Tds>      P2DT2;
typedef CGAL::Alpha_shape_2<P2DT2>                              Alpha_shape_2;
typedef Gt::Point_2                                             Point;
typedef Gt::Segment_2                                           Segment;
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;
}
int main()
{std::list<Point> points;if(! file_input(std::back_inserter(points)))return -1;// Define the periodic squareP2DT2 pdt(Gt::Iso_rectangle_2(-10,-10, 700,700));// Heuristic for inserting large point sets (if pts is reasonably large)pdt.insert(points.begin(), points.end(), true);// As pdt won't be modified anymore switch to 1-sheeted cover if possibleif(pdt.is_triangulation_in_1_sheet())pdt.convert_to_1_sheeted_covering();std::cout << "Periodic Delaunay computed." << std::endl;// compute alpha shapeAlpha_shape_2 as(pdt);std::cout << "Alpha shape computed in REGULARIZED mode by default." << std::endl;// find optimal alpha valuesAlpha_shape_2::NT alpha_solid = as.find_alpha_solid();Alpha_shape_2::Alpha_iterator opt = as.find_optimal_alpha(1);std::cout << "Smallest alpha value to get a solid through data points is " << alpha_solid << std::endl;std::cout << "Optimal alpha value to get one connected component is " <<  *opt    << std::endl;as.set_alpha(*opt);assert(as.number_of_solid_components() == 1);as.set_alpha(10000);std::vector<Segment> segments;alpha_edges(as, std::back_inserter(segments));std::cout << segments.size() << " alpha shape edges" << std::endl;return 0;
}

CGAL 凹包(alpha-Shape)相关推荐

  1. 二维点集求外轮廓Java_从二维点集重建平面形状-浅议凹包算法

    问题背景 近期遇到一个计算几何问题,需要从点集中重建一个合理的几何形状.这个问题既有二维的也有三维的,二维的情况相对简单一点,即给出平面区域的一系列散点,求出一定程度上反映这些散点轮廓的平面多边形,给 ...

  2. matlab 凹包,二维点集凹包算法介绍

    最近遇到一个求二维点集凹包的问题,凹包的叫法不知道是否准确,问题可以描述为:(原文下载在文章末尾) 在二维平面上有一系列的点,求能包围所有点集的二维多边形.(好像搜"离散点边界"或 ...

  3. PCL计算ConvexHull凸包、ConcaveHull凹包

    凸包凹包的概念详见 凹凸包 凸包 凹包 下面附上代码: #include <pcl/io/pcd_io.h> #include <pcl/io/vtk_io.h> #inclu ...

  4. 计算点云的二维面积(凹包面积计算、平面旋转)

    计算点云面积时,cloud compare采取的策略是将点云网格化,然后计算网格面积.这样构网的情况往往会影响到后续面积的计算精度.这里采取了一种凹包面积计算的策略.主要步骤包括: 1.将点云旋转至与 ...

  5. 凸包+凹包+凸边凹化算法

    时针法 一.凸包:最大面积边界->外围边界 离散点建立最小外围边界即凸多边形,如下图所示,离散点建立凸包过程 思路: step1:找到最外围的一个初始边界点A(Xa,Ya),存入边界点集合 st ...

  6. 基于点云凸包的凹包获取方法

    文章目录 一.简介 二.实现代码 三.实现效果 参考文献 一.简介 因为受到参考文献[1]的启发,所以尝试着在三维凸包的基础上,通过去除较大面积的三角面片来得到一个凹包(这里我们是通过指定一个面积阈值 ...

  7. 过滤三角网算法求取凹包(二)

    文章目录 一.原理概述 二.代码实现 三.实现效果 参考文献 一.原理概述 之前写过一篇文章过滤三角网算法求取凹包,但是这个方法当时编写的有问题,后面自己又重新修改了一下,过程仍然和之前的过程相同: ...

  8. 轮廓提取之滚球法、凹包算法

    提示:本文章主要介绍轮廓提取算法------滚球法的运用,可用于提取点云等二维.三维数据的轮廓,以及代码框架设计. 文章目录 前言 一.基于二维点数据的模型轮廓提取算法 1.1 适用场景 1.2 问题 ...

  9. R语言epiDisplay包alpha函数计算dataframe数据中指定数据列之间的信度分析、克朗巴哈系数、标准化系数、每剔除某一条目后系数的变化、var.labels.trunc参数指定字符串长度

    R语言使用epiDisplay包的alpha函数计算dataframe数据中指定数据列之间的信度分析.克朗巴哈系数(Cronbach's α).标准化系数.每当剔除某一条目后系数的变化.使用var.l ...

最新文章

  1. Redis持久化存储详解(一)
  2. C++11 并发指南一(C++11 多线程初探)
  3. SPOJ Finding Fractions
  4. 4、python简单线性回归代码案例(完整)_python 实现一个简单的线性回归案例
  5. C++程序设计方法3:类中的静态成员
  6. tp cli模式产生日志导致web环境写入不了
  7. mac:装机软件汇总
  8. 老铁的IT之路,从迷茫“愤青”到团队项目经理,他是如何一步步走出来的?!
  9. redis的基本命令
  10. 计算机休眠唤醒后没声音,MacBook Pro从睡眠模式中唤醒后突然没有声音
  11. 计算机检测不到蓝牙,图解Win10 1809系统中检测不到蓝牙设备的方法
  12. Do带你解析:原生APP与web APP的区别
  13. 苏州市软件行业协会第五届第四次理事会暨元宇宙专委会成立决议会在苏召开
  14. UnityHub 无需登录 傻瓜教程 一键搞定
  15. 极智开发 | ubuntu 安装有线网卡驱动
  16. 解决RK3328 RealTek 8822CS检测不到WIFI模块问题
  17. js 创建标签 追加标签
  18. redis存值后取出却为空(null)
  19. 《计算机网络(第七版)》谢希仁——网络安全
  20. java 生成印章源码_java代码生成指定的公章和私章,并且解决服务器不能回显文字的问题...

热门文章

  1. Http请求:Google调用本地摄像头权限开启
  2. python常见的问题
  3. Python零基础入门学习笔记(一)
  4. 如何通过脚本开发Android
  5. 一起学时序分析之延迟与时钟偏斜和抖动
  6. 解决office因存在32位,无法安装64位的问题
  7. debian linux win7,win7debian双系统
  8. 微信群很多怎么管理?针对这个问题,今天教你几招。
  9. Planetary Computer——Global Flood Maps全球洪水数据集
  10. 散论陈寅恪先生《对科学院的答复》