140 lines
4.6 KiB
C++
140 lines
4.6 KiB
C++
#pragma once
|
||
#include "vde/mesh/halfedge_mesh.h"
|
||
|
||
namespace vde::mesh {
|
||
using core::Point2D;
|
||
using core::Point3D;
|
||
using core::Vector3D;
|
||
|
||
/**
|
||
* @brief 网格光顺方法
|
||
* @ingroup mesh
|
||
*/
|
||
enum class SmoothMethod {
|
||
Laplacian, ///< 标准拉普拉斯光顺:v ← v + λ·L(v),快速但会收缩
|
||
Taubin, ///< Taubin λ|μ 光顺:先正后负步交替,体积保持
|
||
HCLaplacian, ///< HC 拉普拉斯(Humphrey's Classes):推拉两步保持形状/体积
|
||
Bilateral ///< 双边滤波:法向加权去噪,保持尖锐特征
|
||
};
|
||
|
||
/**
|
||
* @brief 网格光顺参数
|
||
* @ingroup mesh
|
||
*/
|
||
struct SmoothOptions {
|
||
int iterations = 10; ///< 迭代次数
|
||
double lambda = 0.5; ///< 拉普拉斯步长(Standard / Taubin 正步)
|
||
|
||
/// Taubin 负步系数,典型值 mu = -(lambda + ε),默认 -0.53
|
||
/// 必须满足 mu < -lambda 以实现体积保持
|
||
double mu = -0.53;
|
||
|
||
/// HC 拉普拉斯参数
|
||
double hc_alpha = 0.0; ///< 回推强度,0 = 自动计算(推荐)
|
||
double hc_beta = 0.5; ///< 前推混合系数
|
||
|
||
/// 双边滤波参数
|
||
double bilateral_sigma_c = 0.0; ///< 空间 σ,0 = 自动按平均边长计算
|
||
double bilateral_sigma_n = 0.3; ///< 法向 σ(弧度),控制特征保持的敏感度
|
||
int bilateral_iters = 5; ///< 双边内部迭代次数
|
||
|
||
SmoothMethod method = SmoothMethod::Laplacian; ///< 光顺方法选择
|
||
};
|
||
|
||
/**
|
||
* @brief 网格光顺(通用分发器)
|
||
*
|
||
* 根据 opts.method 分派到具体的光顺实现:
|
||
* - Laplacian → smooth_laplacian()
|
||
* - Taubin → smooth_taubin()
|
||
* - HCLaplacian → smooth_hc_laplacian()
|
||
* - Bilateral → smooth_bilateral()
|
||
*
|
||
* @param mesh 输入三角网格
|
||
* @param opts 光顺选项
|
||
* @return 光顺后的网格(顶点位置更新,拓扑不变)
|
||
*
|
||
* @code{.cpp}
|
||
* SmoothOptions opts;
|
||
* opts.method = SmoothMethod::Taubin;
|
||
* opts.iterations = 20;
|
||
* auto smooth = smooth_mesh(noisy_mesh, opts);
|
||
* @endcode
|
||
* @ingroup mesh
|
||
*/
|
||
HalfedgeMesh smooth_mesh(const HalfedgeMesh& mesh, const SmoothOptions& opts = {});
|
||
|
||
/**
|
||
* @brief 标准拉普拉斯光顺
|
||
*
|
||
* 均匀拉普拉斯:v ← v + λ·(avg(neighbor_positions) - v)
|
||
* 最简单但会引入体积收缩,适用于轻度平滑。
|
||
*
|
||
* @param mesh 输入网格
|
||
* @param iterations 迭代次数
|
||
* @param lambda 步长系数 (0, 1]
|
||
* @return 光顺后的网格
|
||
*
|
||
* @note 迭代过多会导致网格坍塌;对于体积关键的应用优先选 Taubin 或 HC
|
||
* @see smooth_taubin smooth_hc_laplacian
|
||
* @ingroup mesh
|
||
*/
|
||
HalfedgeMesh smooth_laplacian(const HalfedgeMesh& mesh, int iterations, double lambda);
|
||
|
||
/**
|
||
* @brief Taubin λ|μ 光顺(体积保持)
|
||
*
|
||
* 两阶段交替:
|
||
* 1. 正步(收缩滤波):v ← v + λ·L(v)
|
||
* 2. 负步(膨胀滤波):v ← v + μ·L(v),其中 μ < 0 且 |μ| > |λ|
|
||
*
|
||
* 传递函数在低频通带增益 ≈ 1,有效去噪同时保持体积。
|
||
*
|
||
* @param mesh 输入网格
|
||
* @param iterations 完整 λ/μ 循环次数
|
||
* @param lambda 正步系数 (0, 1]
|
||
* @param mu 负步系数,需满足 mu < 0 且 |mu| > lambda
|
||
* @return 光顺后的网格
|
||
*
|
||
* @note 典型值:λ = 0.5, μ = -0.53;|mu| 过大可能导致不稳定振荡
|
||
* @ingroup mesh
|
||
*/
|
||
HalfedgeMesh smooth_taubin(const HalfedgeMesh& mesh, int iterations, double lambda, double mu);
|
||
|
||
/**
|
||
* @brief HC 拉普拉斯光顺(Humphrey's Classes)
|
||
*
|
||
* 两遍处理以保持原始形状特征:
|
||
* 1. 前推:标准拉普拉斯光顺,记录位移 b_i = v_i' - v_i
|
||
* 2. 回推:v_i'' = v_i' - (α·b_i + β·avg(neighbor_b))
|
||
*
|
||
* 相比标准拉普拉斯显著减轻体积收缩,同时比 Taubin 更好地保持尖锐特征。
|
||
*
|
||
* @param mesh 输入网格
|
||
* @param opts 光顺选项(使用 hc_alpha 和 hc_beta 字段)
|
||
* @return 光顺后的网格
|
||
*
|
||
* @ingroup mesh
|
||
*/
|
||
HalfedgeMesh smooth_hc_laplacian(const HalfedgeMesh& mesh, const SmoothOptions& opts = {});
|
||
|
||
/**
|
||
* @brief 双边网格滤波
|
||
*
|
||
* 基于法向加权的各向异性去噪,保持尖锐边缘和特征:
|
||
* - 空间权重:w_c = exp(-d²/(2·σ_c²)),基于顶点间距
|
||
* - 法向权重:w_n = exp(-θ²/(2·σ_n²)),基于法向夹角
|
||
* - 更新:v ← v + Σ_j w_c(j)·w_n(j)·(v_j - v) / Σ_j w_c(j)·w_n(j)
|
||
*
|
||
* 相比于各向同性的拉普拉斯类方法,双边滤波在 CAD/机械零件网格上效果最优。
|
||
*
|
||
* @param mesh 输入网格
|
||
* @param opts 光顺选项(使用 bilateral_ 前缀字段)
|
||
* @return 光顺后的网格
|
||
*
|
||
* @ingroup mesh
|
||
*/
|
||
HalfedgeMesh smooth_bilateral(const HalfedgeMesh& mesh, const SmoothOptions& opts = {});
|
||
|
||
} // namespace vde::mesh
|