9.2 曲面网格生成 (Surface_mesher)

上一节: 9.1 Mesh_3三维网格生成概述 下一节: 9.3 四面体重网格化 相关章节: 13.2 Poisson表面重建 (网格用于重建)

0. 直观理解:贴瓷砖与精密测量

0.1 生活类比:浴室贴瓷砖

想象你正在给浴室的曲面浴缸贴瓷砖。这个任务与Surface_mesher的工作非常相似:

Surface_mesher的工作方式

  • 目标:用三角形”瓷砖”覆盖复杂曲面
  • 挑战:曲面弯曲处需要小瓷砖,平坦处可以大瓷砖
  • 要求:瓷砖之间不能重叠,也不能留缝隙
平面贴瓷砖(简单):              曲面贴瓷砖(复杂):

┌───┬───┬───┐                   ┌───┬───┐
├───┼───┼───┤                  /     /   /
├───┼───┼───┤                 /     /   /
└───┴───┴───┘                └───┬───┘
                                    \   \
                                     \   \
                                      └───┘

均匀大小即可                需要自适应大小
                           (弯曲处小,平坦处大)

0.2 为什么需要曲面网格?

场景1:游戏开发

  • 角色模型的3D表面表示
  • 需要平衡视觉质量和渲染性能
  • 少而精的三角形 = 高帧率

场景2:3D打印

  • 将数字模型转换为实体对象
  • 打印机需要切片数据
  • 网格质量影响打印成品表面光洁度

场景3:医学手术规划

  • 从CT扫描重建患者器官表面
  • 医生在虚拟环境中规划手术路径
  • 需要精确表示病灶区域

0.3 保护算法(Protection)的直观理解

在曲面网格生成中,保护算法就像是给曲面的重要特征”画上保护线”:

没有保护的曲面网格:              有保护的曲面网格:

    ╱╲                                ╱╲
   ╱  ╲                              ╱  ╲
  ╱    ╲                            ╱    ╲
 ╱      ╲                          ╱      ╲
╱   尖   ╲                        ╱   ●    ╲
════════════                      ═════╦══════
                                       ║
                                    保护点(红色)
                                    
问题:尖锐特征被抹平            解决:特征被精确保留

9.2.1 数学理论基础

曲面网格生成问题

给定一个光滑曲面 ,曲面网格生成问题是构造一个三角形网格 ,使得:

  1. 几何逼近 在几何上逼近
  2. 拓扑一致 同胚
  3. 质量约束 的三角形满足形状质量标准

Delaunay细化在曲面上的推广

Surface_mesher基于**受限Delaunay三角剖分(Restricted Delaunay Triangulation)**理论。

受限Delaunay三角剖分定义

是曲面 上的点集, 的三维Delaunay三角剖分。

受限Delaunay三角剖分 定义为:

其中Delaunay球是 的外接球(对于三角形)或外接圆(对于边)。

受限Delaunay可视化

三维Delaunay四面体:          受限Delaunay三角形:

        A                          A
       /|\                        /|\
      / | \                      / | \
     /  |  \                    /  |  \
    B---|---C                  B---|---C
     \  |  /                    \  |  /
      \ | /                      \ | /
       \|/                        \|/
        D                          D
        
四面体ABCD的                三角形ABC是受限Delaunay
外接球与曲面相交            因为它的外接球与曲面相交

拓扑保证定理

定理(Restricted Delaunay Homeomorphism)

如果采样 满足 -采样条件(),则受限Delaunay三角剖分 与曲面 同胚。

其中 -采样定义为:对于曲面 上的任意点 ,存在采样点 使得:

处的局部特征尺寸(Local Feature Size)

局部特征尺寸

局部特征尺寸 定义为:

直观意义: 到曲面”骨架”的最小距离,反映了曲面在 处的局部复杂度。

局部特征尺寸可视化:

曲面S:                    Medial Axis(骨架):

    ╭─────╮                    ┌───┐
   ╱       ╲                   │   │
  │    x    │        vs        │ x │   <-- lfs(x) = 到骨架的距离
  │         │                  │   │
   ╲_______╱                   └───┘
   
在平坦区域:lfs大              在狭窄区域:lfs小
(可以稀疏采样)              (需要密集采样)

保护算法(Protection)详解

对于含尖锐特征的曲面,需要保护算法确保特征被正确采样。

保护球(Protected Balls)

1D特征边保护过程:

步骤1: 识别特征边

    ╭─────●─────╮
   ╱      │      ╲
  │       │       │
  │       │       │
   ╲______│______╱
          
    红色边 = 特征边(尖锐边)

步骤2: 在特征边上放置保护球

    ╭───(●)───╮
   ╱     │     ╲
  │   (●)│(●)   │
  │      │      │
   ╲____(●)____╱
   
   (●) = 保护球中心
   
步骤3: 保护球防止细化破坏特征

    ╭───(●)───╮
   ╱  /  |  \  ╲
  │  /   |   \  │
  │ (●)  |  (●) │
   ╲ \   |   / ╱
    ╲(●)─┼─(●)╱
         
    网格在保护球外生成,特征被保留

1D特征处理

对于曲面上的1D特征(如尖锐边):

  1. 特征检测:识别曲面的高曲率边
  2. 保护球放置:沿特征边放置保护球
  3. 约束Delaunay:保护球中心构成1D Delaunay剖分
  4. 受限细化:在保护球外进行曲面细化
1D特征处理可视化:

曲面边界(1D特征):

        A
       / \
      /   \
     /     \
    B       C
     \     /
      \   /
       \ /
        D

保护球放置:

       (A)
       / \
      /   \
    (B)   (C)
      \   /
       \ /
       (D)

1D Delaunay剖分:连接保护球中心

       (A)
       /|
      / |
    (B)-(C)
      \ |
       \|
       (D)

表面中心与Delaunay球

对于Delaunay三角形

表面中心(Surface Center):Delaunay球与曲面 的交点中离三角形平面最远的点。

表面半径(Surface Radius):表面中心到三角形顶点的距离。

表面中心计算:

三角形PQR:                   Delaunay球:

        P                          P
       / \                        /|\
      /   \                      / | \
     /     \                    /  |  \
    Q-------R                  Q---|---R
    \       /                  \   |   /
     \  X  /                    \  |  /
      \   /                      \ | /
       \ /                        \|/
        S                        表面中心S
        
X = 表面中心 = Delaunay球与曲面的交点

细化标准

Surface_mesher使用两个细化标准:

1. 尺寸标准(Size Criterion)

三角形的表面半径超过尺寸上界:

其中 是三角形的中心, 是尺寸场。

尺寸标准可视化:

尺寸太大(需要细化):          尺寸合适:

    ┌─────────┐                ┌───┬───┐
   /         /                /   /   /
  /         /      vs        /   /   /
 ┌─────────┐                ├───┼───┤
 |         |                |   |   |
 └─────────┘                └───┴───┘
 
表面半径 > 尺寸上界          表面半径 ≤ 尺寸上界

2. 形状标准(Shape Criterion)

三角形的纵横比过差:

其中 是外接圆半径, 是内切圆半径。

等价于最小角条件:三角形的最小角小于阈值。

形状标准可视化:

劣质三角形(需要细化):        优质三角形:

    A                          A
   / \                        / \
  /   \                      /   \
 /     \                    /     \
B───────C                  B───────C

最小角 < 30°                最小角 ≥ 30°
(细长)                    (接近等边)

9.2.2 架构分析

整体架构

Surface_mesher
├── Surface(曲面定义)
│   ├── Implicit_surface_3(隐式曲面)
│   ├── Gray_level_image_3(灰度图像曲面)
│   └── Surface_mesh_complex_2_in_triangulation_3
│
├── Surface_mesh_traits(曲面特征)
│   ├── Surface_traits_base_3
│   └── Surface_mesher_traits_base_3
│
├── Mesher(网格生成器)
│   ├── Surface_mesher
│   ├── Surface_mesher_edges_level
│   └── Surface_mesher_visitor
│
└── Criteria(质量标准)
    ├── Surface_mesher_criteria
    └── Surface_mesher_default_criteria

核心类

1. 曲面概念(Surface Concept)

class Surface_3 {
    // 必需的类型
    typedef ... Point_3;
    typedef ... FT;
    typedef ... Intersect_3;      // 线段与曲面求交
    typedef ... Construct_initial_points;  // 构造初始点
    
    // 必需的操作
    Intersect_3 intersect_3_object();
    Construct_initial_points construct_initial_points_object();
    
    // 包围球
    Sphere_3 bounding_sphere() const;
};

2. 曲面特征(Surface Traits)

template <class Surface>
class Surface_mesh_traits_base_3 {
    // 类型定义
    typedef typename Surface::Point_3 Point_3;
    typedef typename Surface::FT FT;
    
    // 几何谓词
    typedef ... Is_on_surface;
    typedef ... Surface_center;
    typedef ... Surface_distance;
};

3. 质量标准(Criteria)

template <class Surface_mesh_traits>
class Surface_mesher_criteria_3 {
public:
    // 构造函数
    Surface_mesher_criteria_3(
        FT angle_bound,    // 最小角下界(弧度)
        FT radius_bound,   // 半径上界
        FT distance_bound  // 距离上界
    );
    
    // 判断三角形是否满足标准
    bool is_bad(const Facet& f, const Tr& tr) const;
};

算法流程

输入:曲面 S,质量标准 C
输出:曲面三角网格 M

1. 初始化
   - 构造初始采样点集 P_0
   - 构建三维Delaunay三角剖分 DT(P_0)
   - 提取受限Delaunay三角剖分 DT_S(P_0)

2. 细化循环
   while 存在违反质量标准的三角形 τ:
       // 计算细化点
       p = surface_center(τ)  // 表面中心
       
       // 插入点
       P = P ∪ {p}
       更新 DT(P)
       更新 DT_S(P)

3. 输出网格
   return DT_S(P) 的二维复形

算法可视化

第1步:初始采样

    S(曲面)
     •
    / \
   /   \
  •     •
   \   /
    \ /
     •

第2步:识别坏三角形

    S
     •
    /|\
   / | \
  •--X--•   X = 坏三角形(太大或太扁)
   \ | /
    \|/
     •

第3步:插入表面中心

    S
     •
    /|\
   / | \
  •--●--•   ● = 新插入的表面中心
   / | \
  •--●--•
   \ | /
    \|/
     •

第4步:最终网格

    S
     •
    /|\
   / | \
  •--|--•
  |\ | /|
  | \|/ |
  •--|--•
   \ | /
    \|/
     •

9.2.3 实现细节

1. 隐式曲面的实现

#include <CGAL/Implicit_surface_3.h>
 
// 定义隐式函数
typedef K::FT FT;
typedef K::Point_3 Point;
 
FT torus_function(const Point& p) {
    FT x = p.x(), y = p.y(), z = p.z();
    FT R = 2.0;  // 大半径
    FT r = 0.5;  // 小半径
    FT tmp = std::sqrt(x*x + y*y) - R;
    return tmp*tmp + z*z - r*r;
}
 
// 创建隐式曲面
typedef CGAL::Implicit_surface_3<K, FT> Surface;
Surface surface(torus_function,             // 隐式函数
                Sphere_3(Point(0,0,0), 9),  // 包围球
                1e-5);                       // 精度

2. 灰度图像曲面的实现

#include <CGAL/Gray_level_image_3.h>
 
// 从医学图像创建曲面
typedef CGAL::Gray_level_image_3<FT, Point> Gray_level_image;
 
Gray_level_image image("brain.inr",  // 图像文件
                       700);         // 等值面值
 
typedef CGAL::Implicit_surface_3<K, Gray_level_image> Surface;
Surface surface(image, Sphere_3(Point(0,0,0), 1000));

3. 网格生成

#include <CGAL/make_surface_mesh.h>
#include <CGAL/Surface_mesh_complex_2_in_triangulation_3.h>
 
// 类型定义
typedef CGAL::Surface_mesh_triangulation_generator_3<Surface>::Type Tr;
typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<Tr> C2t3;
typedef CGAL::Surface_mesher_criteria_3<Tr> Criteria;
 
// 创建三角剖分
Tr tr;
C2t3 c2t3(tr);
 
// 设置质量标准
Criteria criteria(30,    // 最小角(度)
                  0.1,   // 半径上界
                  0.01); // 距离上界
 
// 生成网格
CGAL::make_surface_mesh(c2t3,     // 输出复形
                        surface,  // 输入曲面
                        criteria, // 质量标准
                        CGAL::Manifold_with_boundary_tag());  // 拓扑标签

4. 拓扑标签

CGAL提供三种拓扑标签:

// 1. 不要求流形
CGAL::Non_manifold_tag()
 
// 2. 要求流形(可能带边界)
CGAL::Manifold_with_boundary_tag()
 
// 3. 要求无边界流形
CGAL::Manifold_tag()

5. 表面中心计算

表面中心是细化算法的核心:

// 计算三角形的表面中心
template <class Surface, class Tr>
Point surface_center(const Facet& f, const Surface& surface, const Tr& tr) {
    // 1. 获取三角形的三个顶点
    Cell_handle c = f.first;
    int i = f.second;
    Point p = c->vertex((i+1)%4)->point();
    Point q = c->vertex((i+2)%4)->point();
    Point r = c->vertex((i+3)%4)->point();
    
    // 2. 计算外接球
    Sphere circumsphere = circumsphere(p, q, r);
    
    // 3. 求外接球与曲面的交点
    // 选择离三角形平面最远的交点
    std::vector<Point> intersections;
    surface.intersect(circumsphere, std::back_inserter(intersections));
    
    // 4. 返回表面中心
    return select_farthest_from_plane(intersections, p, q, r);
}

9.2.4 代码示例

完整示例:环面网格

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh_triangulation_generator_3.h>
#include <CGAL/Surface_mesh_complex_2_in_triangulation_3.h>
#include <CGAL/Surface_mesher_criteria_3.h>
#include <CGAL/Implicit_surface_3.h>
#include <CGAL/make_surface_mesh.h>
#include <CGAL/IO/Complex_2_in_triangulation_3_file_writer.h>
#include <fstream>
 
// 几何内核
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
typedef K::Point_3 Point;
typedef K::Sphere_3 Sphere;
 
// 隐式函数:环面
FT torus_function(const Point& p) {
    FT x = p.x(), y = p.y(), z = p.z();
    FT R = 2.0;
    FT r = 0.5;
    FT tmp = std::sqrt(x*x + y*y) - R;
    return tmp*tmp + z*z - r*r;
}
 
// 曲面类型
typedef CGAL::Implicit_surface_3<K, FT> Surface;
 
// 三角剖分类型
typedef CGAL::Surface_mesh_triangulation_generator_3<Surface>::Type Tr;
 
// 二维复形类型
typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<Tr> C2t3;
 
// 质量标准类型
typedef CGAL::Surface_mesher_criteria_3<Tr> Criteria;
 
int main() {
    // 创建环面曲面
    Surface surface(torus_function,
                    Sphere(Point(0, 0, 0), 9.0),
                    1e-5);
    
    // 创建三角剖分和复形
    Tr tr;
    C2t3 c2t3(tr);
    
    // 设置质量标准
    // 角度30度,半径0.1,距离0.01
    Criteria criteria(30, 0.1, 0.01);
    
    // 生成网格
    CGAL::make_surface_mesh(c2t3,
                            surface,
                            criteria,
                            CGAL::Manifold_tag());
    
    // 输出统计
    std::cout << "顶点数: " << tr.number_of_vertices() << std::endl;
    std::cout << "面片数: " << c2t3.number_of_facets() << std::endl;
    
    // 检查拓扑
    if (c2t3.is_manifold()) {
        std::cout << "网格是流形" << std::endl;
    }
    
    // 保存到文件
    std::ofstream out("torus.off");
    CGAL::output_surface_facets_to_off(out, c2t3);
    out.close();
    
    return 0;
}

多曲面网格生成

// 定义分段隐式曲面
FT multi_surface_function(const Point& p) {
    FT x = p.x(), y = p.y(), z = p.z();
    
    // 球面
    FT sphere = x*x + y*y + z*z - 1.0;
    
    // 平面
    FT plane = z - 0.5;
    
    // 返回并集
    return std::min(sphere, plane);
}
 
// 或者使用布尔运算
FT boolean_function(const Point& p) {
    FT x = p.x(), y = p.y(), z = p.z();
    
    FT sphere1 = x*x + y*y + z*z - 1.0;
    FT sphere2 = (x-0.5)*(x-0.5) + y*y + z*z - 0.5;
    
    // 两个球的交集
    return std::max(sphere1, sphere2);
}

自定义尺寸场

#include <CGAL/Surface_mesher_criteria_3.h>
 
// 自定义质量标准
template <class Tr>
class Adaptive_criteria {
public:
    typedef typename Tr::Facet Facet;
    typedef typename Tr::Geom_traits::FT FT;
    
    // 自适应尺寸场
    FT sizing_field(const Point& p) const {
        FT r = std::sqrt(p.x()*p.x() + p.y()*p.y() + p.z()*p.z());
        return 0.1 / (1.0 + r);  // 远离原点处更粗
    }
    
    // 判断三角形是否满足标准
    bool is_bad(const Facet& f, const Tr& tr) const {
        // 计算三角形中心
        Point center = facet_center(f, tr);
        FT desired_size = sizing_field(center);
        
        // 检查实际尺寸
        FT actual_size = facet_size(f, tr);
        
        return actual_size > desired_size;
    }
};

从点云重建曲面

#include <CGAL/Poisson_reconstruction_function.h>
#include <CGAL/Surface_mesh.h>
 
// 点云类型
typedef CGAL::Point_with_normal_3<K> Point_with_normal;
typedef std::vector<Point_with_normal> Point_list;
 
// 泊松重建
Point_list points;
// ... 加载点云 ...
 
// 构建泊松隐式函数
typedef CGAL::Poisson_reconstruction_function<K> Poisson_function;
Poisson_function function(points.begin(), points.end(),
                          CGAL::make_normal_of_point_with_normal_map(Point_list::value_type()));
 
// 计算隐式函数
function.compute_implicit_function();
 
// 等值面提取
typedef CGAL::Implicit_surface_3<K, Poisson_function> Surface;
Surface surface(function, bounding_sphere, 1e-5);
 
// 生成网格
// ... 使用 make_surface_mesh ...

实际应用:医学图像处理

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh_triangulation_generator_3.h>
#include <CGAL/Surface_mesh_complex_2_in_triangulation_3.h>
#include <CGAL/Surface_mesher_criteria_3.h>
#include <CGAL/Gray_level_image_3.h>
#include <CGAL/Implicit_surface_3.h>
#include <CGAL/make_surface_mesh.h>
#include <CGAL/IO/Complex_2_in_triangulation_3_file_writer.h>
 
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
typedef K::Point_3 Point;
 
int main() {
    // 加载CT扫描图像
    CGAL::Image_3 image;
    image.read("patient_ct_scan.inr");
    
    // 创建灰度图像曲面(等值面提取)
    typedef CGAL::Gray_level_image_3<FT, Point> Gray_level_image;
    Gray_level_image gray_image(image, 500);  // 阈值500( Hounsfield单位)
    
    // 定义曲面(骨骼表面)
    typedef CGAL::Implicit_surface_3<K, Gray_level_image> Surface;
    Surface surface(gray_image, K::Sphere_3(Point(0,0,0), 1e9));
    
    // 三角剖分类型
    typedef CGAL::Surface_mesh_triangulation_generator_3<Surface>::Type Tr;
    typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<Tr> C2t3;
    typedef CGAL::Surface_mesher_criteria_3<Tr> Criteria;
    
    Tr tr;
    C2t3 c2t3(tr);
    
    // 医学图像需要高精度
    Criteria criteria(
        30,     // 最小角30度
        0.5,    // 半径上界0.5mm
        0.1     // 距离上界0.1mm
    );
    
    // 生成网格
    CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag());
    
    std::cout << "骨骼表面重建完成:" << std::endl;
    std::cout << "顶点数: " << tr.number_of_vertices() << std::endl;
    std::cout << "面片数: " << c2t3.number_of_facets() << std::endl;
    
    // 保存为STL格式(用于3D打印)
    std::ofstream stl_file("bone_model.stl");
    CGAL::output_surface_facets_to_stl(c2t3, stl_file);
    stl_file.close();
    
    return 0;
}

9.2.5 复杂度分析

时间复杂度

操作复杂度说明
初始化为初始点数
单点插入Delaunay更新
表面中心计算假设曲面求交为常数
完整生成n为输出顶点数
受限Delaunay提取m为三角形数

空间复杂度

  • Delaunay三角剖分
  • 曲面采样(曲面复杂度)
  • 总空间

输出规模

对于面积为 的曲面,在均匀尺寸 下:

  • 顶点数:
  • 三角形数:

9.2.6 理论保证

拓扑保证

定理:如果算法终止,输出网格满足:

  1. 同胚性:网格与输入曲面同胚
  2. 流形性:网格是二维流形(根据标签)
  3. 无自交:网格不自交

几何保证

定理:输出网格满足:

  1. Hausdorff距离(由distance_bound控制)
  2. 法向逼近:网格法向逼近曲面法向
  3. 面积收敛:网格面积收敛到曲面面积

终止性

定理:对于光滑闭曲面,在适当参数下,算法保证终止。

条件

  • 曲面是光滑的(
  • 尺寸场满足Lipschitz条件
  • 角度界小于30度

9.2.7 与其他组件的关系

Surface_mesher
├── 依赖
│   ├── Delaunay_triangulation_3(基础三角剖分)
│   ├── Implicit_surface_3(隐式曲面表示)
│   └── AABB_tree(加速结构)
│
├── 用于
│   ├── Mesh_3(三维网格生成的前置步骤)
│   └── Surface_reconstruction(表面重建)
│
└── 相关算法
    ├── Poisson_reconstruction(泊松重建)
    ├── Advancing_front(前沿推进)
    └── Marching_cubes(移动立方体)

9.2.8 应用

1. 医学图像处理

从CT/MRI数据提取等值面:

// 加载医学图像
CGAL::Image_3 image;
image.read("patient.inr");
 
// 创建灰度图像曲面
Gray_level_image gray_image(image, 500);  // 阈值500
 
// 生成网格
// ...

应用案例

  • 骨骼建模(骨科手术规划)
  • 血管重建(血流模拟)
  • 肿瘤分割(放疗规划)
  • 器官打印(3D生物打印)

2. 计算机辅助设计

从隐式CAD模型生成网格:

// CSG布尔运算
FT csg_model(const Point& p) {
    FT cube = std::max({std::abs(p.x()), std::abs(p.y()), std::abs(p.z())}) - 1.0;
    FT sphere = p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 1.5;
    
    // 立方体减球体
    return std::max(cube, -sphere);
}

应用案例

  • 机械零件设计
  • 模具制造
  • 建筑构件优化
  • 珠宝设计

3. 科学计算可视化

可视化标量场的等值面:

// 从模拟数据创建曲面
std::function<FT(Point)> field = [](const Point& p) {
    // 模拟物理场
    return simulation_value(p);
};
 
Surface surface(field, bounding_sphere);

应用案例

  • 天气模式可视化
  • 电磁场分布
  • 应力分析结果
  • 分子电子云

4. 参数选择指南

不同应用场景的参数建议

应用angle_boundradius_bounddistance_bound拓扑标签
医学图像20-30°0.1-0.50.01-0.05Manifold_tag
CAD设计25-30°0.01-0.10.001-0.01Manifold_tag
科学可视化15-25°0.5-2.00.05-0.2Manifold_with_boundary_tag
游戏模型20-25°0.1-1.00.01-0.1Manifold_tag

9.2.9 总结

Surface_mesher提供了:

  1. 全自动曲面网格生成:从隐式定义到高质量三角形网格
  2. 拓扑保证:确保输出网格与输入曲面同胚
  3. 几何精度:通过尺寸场和距离界控制逼近精度
  4. 自适应细化:根据曲面曲率自动调整网格密度
  5. 特征保护:保留尖锐边和角等几何特征

Surface_mesher是三维重建、科学计算可视化和计算机辅助设计的关键工具,广泛应用于医学、工程、娱乐等领域。