CGAL笔记之网格生成——3D 表面网格生成

CGAL笔记之网格生成——3D 表面网格生成

  • 1 介绍
  • 2 光滑表面的表面网格生成器接口
  • 3 输入/输出
  • 4 示例
    • 4.1 网格划分隐式函数定义的等值面
  • 5 网格划分标准、保证和变化
  • 6 输出


CGAL笔记之网格生成——3D 表面网格生成_第1张图片

1 介绍

这个包提供了一个函数模板来计算一个近似于表面的三角形网格。

网格划分算法需要仅通过 oracle 了解要划分网格的表面,该 oracle 能够判断给定线段、线或射线是否与表面相交,并计算交点(如果有)。此功能使包足够通用,可以应用于各种情况。例如,它可用于对描述为某些函数的零水平集的隐式曲面进行网格划分。它也可以用于医学成像领域,以网格化描述为三维图像中的灰度级集的表面。

网格划分算法基于受限 Delaunay 三角剖分的概念。基本上,该算法计算表面上的一组样本点,并从这些样本点的三维三角剖分中提取插值表面网格。点被迭代地添加到样本中,就像在 Delaunay 细化过程中一样,直到满足表面网格元素的某些尺寸和形状标准。

大小和形状标准指导细化过程的行为并控制其终止。它们还调节最终网格中元素的大小和形状。当然,可以定制这些标准以满足用户需求。表面网格生成包提供了一组标准标准,可以通过三个数值进行缩放。此外,用户还可以插入自己的一组细化标准。

如果预言机(或用户)能够在每个连接的组件上提供一个初始样本点,则对表面的拓扑结构和组件数量没有限制。如果表面足够光滑,并且尺寸标准足够小,则该算法保证输出网格与表面同胚,并且在距表面的小有界距离(Hausdorff 或什至 Frechet 距离)内。该算法也可用于非光滑表面,但无法保证。

2 光滑表面的表面网格生成器接口

网格划分过程是通过调用函数模板启动的。网格划分函数有两个重载版本,其签名如下:

template <class SurfaceMeshC2T3,
          class Surface,
          class FacetsCriteria,
          class Tag >
void make_surface_mesh(SurfaceMeshC2T3& c2t3,
                       Surface surface,
                       FacetsCriteria criteria,
                       Tag);
template< class SurfaceMeshC2T3,
          class SurfaceMeshTraits,
          class FacetsCriteria,
          class Tag >
void make_surface_mesh(SurfaceMeshC2T3& c2t3,
                       SurfaceMeshTraits::Surface_3 surface,
                       SurfaceMeshTraits traits,
                       FacetsCriteria criteria,
                       Tag );

模板参数代表用于存储曲面网格的数据结构类型。这种类型必须是概念的模型。此类数据结构具有指向三维三角测量的指针,并将表面网格编码为此三角测量中的分面子集。类型的参数通过引用网格划分函数传递。此参数在进程结束时保存输出网格。SurfaceMeshC2T3``SurfaceMeshComplex_2InTriangulation_3``SurfaceMeshC2T3

模板参数代表曲面类型。这种类型必须是概念的模型。Surface``Surface_3

曲面网格生成器所需的曲面知识封装在特征类中。实际上,网格生成器仅通过此特征类访问要网格划分的表面。特征类必须是概念的模型。两个重载版本的区别可以解释如下SurfaceMeshTraits_3``make_surface_mesh()

  • 在 的第一个重载版本中,曲面类型作为模板参数 () 给出,待网格划分的作为参数传递给网格生成器。在这种情况下,曲面网格生成器特征类型由名为 的辅助类从曲面类型自动生成。make_surface_mesh()``Surface``surface``Surface_mesh_traits_generator_3
  • 在 的第二个重载版本中,表面网格生成器特征类型由模板参数提供,表面类型从此特征类型获取。曲面和特征都作为参数传递给网格生成器。make_surface_mesh()``SurfaceMeshTraits_3

只要曲面类型提供嵌套类型(作为模型)或提供特征生成器专用化的曲面类型,就可以使用第一个重载版本。目前,该库为隐式表面 () 和灰度级图像 () 提供部分专用化。Surface::Surface_mesher_traits_3``SurfaceMeshTraits_3``Surface_mesh_traits_generator_3``Surface_mesh_traits_generator_3``Implicit_surface_3``Gray_level_image_3

该参数处理驱动网格划分过程的大小和形状标准的描述。模板参数必须由概念的模型实例化。criteria``FacetsCriteria``SurfaceMeshFacetsCriteria_3

参数是一个标记,其类型影响网格划分算法的行为。例如,此参数可用于强制执行输出网格的歧管属性,同时避免网格的过度细化。

make_surface_mesh(c2t3,surface, criteria, tag)的调用使用一组初始点启动网格划分过程,该点集是两个子集的并集:初始三角测量中由 指向的顶点集,以及由特征类的函子提供的一组点。这组初始点需要在要网格划分的曲面的每个连接组件上至少包含一个点。c2t3``Construct_initial_points()

3 输入/输出

可以将曲面网格输出为 OFF 格式。使用函数 .CGAL::output_surface_facets_to_off()

4 示例

4.1 网格划分隐式函数定义的等值面

第一个代码示例对一个球体进行网格划分,该球体作为函数的零级集给出。更准确地说,要网格划分的表面是由类的构造函数从指向函数 () 和边界球体的指针创建的。Implicit_surface_3``sphere_function

默认网格划分标准由三个数值确定:

  • angular_bound是网格小平面角度的度数下限。
  • radius_bound是表面德劳内球半径的上限。表面 Delaunay 球是围绕网格刻面并以表面为中心的球。
  • distance_bound是网格刻面的圆周中心与该刻面的曲面 Delaunay 球中心之间距离的上限。

给定此表面类型,表面网格生成器将使用自动生成的特征类。

生成的网格如图所示。

CGAL笔记之网格生成——3D 表面网格生成_第2张图片

#include 
#include 
#include 
#include 
#include 
#include 
#include 
// default triangulation for Surface_mesher
typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
// c2t3
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
typedef Tr::Geom_traits GT;
typedef GT::Sphere_3 Sphere_3;
typedef GT::Point_3 Point_3;
typedef GT::FT FT;
typedef FT (*Function)(Point_3);
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
FT sphere_function (Point_3 p) {
  const FT x2=p.x()*p.x(), y2=p.y()*p.y(), z2=p.z()*p.z();
  return x2+y2+z2-1;
}
int main() {
  Tr tr;            // 3D-Delaunay triangulation
  C2t3 c2t3 (tr);   // 2D-complex in 3D-Delaunay triangulation
  // defining the surface
  Surface_3 surface(sphere_function,             // pointer to function
                    Sphere_3(CGAL::ORIGIN, 2.)); // bounding sphere
  // Note that "2." above is the *squared* radius of the bounding sphere!
  // defining meshing criteria
  CGAL::Surface_mesh_default_criteria_3<Tr> criteria(30.,  // angular bound
                                                     0.1,  // radius bound
                                                     0.1); // distance bound
  // meshing surface
  CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Non_manifold_tag());
  Surface_mesh sm;
  CGAL::facets_in_complex_2_to_triangle_mesh(c2t3, sm);
  std::ofstream out("sphere.off");
  out << sm << std::endl;
  std::cout << "Final number of points: " << tr.number_of_vertices() << "\n";
}

在此示例中,要网格划分的表面定义为 3D 图像中具有给定灰度级别的点的轨迹。该代码与前面的示例非常相似。

与前面的代码的主要区别在于,用于定义表面的函数是从图像文件创建的类型的对象,以及一个数值,该数值是希望网格划分的级别的灰度值。Gray_level_image_3

请注意,表面现在仍然是类型的对象,由三个参数定义,这三个参数是函数、边界球体和称为精度的数值。此精度(其值相对于边界球半径)用于交点计算。此参数具有上一示例中使用的默认值。另请注意,边界球体的中心必须是函数具有负值的内部点。Implicit_surface_3

此 3D 图像选择的等值对应于头部头骨。生成的网格如图 56.2 所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SJMEZl59-1677421153197)(file:///E:/WorkingLearning/learning/CGAL/CGAL-5.5.1-doc_html/doc_html/Surface_mesher/skull-surface.png)]

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// default triangulation for Surface_mesher
typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
// c2t3
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
typedef Tr::Geom_traits GT;
typedef CGAL::Gray_level_image_3<GT::FT, GT::Point_3> Gray_level_image;
typedef CGAL::Implicit_surface_3<GT, Gray_level_image> Surface_3;
int main() {
  Tr tr;            // 3D-Delaunay triangulation
  C2t3 c2t3 (tr);   // 2D-complex in 3D-Delaunay triangulation
  // the 'function' is a 3D gray level image
  Gray_level_image image(CGAL::data_file_path("images/skull_2.9.inr"), 2.9f);
  // Carefully chosen bounding sphere: the center must be inside the
  // surface defined by 'image' and the radius must be high enough so that
  // the sphere actually bounds the whole image.
  GT::Point_3 bounding_sphere_center(122., 102., 117.);
  GT::FT bounding_sphere_squared_radius = 200.*200.*2.;
  GT::Sphere_3 bounding_sphere(bounding_sphere_center,
                                   bounding_sphere_squared_radius);
  // definition of the surface, with 10^-5 as relative precision
  Surface_3 surface(image, bounding_sphere, 1e-5);
  // defining meshing criteria
  CGAL::Surface_mesh_default_criteria_3<Tr> criteria(30.,
                                                     5.,
                                                     5.);
  // meshing surface, with the "manifold without boundary" algorithm
  CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag());
  std::ofstream out("out.off");
  CGAL::output_surface_facets_to_off (out, c2t3);
  std::cout << "Final number of points: " << tr.number_of_vertices() << "\n";
}

5 网格划分标准、保证和变化

输出网格的保证取决于网格标准。首先,如果小平面角度的下限不大于度数,则证明网格划分算法终止。此外,输出网格保证与表面同胚,并且如果半径边界处小于局部特征尺寸的30倍,则网格与表面之间的距离(Hausdorff甚至Frechet距离)存在保证边界。这里 ϵ \epsilon ϵ 是一个必须小于 0.16的常数,局部特征大小 I f s ( x ) Ifs(x) Ifs(x) 在曲面的每个点x上定义为从 x到中轴的距离。请注意,半径边界不必是均匀的,尽管它在默认条件中是统一的边界。

当然,这种理论保证只能用于具有有限、非零到达值的光滑表面。(表面的覆盖范围是该表面上局部特征尺寸的最小值)。

表面上任何一点上的局部特征尺寸值或其在表面上的最小值通常未知,尽管有时可以猜测。此外,设置网格划分标准以满足理论条件也经常产生过度精细的网格。另一方面,当尺寸标准放宽时,不能保证与输入表面的同胚,甚至不能保证输出网格是流形的。为了解决这个问题并提供更灵活的网格划分算法,函数模板具有一个标记模板参数,允许稍微改变细化过程的行为。例如,此功能允许使用宽松的尺寸标准运行网格划分算法,与用户预期的网格大小更加一致,并且仍然保证输出网格形成歧管表面。该函数具有针对以下标记类型的专用版本:make_surface_mesh()``make_surface_mesh()

Manifold_tag:输出网格保证为无边界的流形曲面。

Manifold_with_boundary_tag:输出网格保证是流形的,但可能有边界。

Non_manifold_tag:该算法依赖于给定的标准,不保证任何其他内容。

6 输出

此 CGAL 组件还提供了将重建的曲面网格写入对象文件格式 (OFF)并将其转换为(当它是流形时)的功能:FaceGraph

  • output_surface_facets_to_off()
  • output_surface_facets_to_polyhedron()
  • facets_in_complex_2_to_triangle_mesh()

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