2D 凸包-2D Convex Hulls
本章描述了CGAL
中用于生成二维凸包的函数,以及用于检查点集是否为强凸的函数。还有许多用于计算特殊极值点和包点子序列的函数,如一组点的下包和上包。
CGAL
提供了几种经典算法的实现,用于计算二维点集的逆时针极值点序列(即凸包上的逆时针极值点序列)。这两种算法的渐近运行时间不同,所需的几何基元集也略有不同。因此,可以选择最适合设置的算法。
点序列(数组)的凸包
有一个包含5个点的数组作为输入。由于这些点的凸包是输入的子集,因此可以提供一个大小相同的数组来存储结果。
#include <iostream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
int main()
{
Point_2 points[5] = { Point_2(0,0), Point_2(10,0), Point_2(10,10), Point_2(6,5), Point_2(4,1) };
Point_2 result[5];
Point_2 *ptr = CGAL::convex_hull_2( points, points+5, result );
std::cout << ptr - result << " points on the convex hull:" << std::endl;
for(int i = 0; i < ptr - result; i++){
std::cout << result[i] << std::endl;
}
return 0;
}
点向量(vector)的凸包
将内置数组替换为标准模板库中的 std::vector
。
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
typedef std::vector<Point_2> Points;
int main()
{
Points points, result;
points.push_back(Point_2(0,0));
points.push_back(Point_2(10,0));
points.push_back(Point_2(10,10));
points.push_back(Point_2(6,5));
points.push_back(Point_2(4,1));
CGAL::convex_hull_2( points.begin(), points.end(), std::back_inserter(result) );
std::cout << result.size() << " points on the convex hull" << std::endl;
return 0;
}
拓展到三维数据点
计算投影到 yz
平面上的三维点的凸包。使用 Projection_traits_yz_3
类是对前一个示例的一个小修改。
#include <iostream>
#include <iterator>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Projection_traits_yz_3.h>
#include <CGAL/convex_hull_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K3;
typedef CGAL::Projection_traits_yz_3<K3> K;
typedef K3::Point_3 Point_3;
int main()
{
Point_3 points[5] = { Point_3(0,0,0), Point_3(0,10,0), Point_3(0,10,10), Point_3(0,6,5),Point_3(0,4,1) };
std::ostream_iterator< Point_3 > output(std::cout, "\n");
CGAL::convex_hull_2(points, points+5, output, K());
return 0;
}
使用Graham-Andrew算法的示例
在下面的示例中,使用 Graham_Andrew
算法构建凸包。得到的凸多边形显示在标准输出控制台。将函数 ch_graham_andrew()
替换为其他函数,如 ch_bykat()
,也可以得到相同的结果。
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/ch_graham_andrew.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
int main()
{
std::vector<Point_2> input = { Point_2(0, 0), Point_2(1,1), Point_2(2,0), Point_2(2,2), Point_2(1,2), Point_2(0,2) };
std::ostream_iterator< Point_2 > out(std::cout, "\n");
CGAL::ch_graham_andrew(input.begin(), input.end(), out);
return 0;
}
其中,Point_2(1,1)
在内部,Point_2(1,2)
共线。
使用属性映射的示例
在下面的例子中,我们有一个点向量作为输入,我们检索凸包上点的索引。凸包函数的第四个参数是一个必须为 ConvexHullTraits_2
概念模型的traits类。它提供了诸如定向测试之类的谓词。类 Convex_hull_traits_adapter_2
结合a Pointer_property_map
,就是这样的模型。索引 i
就是“点”,适配器执行 points[i]
上的谓词。
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
#include <CGAL/Convex_hull_traits_adapter_2.h>
#include <CGAL/property_map.h>
#include <vector>
#include <numeric>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
typedef CGAL::Convex_hull_traits_adapter_2<K,
CGAL::Pointer_property_map<Point_2>::type > Convex_hull_traits_2;
int main()
{
std::vector<Point_2> points = { Point_2(10,0),
Point_2(10,0),
Point_2(0,10),
Point_2(1,1),
Point_2(3,4),
Point_2(0,0),
Point_2(10,10),
Point_2(2,6) };
std::vector<std::size_t> indices(points.size()), out;
std::iota(indices.begin(), indices.end(), 0);
CGAL::convex_hull_2(indices.begin(), indices.end(), std::back_inserter(out),
Convex_hull_traits_2(CGAL::make_property_map(points)));
for (std::size_t i : out) {
std::cout << "points[" << i << "] = " << points[i] << std::endl;
}
return 0;
}
输出凸包点的索引。
凸性检查
is_ccw_strongly_convex_2()
和 is_cw_strongly_convex_2()
函数用于检测给定的二维点序列是否构成逆时针或顺时针强凸多边形。它们用于二维凸包函数的后置条件测试。
如果你想保持共线点,可以使用2D Delaunay
三角剖分,如下面的例子所示。这个序列不是强凸的。
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <list>
#include <iostream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point_2;
typedef CGAL::Delaunay_triangulation_2<K> Delaunay_triangulation_2;
int main()
{
std::vector<Point_2> input = { Point_2(0, 0), Point_2(1,1), Point_2(2,0), Point_2(2,2), Point_2(1,2), Point_2(0,2) };
Delaunay_triangulation_2 dt(input.begin(), input.end());
std::list<Point_2> result;
Delaunay_triangulation_2::Vertex_circulator vc = dt.incident_vertices(dt.infinite_vertex());
Delaunay_triangulation_2::Vertex_circulator done(vc);
do{
std ::cout << vc->point() << std::endl;
// push_front in order to obtain the counterclockwise sequence
result.push_front(vc->point());
++vc;
}while(vc != done);
return 0;
}
使用2D Delaunay
三角剖分,输出凸包点,逆时针打印凸包点。
参考及相关链接
- https://doc.cgal.org/latest/Convex_hull_2/index.html#Chapter_2D_Convex_Hulls_and_Extreme_Points
- https://blog.csdn.net/mrbaolong/article/details/141713098?spm=1001.2014.3001.5501
- https://juejin.cn/post/7409866963981451299