CGAL笔记之凸包算法—3D凸包

CGAL笔记之凸包算法—3D凸包

  • 1 介绍
  • 2 静态凸壳结构
    • 2.1 特性类
      • 2.1.1 示例
      • 2.1.2 低维结果示例
    • 2.2 极值点
    • 2.3 半空间交集
      • 2.3.1 例子
    • 2.4 凸性检查
  • 3 动态凸包构造
    • 3.1 示例


1 介绍

本章描述了 CGAL 中提供的用于在三个维度上生成凸包的函数,以及用于检查点集是否为强凸包的函数。在 CGAL 中,可以通过两种方式计算三维点集的凸包:使用静态算法或使用三角剖分来获得完全动态的计算。

CGAL笔记之凸包算法—3D凸包_第1张图片

2 静态凸壳结构

函数convex_hull_3()提供了quickhull算法的实现。这个函数有两个版本,一个可以在已知输出将是一个多面体(即,有三个以上的点,并且它们不都是共线的)时使用,另一个可以处理所有退化情况并返回一个Object,它可能是一个点、一个段、一个三角形或一个多面体。这两个版本都接受一系列输入迭代器,定义要计算凸包的点集,以及定义计算中使用的几何类型和谓词的trait类。

2.1 特性类

该函数convex_hull_3()由特征类参数化,特征类指定要在计算中使用的类型和几何图元。由于函数从三个输入点构造 3D 平面,我们不能简单地将具有不精确构造的内核作为特征类的可选参数传递。

Convex_hull_traits_3如果使用来自具有精确谓词和非精确构造的内核的输入点,并且期望得到经过验证的结果,则应使用该类(R作为输入内核)。如果来自内核的构造是准确的,则该内核可以直接用作特征类。

请注意,默认特征类会考虑到这一点,即上述注意事项仅对自定义特征类很重要。

2.1.1 示例

以下程序从输入文件中读取点并计算它们的凸包。我们假设点不完全相同且不共线,因此我们直接使用多面体作为输出。在示例中,您看到凸包函数可以写入概念的任何模型MutableFaceGraph

#include 
#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel  K;
typedef CGAL::Polyhedron_3<K>                     Polyhedron_3;
typedef K::Point_3                                Point_3;
typedef CGAL::Surface_mesh<Point_3>               Surface_mesh;
int main(int argc, char* argv[])
{
  std::ifstream in( (argc>1)? argv[1] : CGAL::data_file_path("points_3/cube.xyz"));
  std::vector<Point_3> points;
  Point_3 p;
  while(in >> p){
    points.push_back(p);
  }
  // define polyhedron to hold convex hull
  Polyhedron_3 poly;
  // compute convex hull of non-collinear points
  CGAL::convex_hull_3(points.begin(), points.end(), poly);
  std::cout << "The convex hull contains " << poly.size_of_vertices() << " vertices" << std::endl;
  Surface_mesh sm;
  CGAL::convex_hull_3(points.begin(), points.end(), sm);
  std::cout << "The convex hull contains " << num_vertices(sm) << " vertices" << std::endl;
  return 0;
}

2.1.2 低维结果示例

以下程序从输入文件中读取点并计算它们的凸包。根据结果的维度,我们将得到一个点、一个线段、一个三角形或一个多面体表面。请注意,后者也可以是带边框的平面多边形。

#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel  K;
typedef CGAL::Polyhedron_3<K>                     Polyhedron_3;
typedef K::Point_3                                Point_3;
typedef K::Segment_3                              Segment_3;
typedef K::Triangle_3                             Triangle_3;
int main(int argc, char* argv[])
{
  std::ifstream in( (argc>1)? argv[1] : CGAL::data_file_path("points_3/cube.xyz"));
  std::vector<Point_3> points;
  Point_3 p;
  while(in >> p){
    points.push_back(p);
  }
  CGAL::Object obj;
  // compute convex hull of non-collinear points
  CGAL::convex_hull_3(points.begin(), points.end(), obj);
  if(const Point_3* p = CGAL::object_cast<Point_3>(&obj)){
    std::cout << "Point " << *p << std::endl;
  }
  else if(const Segment_3* s = CGAL::object_cast<Segment_3>(&obj)){
    std::cout << "Segment " << *s << std::endl;
  }
  else if(const Triangle_3* t = CGAL::object_cast<Triangle_3>(&obj)){
    std::cout << "Triangle " << *t << std::endl;
  }
  else  if(const Polyhedron_3* poly = CGAL::object_cast<Polyhedron_3>(&obj)){
    std::cout << "Polyhedron\n " << *poly << std::endl;
  std::cout << "The convex hull contains " << poly->size_of_vertices() << " vertices" << std::endl;
  }
  else {
    std::cout << "something else"<< std::endl;
  }
  return 0;
}

2.2 极值点

除了该convex_hull_3()函数之外,还提供了该函数extreme_points_3()以防只需要凸包上的点(没有连接信息)。此外,CGAL::Extreme_points_traits_adapter_3还提供了 traits 类适配器,以便获取索引或更普遍地获取与凸包上的 3D 点相关联的任何给定实体。

以下程序从 OFF 文件中读取一组点并输出凸包上的点的索引。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel      K;
typedef K::Point_3                                               Point_3;
int main(int argc, char* argv[])
{
  const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/star.off");
  std::vector<Point_3> points;
  if(!CGAL::IO::read_points(filename, std::back_inserter(points)))
  {
    std::cerr<< "Cannot open input file." <<std::endl;
    return 1;
  }
  //This will contain the extreme vertices
  std::vector<std::size_t> extreme_point_indices;
  //call the function with the traits adapter for vertices
  CGAL::extreme_points_3(CGAL::make_range(boost::counting_iterator<std::size_t>(0),
                                          boost::counting_iterator<std::size_t>(points.size())),
                         std::back_inserter(extreme_point_indices),
                         CGAL::make_extreme_points_traits_adapter(CGAL::make_property_map(points)));
  //print the number of extreme vertices
  std::cout << "Indices of points on the convex hull are:\n";
  std::copy(extreme_point_indices.begin(), extreme_point_indices.end(), std::ostream_iterator<std::size_t>(std::cout, " "));
  std::cout << "\n";
  return 0;
}

以下程序从 OFF 文件读取并构建网格,然后收集网格凸包上的顶点。

#include 
#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel      K;
typedef K::Point_3                                               Point_3;
typedef CGAL::Surface_mesh<Point_3>                              Mesh;
int main(int argc, char* argv[])
{
  const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/star.off");
  Mesh sm;
  if(!CGAL::IO::read_polygon_mesh(filename, sm))
  {
    std::cerr<< "Cannot open input file." <<std::endl;
    return 1;
  }
  //This will contain the extreme vertices
  std::vector<Mesh::Vertex_index> extreme_vertices;
  //call the function with the traits adapter for vertices
  CGAL::extreme_points_3(vertices(sm), std::back_inserter(extreme_vertices),
                         CGAL::make_extreme_points_traits_adapter(sm.points()));
  //print the number of extreme vertices
  std::cout << "There are  " << extreme_vertices.size() << " extreme vertices in this mesh." << std::endl;
  return 0;
}

2.3 半空间交集

函数halfspace_intersection_3()halfspace_intersection_with_constructions_3()使用凸包算法和对偶性来计算半空间列表的交集。第一个版本没有明确计算对偶点:特征类处理这个问题。第二个构建这些点,因此鲁棒性较差,但计算速度更快。

为了计算交点,需要一个内点。它可以由用户给出或使用线性规划计算。请注意,由于线性程序的分辨率,第二种方法较慢。

2.3.1 例子

以下示例计算由切平面定义的半空间与球体的交集。

#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel   K;
typedef K::Plane_3                                            Plane;
typedef K::Point_3                                            Point;
typedef CGAL::Surface_mesh<Point>                             Surface_mesh;
// compute the tangent plane of a point
template <typename K>
typename K::Plane_3 tangent_plane (typename K::Point_3 const& p) {
    typename K::Vector_3 v(p.x(), p.y(), p.z());
    v = v / sqrt(v.squared_length());
    typename K::Plane_3 plane(v.x(), v.y(), v.z(), -(p - CGAL::ORIGIN) * v);
    return plane;
}
int main (void) {
    // number of generated planes
    int N = 200;
    // generates random planes on a sphere
    std::list<Plane> planes;
    CGAL::Random_points_on_sphere_3<Point> g;
    for (int i = 0; i < N; i++) {
        planes.push_back(tangent_plane<K>(*g++));
    }
    // define polyhedron to hold the intersection
    Surface_mesh chull;
    // compute the intersection
    // if no point inside the intersection is provided, one
    // will be automatically found using linear programming
    CGAL::halfspace_intersection_3(planes.begin(),
                                   planes.end(),
                                   chull );
    std::cout << "The convex hull contains " << num_vertices(chull) << " vertices" << std::endl;
    return 0;
}

2.4 凸性检查

该函数实现了 Mehlhorn等人is_strongly_convex_3()的算法。判断给定多面体的顶点是否构成强凸点集。此函数用于. convex_hull_3()

3 动态凸包构造

使用类可以实现凸包的完全动态维护Delaunay_triangulation_3。这个类支持插入和删除点(,三角剖分的顶点)和凸包边只是无限面的有限边。以下示例说明了凸包的动态构造。首先,生成来自特定半径球体的随机点并将其插入到三角剖分中。然后通过统计入射到无限顶点的三角剖分顶点的个数,得到凸包的点数。一些点被移除,然后确定船体上剩余的点数。请注意,入射到三角剖分无限顶点的顶点位于凸包上,但可能并非所有顶点都是包的顶点。

3.1 示例

以下示例说明如何使用三角剖分计算凸包。入射到无限顶点的顶点在凸包上。

该函数convex_hull_3_to_face_graph()可用于获得作为概念模型的多面体表面MutableFaceGraph,例如Polyhedron_3Surface_mesh

#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef CGAL::Exact_predicates_inexact_constructions_kernel     K;
typedef K::Point_3                                              Point_3;
typedef CGAL::Delaunay_triangulation_3<K>                       Delaunay;
typedef Delaunay::Vertex_handle                                 Vertex_handle;
typedef CGAL::Surface_mesh<Point_3>                             Surface_mesh;
int main()
{
  CGAL::Random_points_in_sphere_3<Point_3> gen(100.0);
  std::list<Point_3> points;
  // generate 250 points randomly in a sphere of radius 100.0
  // and insert them into the triangulation
  std::copy_n(gen, 250, std::back_inserter(points));
  Delaunay T;
  T.insert(points.begin(), points.end());
  std::list<Vertex_handle>  vertices;
  T.incident_vertices(T.infinite_vertex(), std::back_inserter(vertices));
  std::cout << "This convex hull of the 250 points has "
            << vertices.size() << " points on it." << std::endl;
  // remove 25 of the input points
  std::list<Vertex_handle>::iterator v_set_it = vertices.begin();
  for (int i = 0; i < 25; i++)
  {
     T.remove(*v_set_it);
     v_set_it++;
  }
  //copy the convex hull of points into a polyhedron and use it
  //to get the number of points on the convex hull
  Surface_mesh chull;
  CGAL::convex_hull_3_to_face_graph(T, chull);
  std::cout << "After removal of 25 points, there are "
            << num_vertices(chull) << " points on the convex hull." << std::endl;
  return 0;
}

你可能感兴趣的:(CGAL,算法,c++,图形渲染,数据结构)