feat(v6.1): 5-axis CAM + reverse engineering + FEA mesh generation
v6.1.1 — 5-Axis CAM: - cam_5axis.h/.cpp: swarf_machining, multi_axis_roughing/finishing - 4 tool axis strategies, AC/BC/AB machine configs - inverse_kinematics, collision detection (holder+shank) - 30 tests, compilation passes v6.1.2 — Reverse Engineering: - point_cloud.h/.cpp: PointCloud class, PLY/E57/PTX loading - voxel_downsample, statistical_outlier_removal, kNN normal estimation - reverse_engineering.h/.cpp: Poisson surface reconstruction - mesh_to_nurbs_surface (quad remesh + LSQ fitting) - fit_plane (SVD), hole_filling, curvature-aware sampling - 19 tests v6.1.3 — FEA Mesh Generation: - fea_mesh.h/.cpp: tetrahedral (Delaunay 3D), boundary layer (prism) - hexahedral (sweep/extrude), adaptive refinement - MeshQuality: skewness, aspect_ratio, Jacobian, orthogonality - export_abaqus/ansys/nastran formats - 15 tests, 7/8 quality metrics verified
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file cam_5axis.h
|
||||
* @brief 5 轴联动 CAM 加工策略
|
||||
*
|
||||
* 在 3 轴 cam_strategies.h 的基础上扩展为 5 轴联动:
|
||||
* - 刀位点 + 刀轴矢量 (CLData)
|
||||
* - 侧刃加工 (swarf_machining)
|
||||
* - 多轴粗加工 3+2 定位 (multi_axis_roughing)
|
||||
* - 多轴精加工 + 碰撞检测 (multi_axis_finishing)
|
||||
* - 机床运动学逆解 (inverse_kinematics)
|
||||
* - 刀轴策略枚举 (ToolAxisStrategy)
|
||||
*
|
||||
* @ingroup core
|
||||
*/
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include "vde/core/cam_toolpath.h"
|
||||
#include "vde/core/cam_strategies.h"
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
namespace vde::brep {
|
||||
class BrepModel;
|
||||
} // namespace vde::brep
|
||||
|
||||
namespace vde::curves {
|
||||
class NurbsSurface;
|
||||
} // namespace vde::curves
|
||||
|
||||
namespace vde::core {
|
||||
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
using core::AABB3D;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 5 轴刀位数据
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 单个刀位点 + 刀轴矢量 (Cutter Location Data)
|
||||
struct CLData {
|
||||
Point3D position; ///< 刀尖点/TCP 位置
|
||||
Vector3D tool_axis; ///< 刀轴单位矢量(从刀尖指向刀柄)
|
||||
double feed_rate = 500.0; ///< 进给速度 (mm/min)
|
||||
|
||||
/// 便捷构造
|
||||
CLData() : position(Point3D::Zero()), tool_axis(Vector3D::UnitZ()) {}
|
||||
CLData(const Point3D& pos, const Vector3D& axis_, double feed = 500.0)
|
||||
: position(pos), tool_axis(axis_.normalized()), feed_rate(feed) {}
|
||||
};
|
||||
|
||||
/// 5 轴刀路 — CLData 集合
|
||||
struct AxisToolpath5 {
|
||||
std::string name;
|
||||
std::vector<CLData> points; ///< 刀位点序列
|
||||
double safe_height = 50.0; ///< 安全高度 (mm)
|
||||
|
||||
/// 刀位点数量
|
||||
[[nodiscard]] size_t size() const { return points.size(); }
|
||||
|
||||
/// 是否为空
|
||||
[[nodiscard]] bool empty() const { return points.empty(); }
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 刀轴策略
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 刀轴控制策略
|
||||
enum class ToolAxisStrategy {
|
||||
FixedAngle, ///< 固定角度:刀轴保持与 Z 轴固定偏角
|
||||
LeadLag, ///< 导前/滞后角:沿切削方向前倾或后倾
|
||||
Tilted, ///< 侧倾:垂直于切削方向倾斜
|
||||
NormalToSurface ///< 法向:刀轴始终沿曲面法向
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 机床配置
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 机床结构类型
|
||||
enum class MachineType {
|
||||
HeadHead, ///< 双摆头:A/B 轴均在主轴侧
|
||||
TableTable, ///< 双转台:A/C 轴均在工作台侧
|
||||
HeadTable ///< 摆头+转台:主轴侧一轴 + 工作台侧一轴
|
||||
};
|
||||
|
||||
/// 旋转轴配置
|
||||
enum class MachineAxisConfig {
|
||||
AC, ///< A 轴(绕 X 旋转)+ C 轴(绕 Z 旋转)
|
||||
BC, ///< B 轴(绕 Y 旋转)+ C 轴(绕 Z 旋转)
|
||||
AB ///< A 轴(绕 X 旋转)+ B 轴(绕 Y 旋转)
|
||||
};
|
||||
|
||||
/// 机床运动学配置
|
||||
struct MachineConfig {
|
||||
MachineType machine_type = MachineType::TableTable;
|
||||
MachineAxisConfig axis_config = MachineAxisConfig::AC;
|
||||
|
||||
/// 旋转轴行程限制(度)
|
||||
double a_min = -120.0;
|
||||
double a_max = 120.0;
|
||||
double b_min = -120.0;
|
||||
double b_max = 120.0;
|
||||
double c_min = -9999.0; // C 轴通常无限制(360°连续)
|
||||
double c_max = 9999.0;
|
||||
|
||||
/// 主轴端到旋转中心的偏移 (mm)
|
||||
Vector3D pivot_offset = Vector3D::Zero();
|
||||
|
||||
/// 刀具长度 (mm)
|
||||
double tool_length = 100.0;
|
||||
|
||||
/// 检查旋转角是否在行程范围内
|
||||
[[nodiscard]] bool in_range(double a, double b, double c) const;
|
||||
|
||||
/// 解析刀轴矢量为旋转角(根据 axis_config)
|
||||
/// @return (a_deg, b_deg, c_deg),失败返回 std::nullopt
|
||||
[[nodiscard]] std::optional<std::tuple<double, double, double>>
|
||||
axis_to_angles(const Vector3D& tool_axis) const;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 5 轴加工参数
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 侧刃加工参数
|
||||
struct SwarfParams {
|
||||
double step_down = 1.0; ///< 每层切深 (mm)
|
||||
double step_over = 0.5; ///< 横向步距 (mm)
|
||||
double feed_rate = 600.0; ///< 进给速度 (mm/min)
|
||||
double safe_height = 50.0; ///< 安全高度 (mm)
|
||||
double tilt_angle = 0.0; ///< 刀轴相对于曲面法线的偏转角 (度)
|
||||
};
|
||||
|
||||
/// 多轴粗加工参数
|
||||
struct MultiAxisRoughingParams {
|
||||
double step_down = 2.0; ///< 每层切深 (mm)
|
||||
double step_over = 3.0; ///< 横向步距 (mm)
|
||||
double stock_to_leave = 1.0; ///< 留量 (mm)
|
||||
double feed_rate = 800.0; ///< 进给速度 (mm/min)
|
||||
double safe_height = 50.0; ///< 安全高度 (mm)
|
||||
/// 3+2 定位角度 — 固定刀轴方向(相对于 Z 轴的倾斜角, 度)
|
||||
double tilt_angle = 15.0;
|
||||
double lead_angle = 0.0; ///< 导前角 (度)
|
||||
};
|
||||
|
||||
/// 多轴精加工参数
|
||||
struct MultiAxisFinishingParams {
|
||||
double step_over = 0.3; ///< 行距 (mm)
|
||||
double feed_rate = 500.0; ///< 进给速度 (mm/min)
|
||||
double safe_height = 50.0; ///< 安全高度 (mm)
|
||||
ToolAxisStrategy axis_strategy = ToolAxisStrategy::NormalToSurface;
|
||||
double max_tilt = 30.0; ///< 最大倾斜角 (度)
|
||||
double lead_angle = 3.0; ///< 导前角 (度)
|
||||
/// 碰撞检测参数
|
||||
bool collision_check = true; ///< 是否启用碰撞检测
|
||||
double shank_clearance = 2.0; ///< 刀柄安全间隙 (mm)
|
||||
double holder_clearance = 5.0; ///< 刀杆安全间隙 (mm)
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 5 轴加工策略函数
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 侧刃加工 (Swarf Machining)
|
||||
///
|
||||
/// 使用刀具侧刃贴合曲面进行切削,刀轴沿曲面法线偏转。
|
||||
/// 适用于直纹面侧壁加工。
|
||||
///
|
||||
/// @param surface 目标 NURBS 曲面
|
||||
/// @param tool 刀具参数
|
||||
/// @param params 侧刃加工参数
|
||||
/// @return 5 轴刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] AxisToolpath5 swarf_machining(
|
||||
const curves::NurbsSurface& surface,
|
||||
const Tool& tool,
|
||||
const SwarfParams& params);
|
||||
|
||||
/// 多轴粗加工 (3+2 定位加工)
|
||||
///
|
||||
/// 使用 3+2 定位方式对实体进行分层粗加工。
|
||||
/// 自动优化刀轴方向以最大化材料去除率,同时避免干涉。
|
||||
///
|
||||
/// @param body B-Rep 实体
|
||||
/// @param tool 刀具参数
|
||||
/// @param params 多轴粗加工参数
|
||||
/// @param config 机床运动学配置(用于刀轴方向可行性检查)
|
||||
/// @return 5 轴刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] AxisToolpath5 multi_axis_roughing(
|
||||
const brep::BrepModel& body,
|
||||
const Tool& tool,
|
||||
const MultiAxisRoughingParams& params,
|
||||
const MachineConfig& config = MachineConfig{});
|
||||
|
||||
/// 多轴精加工
|
||||
///
|
||||
/// 对曲面进行 5 轴联动精加工。刀轴平滑变化,
|
||||
/// 包含刀柄和刀杆的碰撞检测。
|
||||
///
|
||||
/// @param surface 目标 NURBS 曲面
|
||||
/// @param body 完整 B-Rep 模型(碰撞检测用)
|
||||
/// @param tool 刀具参数
|
||||
/// @param params 多轴精加工参数
|
||||
/// @param config 机床运动学配置
|
||||
/// @return 5 轴刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] AxisToolpath5 multi_axis_finishing(
|
||||
const curves::NurbsSurface& surface,
|
||||
const brep::BrepModel& body,
|
||||
const Tool& tool,
|
||||
const MultiAxisFinishingParams& params,
|
||||
const MachineConfig& config = MachineConfig{});
|
||||
|
||||
/// 机床运动学逆解
|
||||
///
|
||||
/// 将工件坐标系下的刀路 (CLData) 转换为机床各轴坐标。
|
||||
/// 根据机床配置 (AC/BC/AB + 双转台/摆头) 计算 X/Y/Z/A/B/C。
|
||||
///
|
||||
/// @param toolpath 工件坐标系下的 5 轴刀路
|
||||
/// @param config 机床运动学配置
|
||||
/// @return 机床坐标刀路(points 中 position 存 X/Y/Z,tool_axis 存 A/B/C 度)
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] AxisToolpath5 inverse_kinematics(
|
||||
const AxisToolpath5& toolpath,
|
||||
const MachineConfig& config);
|
||||
|
||||
/// 刀轴碰撞检测
|
||||
///
|
||||
/// 检查刀柄和刀杆是否与工件发生碰撞。
|
||||
///
|
||||
/// @param position 刀尖位置
|
||||
/// @param tool_axis 刀轴方向
|
||||
/// @param body B-Rep 工件
|
||||
/// @param tool 刀具参数
|
||||
/// @param shank_clearance 刀柄安全间隙
|
||||
/// @param holder_clearance 刀杆安全间隙
|
||||
/// @return true 如果发生碰撞
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] bool check_collision(
|
||||
const Point3D& position,
|
||||
const Vector3D& tool_axis,
|
||||
const brep::BrepModel& body,
|
||||
const Tool& tool,
|
||||
double shank_clearance = 2.0,
|
||||
double holder_clearance = 5.0);
|
||||
|
||||
/// 刀轴方向优化
|
||||
///
|
||||
/// 给定候选刀轴方向列表,选择最优方向:
|
||||
/// - 优先选择更接近 Z 轴(减小旋转轴行程)
|
||||
/// - 避免超出机床行程的配置
|
||||
/// - 考虑切削条件(避免刀尖切削)
|
||||
///
|
||||
/// @param candidates 候选刀轴方向
|
||||
/// @param config 机床配置
|
||||
/// @return 最优刀轴方向(归一化),若无可行方向返回 Z 轴
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] Vector3D optimize_tool_axis(
|
||||
const std::vector<Vector3D>& candidates,
|
||||
const MachineConfig& config);
|
||||
|
||||
} // namespace vde::core
|
||||
@@ -0,0 +1,409 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file fea_mesh.h
|
||||
* @brief 高质量FEA有限元网格生成模块
|
||||
*
|
||||
* 提供四面体、边界层棱柱、六面体网格生成、自适应细化、
|
||||
* 网格质量评估及CAE格式(Abaqus/Ansys/Nastran)导出。
|
||||
*
|
||||
* ## 功能概览
|
||||
* - tetrahedral_mesh: Delaunay 3D + 质量优化四面体网格
|
||||
* - boundary_layer_mesh: 沿壁面法向拉伸棱柱边界层
|
||||
* - hexahedral_mesh: sweep/extrude 六面体网格
|
||||
* - adaptive_refinement: 基于误差估计的局部细化
|
||||
* - fea_quality_report: skewness/aspect_ratio/jacobian/orthogonality 报告
|
||||
* - export_abaqus / export_ansys / export_nastran: CAE 格式导出
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include "vde/mesh/delaunay_3d.h"
|
||||
#include "vde/brep/brep.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
|
||||
namespace vde::mesh {
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// FEA 单元类型
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief FEA 单元拓扑类型
|
||||
* @ingroup mesh
|
||||
*/
|
||||
enum class FEAElementType {
|
||||
Tet4, ///< 4节点线性四面体 (C3D4)
|
||||
Tet10, ///< 10节点二次四面体 (C3D10)
|
||||
Hex8, ///< 8节点线性六面体 (C3D8)
|
||||
Hex20, ///< 20节点二次六面体 (C3D20)
|
||||
Wedge6, ///< 6节点线性三棱柱/楔形 (C3D6)
|
||||
Wedge15, ///< 15节点二次三棱柱 (C3D15)
|
||||
};
|
||||
|
||||
/// 获取单元类型对应的每单元节点数
|
||||
inline int nodes_per_element(FEAElementType t) {
|
||||
switch (t) {
|
||||
case FEAElementType::Tet4: return 4;
|
||||
case FEAElementType::Tet10: return 10;
|
||||
case FEAElementType::Hex8: return 8;
|
||||
case FEAElementType::Hex20: return 20;
|
||||
case FEAElementType::Wedge6: return 6;
|
||||
case FEAElementType::Wedge15:return 15;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 获取单元类型名称
|
||||
inline const char* element_type_name(FEAElementType t) {
|
||||
switch (t) {
|
||||
case FEAElementType::Tet4: return "Tet4";
|
||||
case FEAElementType::Tet10: return "Tet10";
|
||||
case FEAElementType::Hex8: return "Hex8";
|
||||
case FEAElementType::Hex20: return "Hex20";
|
||||
case FEAElementType::Wedge6: return "Wedge6";
|
||||
case FEAElementType::Wedge15:return "Wedge15";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// FEAMesh 数据结构
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief FEA有限元网格
|
||||
*
|
||||
* 存储顶点、单元连通性、边界面及单元类型信息。
|
||||
* 支持Tet4/Tet10/Hex8/Wedge6等常见FEA单元。
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct FEAMesh {
|
||||
std::vector<Point3D> vertices; ///< 顶点坐标数组
|
||||
std::vector<std::vector<int>> elements; ///< 各单元顶点索引(长度 = nodes_per_element)
|
||||
FEAElementType element_type = FEAElementType::Tet4; ///< 单元类型
|
||||
std::vector<int> material_ids; ///< 各单元材料ID(可选,默认0)
|
||||
std::vector<std::vector<int>> boundary_faces;///< 边界面(用于施加BC),顶点索引数组
|
||||
std::vector<int> boundary_face_tags; ///< 边界面标签(与boundary_faces一一对应)
|
||||
|
||||
/** @brief 单元总数 */
|
||||
[[nodiscard]] size_t num_elements() const { return elements.size(); }
|
||||
/** @brief 顶点总数 */
|
||||
[[nodiscard]] size_t num_vertices() const { return vertices.size(); }
|
||||
/** @brief 边界面总数 */
|
||||
[[nodiscard]] size_t num_boundary_faces() const { return boundary_faces.size(); }
|
||||
/** @brief 每单元节点数 */
|
||||
[[nodiscard]] int npe() const { return nodes_per_element(element_type); }
|
||||
};
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 网格生成参数
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 四面体网格生成参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct TetMeshParams {
|
||||
double min_angle = 15.0; ///< 最小二面角(度),太小导致刚度矩阵病态
|
||||
double max_aspect_ratio = 5.0; ///< 最大长宽比(外接球半径/最短边)
|
||||
double max_size = 0.0; ///< 最大单元尺寸,0 = 自动(包围盒对角线的 5%)
|
||||
double min_size = 0.0; ///< 最小单元尺寸,0 = max_size/10
|
||||
int quality_iterations = 3; ///< 质量优化迭代次数(Laplacian光顺+边翻转)
|
||||
bool keep_surface = true; ///< 是否保持原表面顶点位置
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 边界层网格参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct BLPParams {
|
||||
double first_cell_height = 0.001; ///< 第一层棱柱高度(壁面法向距离)
|
||||
double growth_rate = 1.2; ///< 相邻层高度增长率(>1.0)
|
||||
int num_layers = 5; ///< 棱柱层数
|
||||
double total_thickness = 0.0; ///< 边界层总厚度,0 = 自动(first * (growth^n - 1)/(growth - 1))
|
||||
bool smooth_transition = true; ///< 是否平滑过渡到内部网格
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 六面体网格参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct HexMeshParams {
|
||||
int sweep_layers = 1; ///< sweep 方向层数
|
||||
double sweep_distance = 0.0; ///< sweep 总距离,0 = 自动(包围盒最小维度)
|
||||
bool use_quad_dominant = true; ///< 源面是否使用四边形主导网格
|
||||
double cell_size = 0.0; ///< 目标单元尺寸,0 = 自动
|
||||
};
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 网格质量评估
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief FEA网格质量报告
|
||||
*
|
||||
* 包含 skewness(偏斜度)、aspect_ratio(长宽比)、
|
||||
* jacobian(雅可比)、orthogonality(正交性)四项
|
||||
* 核心FEA网格质量指标。
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct FEAQualityReport {
|
||||
/// 偏斜度 (skewness): 实际单元与理想单元的偏差,[0,1],0=最优
|
||||
double min_skewness = 0.0;
|
||||
double max_skewness = 0.0;
|
||||
double avg_skewness = 0.0;
|
||||
|
||||
/// 长宽比 (aspect ratio): 最长边/最短边,(Fluent: 1=最佳)
|
||||
double min_aspect_ratio = 0.0;
|
||||
double max_aspect_ratio = 0.0;
|
||||
double avg_aspect_ratio = 0.0;
|
||||
|
||||
/// 归一化雅可比 (scaled jacobian): [0,1],1=正单元,0=退化,<0=反转
|
||||
double min_jacobian = 0.0;
|
||||
double max_jacobian = 0.0;
|
||||
double avg_jacobian = 0.0;
|
||||
|
||||
/// 正交性 (orthogonality): 面法向与质心连线的夹角余弦,[0,1],1=完美正交
|
||||
double min_orthogonality = 0.0;
|
||||
double max_orthogonality = 0.0;
|
||||
double avg_orthogonality = 0.0;
|
||||
|
||||
size_t total_elements = 0; ///< 单元总数
|
||||
size_t degenerate_elements = 0; ///< 退化单元数 (Jacobian < 0.01)
|
||||
size_t inverted_elements = 0; ///< 反转单元数 (Jacobian < 0)
|
||||
|
||||
/// 分级统计 (A=优秀 B=良好 C=合格 D=差 F=不合格,按Jacobian)
|
||||
size_t grade_A = 0, grade_B = 0, grade_C = 0, grade_D = 0, grade_F = 0;
|
||||
};
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 自适应细化
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 误差估计函数类型
|
||||
*
|
||||
* 对给定单元返回估计误差值(≥0),值越大表示该单元越需要细化。
|
||||
*
|
||||
* @param element_idx 单元索引
|
||||
* @param mesh 所属网格
|
||||
* @return 误差估计值(非负)
|
||||
*/
|
||||
using ErrorEstimator = std::function<double(int element_idx, const FEAMesh& mesh)>;
|
||||
|
||||
/**
|
||||
* @brief 自适应细化参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct RefinementParams {
|
||||
double error_threshold = 0.5; ///< 相对误差阈值(高于此值的单元被细化)
|
||||
double refinement_fraction = 0.2; ///< 每次细化单元比例(0~1)
|
||||
int max_iterations = 3; ///< 最大细化迭代次数
|
||||
bool smooth_after_refine = true; ///< 细化后是否光顺
|
||||
};
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 网格生成 API
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 生成四面体FEA网格(Delaunay 3D + 质量优化)
|
||||
*
|
||||
* 对 BrepModel 进行 tessellation 获取表面三角网格,
|
||||
* 采样内部点后进行 Delaunay 3D 四面体化,
|
||||
* 再进行 Laplacian 光顺 + 边翻转优化质量。
|
||||
*
|
||||
* @param body B-Rep实体模型
|
||||
* @param params 四面体化参数(最小角、长宽比约束等)
|
||||
* @return FEAMesh 四面体网格
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto box = vde::brep::make_box(1, 1, 1);
|
||||
* TetMeshParams p;
|
||||
* p.min_angle = 18.0;
|
||||
* p.max_aspect_ratio = 4.0;
|
||||
* auto mesh = tetrahedral_mesh(box, p);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
FEAMesh tetrahedral_mesh(const brep::BrepModel& body,
|
||||
const TetMeshParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 生成边界层棱柱网格
|
||||
*
|
||||
* 沿B-Rep模型壁面法向拉伸多层棱柱单元,
|
||||
* 用于CFD边界层捕捉(y+控制)。
|
||||
* 先对表面进行三角化,然后每层沿法向偏移。
|
||||
*
|
||||
* @param body B-Rep实体模型
|
||||
* @param params 边界层参数(首层高度、增长率、层数)
|
||||
* @return FEAMesh 棱柱网格 (Wedge6)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* BLPParams p;
|
||||
* p.first_cell_height = 0.0001;
|
||||
* p.growth_rate = 1.15;
|
||||
* p.num_layers = 10;
|
||||
* auto bl = boundary_layer_mesh(wing, p);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
FEAMesh boundary_layer_mesh(const brep::BrepModel& body,
|
||||
const BLPParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 生成六面体网格(sweep/extrude策略)
|
||||
*
|
||||
* 将B-Rep模型的一个面(源面)四边形化,
|
||||
* 然后沿法向 sweep 生成六面体层。
|
||||
* 适用于拉伸体/棱柱体等 sweepable 几何。
|
||||
*
|
||||
* @param body B-Rep实体模型
|
||||
* @param params 六面体化参数
|
||||
* @return FEAMesh 六面体网格 (Hex8)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto cylinder = vde::brep::make_cylinder(1, 3);
|
||||
* HexMeshParams p;
|
||||
* p.sweep_layers = 5;
|
||||
* auto mesh = hexahedral_mesh(cylinder, p);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
FEAMesh hexahedral_mesh(const brep::BrepModel& body,
|
||||
const HexMeshParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 自适应网格细化
|
||||
*
|
||||
* 基于误差估计函数对高误差区域进行局部细分。
|
||||
* 支持边中点分裂细化(适用于Tet4→4×Tet4子单元)。
|
||||
*
|
||||
* @param mesh 输入FEA网格
|
||||
* @param estimator 误差估计函数
|
||||
* @param params 细化参数
|
||||
* @return FEAMesh 细化后的网格
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto estimator = [](int ei, const FEAMesh& m) -> double {
|
||||
* // 基于应力梯度的误差估计
|
||||
* return stress_gradient_norm(ei, m);
|
||||
* };
|
||||
* auto refined = adaptive_refinement(mesh, estimator);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
FEAMesh adaptive_refinement(const FEAMesh& mesh,
|
||||
const ErrorEstimator& estimator,
|
||||
const RefinementParams& params = {});
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// 质量评估 API
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 评估FEA网格质量
|
||||
*
|
||||
* 计算四项核心质量指标:
|
||||
* - skewness: 偏斜度(实际vs理想单元的偏差)
|
||||
* - aspect_ratio: 长宽比
|
||||
* - jacobian: 归一化雅可比行列式
|
||||
* - orthogonality: 正交性(面法向与质心连线夹角)
|
||||
*
|
||||
* 自动根据 element_type 选择对应算法(Tet/Hex/Wedge)。
|
||||
*
|
||||
* @param mesh FEA网格
|
||||
* @return FEAQualityReport 质量报告
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
FEAQualityReport fea_quality_report(const FEAMesh& mesh);
|
||||
|
||||
// ── 单项质量指标 ──
|
||||
|
||||
/**
|
||||
* @brief 计算单元的偏斜度
|
||||
* @param verts 单元顶点数组
|
||||
* @param type 单元类型
|
||||
* @return skewness [0,1],0=理想单元
|
||||
*/
|
||||
double element_skewness(const std::vector<Point3D>& verts, FEAElementType type);
|
||||
|
||||
/**
|
||||
* @brief 计算单元的长宽比
|
||||
* @param verts 单元顶点数组
|
||||
* @param type 单元类型
|
||||
* @return aspect_ratio ≥ 1,1=理想
|
||||
*/
|
||||
double element_aspect_ratio(const std::vector<Point3D>& verts, FEAElementType type);
|
||||
|
||||
/**
|
||||
* @brief 计算单元的归一化雅可比
|
||||
* @param verts 单元顶点数组
|
||||
* @param type 单元类型
|
||||
* @return scaled_jacobian [0,1],1=正四面体/正方体,0=退化
|
||||
*/
|
||||
double element_scaled_jacobian(const std::vector<Point3D>& verts, FEAElementType type);
|
||||
|
||||
/**
|
||||
* @brief 计算单元的正交性
|
||||
* @param verts 单元顶点数组
|
||||
* @param type 单元类型
|
||||
* @return orthogonality [0,1],1=完全正交(面法向与对面质心连线平行)
|
||||
*/
|
||||
double element_orthogonality(const std::vector<Point3D>& verts, FEAElementType type);
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// CAE 格式导出
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 导出 Abaqus 输入文件 (.inp)
|
||||
*
|
||||
* 生成包含 *NODE 和 *ELEMENT 卡的 Abaqus 输入文件。
|
||||
* 支持 Tet4 (C3D4), Tet10 (C3D10), Hex8 (C3D8), Wedge6 (C3D6)。
|
||||
*
|
||||
* @param mesh FEA网格
|
||||
* @param filepath 输出文件路径
|
||||
* @return 成功返回 true
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
bool export_abaqus(const FEAMesh& mesh, const std::string& filepath);
|
||||
|
||||
/**
|
||||
* @brief 导出 Ansys CDB 文件 (.cdb)
|
||||
*
|
||||
* 生成包含 NBLOCK 和 EBLOCK 的 Ansys CDB 格式文件。
|
||||
*
|
||||
* @param mesh FEA网格
|
||||
* @param filepath 输出文件路径
|
||||
* @return 成功返回 true
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
bool export_ansys(const FEAMesh& mesh, const std::string& filepath);
|
||||
|
||||
/**
|
||||
* @brief 导出 Nastran 批量数据文件 (.bdf/.dat)
|
||||
*
|
||||
* 生成包含 GRID 和 CTETRA/CHEXA/CPENTA 卡的 Nastran 输入文件。
|
||||
*
|
||||
* @param mesh FEA网格
|
||||
* @param filepath 输出文件路径
|
||||
* @return 成功返回 true
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
bool export_nastran(const FEAMesh& mesh, const std::string& filepath);
|
||||
|
||||
} // namespace vde::mesh
|
||||
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
namespace vde::mesh {
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
using core::AABB3D;
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
// PointCloud 点云类
|
||||
// ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 点云数据结构
|
||||
*
|
||||
* 存储顶点位置、法线、颜色(可选)及包围盒信息。
|
||||
* 支持 PLY/E57/PTX 加载,体素降采样、统计离群点剔除、kNN 法线估计。
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
class PointCloud {
|
||||
public:
|
||||
std::vector<Point3D> vertices; ///< 顶点位置
|
||||
std::vector<Vector3D> normals; ///< 顶点法线(归一化,空数组表示未计算)
|
||||
std::vector<std::array<uint8_t, 3>> colors; ///< RGB 颜色(0-255,空数组表示无颜色)
|
||||
|
||||
PointCloud() = default;
|
||||
|
||||
/// 从顶点列表构造(无颜色/法线)
|
||||
explicit PointCloud(std::vector<Point3D> pts) : vertices(std::move(pts)) {}
|
||||
|
||||
/// 顶点数
|
||||
[[nodiscard]] size_t size() const { return vertices.size(); }
|
||||
/// 是否有法线
|
||||
[[nodiscard]] bool has_normals() const { return !normals.empty(); }
|
||||
/// 是否有颜色
|
||||
[[nodiscard]] bool has_colors() const { return !colors.empty(); }
|
||||
|
||||
/// 包围盒
|
||||
[[nodiscard]] AABB3D bounds() const;
|
||||
|
||||
// ── I/O ──────────────────────────────────────────────
|
||||
|
||||
/// 加载 PLY 点云文件(ASCII 或 binary little-endian)
|
||||
static PointCloud load_ply(const std::string& path);
|
||||
|
||||
/// 加载 E57 点云文件(简化解析:仅提取 CartesianBounds + points3D)
|
||||
static PointCloud load_e57(const std::string& path);
|
||||
|
||||
/// 加载 PTX 格式点云(Leica 扫描仪原始格式)
|
||||
static PointCloud load_ptx(const std::string& path);
|
||||
|
||||
/// 保存为 PLY 文件
|
||||
bool save_ply(const std::string& path) const;
|
||||
|
||||
// ── 滤波 / 降采样 ────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 体素降采样
|
||||
* @param voxel_size 体素边长
|
||||
* @return 降采样后的点云(每个体素用质心代替)
|
||||
*/
|
||||
[[nodiscard]] PointCloud voxel_downsample(double voxel_size) const;
|
||||
|
||||
/**
|
||||
* @brief 统计离群点剔除(SOR)
|
||||
* @param k 邻域点数(默认 6)
|
||||
* @param std_ratio 标准差倍率阈值(默认 1.0),超过 mean+k*std_ratio 的点标记为离群
|
||||
* @return 剔除离群点后的点云
|
||||
*/
|
||||
[[nodiscard]] PointCloud statistical_outlier_removal(int k = 6, double std_ratio = 1.0) const;
|
||||
|
||||
// ── 法线估计 ──────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief kNN 法线估计
|
||||
*
|
||||
* 对每个点,找到 k 个最近邻点,用 PCA 估计法线(最小特征值对应方向)。
|
||||
* 法线方向通过视角向量(点→原点方向)统一朝向。
|
||||
*
|
||||
* @param k 最近邻点数(≥ 3)
|
||||
* @return 估计了法线的新点云
|
||||
*/
|
||||
[[nodiscard]] PointCloud normal_estimation(int k = 10) const;
|
||||
|
||||
// ── 曲率感知采样 ──────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 曲率感知降采样
|
||||
*
|
||||
* 计算每点局部曲率近似,按曲率加权采样:高曲率区域保留更多点。
|
||||
*
|
||||
* @param target_count 目标点数
|
||||
* @return 采样后的索引数组
|
||||
*/
|
||||
[[nodiscard]] std::vector<size_t> curvature_aware_sampling(size_t target_count) const;
|
||||
|
||||
// ── 平滑滤波 ──────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 双边滤波平滑
|
||||
*
|
||||
* 对点云位置进行法向加权的双边滤波去噪,保持尖锐特征。
|
||||
*
|
||||
* @param sigma_c 空间高斯 σ(0 = 自动按平均点距计算)
|
||||
* @param sigma_n 法向高斯 σ(弧度)
|
||||
* @param iterations 迭代次数
|
||||
* @return 平滑后的新点云
|
||||
*/
|
||||
[[nodiscard]] PointCloud smoothing_filter(double sigma_c = 0.0,
|
||||
double sigma_n = 0.3,
|
||||
int iterations = 3) const;
|
||||
|
||||
private:
|
||||
/** 构建 k-d 树索引,返回每个顶点的 k 最近邻索引 */
|
||||
[[nodiscard]] std::vector<std::vector<size_t>> k_nearest_neighbors(size_t k) const;
|
||||
|
||||
/** 协方差矩阵 PCA:计算三个特征值,返回最小特征值对应的特征向量 */
|
||||
[[nodiscard]] static Vector3D pca_normal(const std::vector<Point3D>& local_pts);
|
||||
};
|
||||
|
||||
} // namespace vde::mesh
|
||||
@@ -0,0 +1,235 @@
|
||||
#pragma once
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include "vde/mesh/point_cloud.h"
|
||||
#include "vde/curves/nurbs_surface.h"
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace vde::mesh {
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
using core::AABB3D;
|
||||
using curves::NurbsSurface;
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
// 参数结构体
|
||||
// ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief Poisson 曲面重建参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct PoissonReconParams {
|
||||
int max_depth = 8; ///< 八叉树最大深度(越高越精细)
|
||||
int min_depth = 3; ///< 八叉树最小深度
|
||||
double point_weight = 4.0; ///< 插值点权重(越高越贴近输入点)
|
||||
int solver_divide = 8; ///< 求解器分块大小
|
||||
int iso_divide = 8; ///< 等值面提取分块大小
|
||||
double samples_per_node = 1.5; ///< 每节点采样数
|
||||
bool scale_fit = true; ///< 是否缩放到单位立方体
|
||||
double confidence = 0.0; ///< 点置信度(0=均匀权重)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 四边形重网格化参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct QuadRemeshParams {
|
||||
int target_quads = 400; ///< 目标四边形数量
|
||||
double edge_length = 0.0; ///< 目标边长(0=自动)
|
||||
double regularity = 0.5; ///< 规则性权重 [0,1]
|
||||
double sharpness = 0.5; ///< 特征保持权重 [0,1]
|
||||
int iterations = 10; ///< 迭代次数
|
||||
bool adaptive_size = false; ///< 自适应边长(曲率区域更密)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief NURBS 拟合参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct NURBSFitParams {
|
||||
int degree_u = 3; ///< u 向阶次
|
||||
int degree_v = 3; ///< v 向阶次
|
||||
int num_cp_u = 8; ///< u 向控制点数(≥ degree_u+1)
|
||||
int num_cp_v = 8; ///< v 向控制点数(≥ degree_v+1)
|
||||
double smoothness = 0.001; ///< 平滑项权重(Tikhonov 正则化)
|
||||
int max_iterations = 50; ///< 最小二乘迭代上限
|
||||
double tolerance = 1e-6; ///< 收敛容差
|
||||
bool use_weights = true; ///< 是否使用有理权重拟合(NURBS vs B-spline)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 点云→网格综合参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct PointCloudToMeshParams {
|
||||
int knn = 10; ///< 法线估计 kNN
|
||||
double voxel_size = 0.0; ///< 预降采样体素尺寸(0=跳过)
|
||||
bool remove_outliers = true; ///< 是否先剔除统计离群点
|
||||
PoissonReconParams poisson; ///< Poisson 重建参数
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 网格→NURBS 综合参数
|
||||
* @ingroup mesh
|
||||
*/
|
||||
struct MeshToNURBSParams {
|
||||
QuadRemeshParams quad; ///< 四边形重网格化参数
|
||||
NURBSFitParams nurbs; ///< NURBS 拟合参数
|
||||
bool smooth_before_remesh = false; ///< 重网格化前是否平滑
|
||||
};
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
// 拟合结果
|
||||
// ───────────────────────────────────────────────────────────
|
||||
|
||||
/// 平面拟合结果
|
||||
struct PlaneFitResult {
|
||||
Point3D origin; ///< 平面上一点(点云质心)
|
||||
Vector3D normal; ///< 平面法向量(单位向量)
|
||||
double rms_error; ///< RMS 拟合误差
|
||||
bool valid; ///< 拟合是否有效
|
||||
};
|
||||
|
||||
/// 曲面片拟合结果
|
||||
struct PatchFitResult {
|
||||
NurbsSurface surface; ///< 拟合的 NURBS 曲面
|
||||
double rms_error; ///< RMS 拟合误差
|
||||
double max_error; ///< 最大偏差
|
||||
bool valid; ///< 拟合是否有效
|
||||
};
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
// 核心函数声明
|
||||
// ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 点云 → 三角网格(Poisson 曲面重建)
|
||||
*
|
||||
* 完整流水线:法线估计 → Poisson 隐式曲面重建 → 等值面提取。
|
||||
*
|
||||
* @param cloud 输入点云(可无法线,内部自动估计)
|
||||
* @param params 控制参数
|
||||
* @return 重建的三角网格
|
||||
*
|
||||
* @code{.cpp}
|
||||
* PointCloudToMeshParams p;
|
||||
* p.knn = 10; p.voxel_size = 0.02;
|
||||
* auto mesh = point_cloud_to_mesh(cloud, p);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
HalfedgeMesh point_cloud_to_mesh(const PointCloud& cloud,
|
||||
const PointCloudToMeshParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 网格 → NURBS 曲面
|
||||
*
|
||||
* 流水线:四边形重网格化 → 参数化 → 控制点最小二乘拟合。
|
||||
*
|
||||
* @param mesh 输入三角网格
|
||||
* @param params 控制参数
|
||||
* @return 拟合的 NURBS 曲面
|
||||
*
|
||||
* @code{.cpp}
|
||||
* MeshToNURBSParams p;
|
||||
* p.quad.target_quads = 200;
|
||||
* p.nurbs.num_cp_u = 6; p.nurbs.num_cp_v = 6;
|
||||
* auto surf = mesh_to_nurbs_surface(mesh, p);
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
NurbsSurface mesh_to_nurbs_surface(const HalfedgeMesh& mesh,
|
||||
const MeshToNURBSParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 点云平面拟合(SVD 最小二乘)
|
||||
*
|
||||
* @param points 输入点列表
|
||||
* @return 平面拟合结果(origin, normal, rms_error)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto plane = fit_plane(points);
|
||||
* // plane.normal 是单位法向量,plane.origin 是质心
|
||||
* @endcode
|
||||
* @ingroup mesh
|
||||
*/
|
||||
PlaneFitResult fit_plane(const std::vector<Point3D>& points);
|
||||
|
||||
/**
|
||||
* @brief 点云曲面片 NURBS 拟合
|
||||
*
|
||||
* 将点云拟合为指定阶次的 NURBS 曲面片:先将点投影到拟合平面上,
|
||||
* 在参数域中均匀采样构造控制网格,再用最小二乘优化控制点位置。
|
||||
*
|
||||
* @param points 输入点列表
|
||||
* @param degree_u u 向阶次
|
||||
* @param degree_v v 向阶次
|
||||
* @param num_cp_u u 向控制点数
|
||||
* @param num_cp_v v 向控制点数
|
||||
* @return 拟合结果(NURBS 曲面 + 误差)
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
PatchFitResult fit_patch(const std::vector<Point3D>& points,
|
||||
int degree_u = 3, int degree_v = 3,
|
||||
int num_cp_u = 8, int num_cp_v = 8);
|
||||
|
||||
/**
|
||||
* @brief 点云曲率感知采样
|
||||
*
|
||||
* 计算局部曲率近似,高曲率区域保留更多点,低曲率区域用较少点表示。
|
||||
*
|
||||
* @param points 输入点列表
|
||||
* @param target_count 目标保留点数
|
||||
* @return 采样后的点索引数组
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
std::vector<size_t> curvature_aware_sampling(const std::vector<Point3D>& points,
|
||||
size_t target_count);
|
||||
|
||||
/**
|
||||
* @brief 网格孔洞填充
|
||||
*
|
||||
* 检测边界环,对每个孔洞用 fan 三角化(或最小面积三角化)填充。
|
||||
*
|
||||
* @param mesh 输入网格
|
||||
* @param max_hole_edges 最大孔洞边界边数(超过此数的孔洞不填充,0=无限制)
|
||||
* @return 填充后的网格
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
HalfedgeMesh hole_filling(const HalfedgeMesh& mesh, int max_hole_edges = 0);
|
||||
|
||||
/**
|
||||
* @brief 点云平滑滤波
|
||||
*
|
||||
* 对点云位置进行各向同性拉普拉斯 + 双边滤波去噪。
|
||||
*
|
||||
* @param points 输入点列表
|
||||
* @param sigma 高斯核 σ(控制平滑强度)
|
||||
* @param iterations 迭代次数
|
||||
* @return 平滑后的点列表
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
std::vector<Point3D> smoothing_filter(const std::vector<Point3D>& points,
|
||||
double sigma = 0.5, int iterations = 3);
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
// 法线估计(独立函数)
|
||||
// ───────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief 点云法线估计(kNN + PCA)
|
||||
*
|
||||
* @param points 输入点列表
|
||||
* @param k 最近邻点数
|
||||
* @return 估计的法线向量列表
|
||||
*
|
||||
* @ingroup mesh
|
||||
*/
|
||||
std::vector<Vector3D> estimate_normals(const std::vector<Point3D>& points, int k = 10);
|
||||
|
||||
} // namespace vde::mesh
|
||||
Reference in New Issue
Block a user