Files
ViewDesignEngine/include/vde/mesh/mesh_smooth.h
T

140 lines
4.6 KiB
C++
Raw Normal View History

#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;
2026-07-23 12:36:39 +00:00
/// HC 拉普拉斯参数
double hc_alpha = 0.0; ///< 回推强度,0 = 自动计算(推荐)
double hc_beta = 0.5; ///< 前推混合系数
2026-07-23 12:36:39 +00:00
/// 双边滤波参数
double bilateral_sigma_c = 0.0; ///< 空间 σ,0 = 自动按平均边长计算
double bilateral_sigma_n = 0.3; ///< 法向 σ(弧度),控制特征保持的敏感度
int bilateral_iters = 5; ///< 双边内部迭代次数
2026-07-23 12:36:39 +00:00
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
*/
2026-07-23 12:36:39 +00:00
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
*/
2026-07-23 12:36:39 +00:00
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
*/
2026-07-23 12:36:39 +00:00
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
*/
2026-07-23 12:36:39 +00:00
HalfedgeMesh smooth_bilateral(const HalfedgeMesh& mesh, const SmoothOptions& opts = {});
} // namespace vde::mesh