2026-07-24 15:15:53 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @file brep_heal.h
|
|
|
|
|
|
* @brief B-Rep 拓扑修复
|
|
|
|
|
|
*
|
|
|
|
|
|
* 对 BrepModel 执行拓扑修复操作,处理导入 STEP/IGES 文件时常见的
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* 几何缺陷:重复顶点、冗余边、间隙、退化面和方向不一致。
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* ## 修复流水线(新版)
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* 1. heal_gaps — BFS 合并距离<tolerance 的顶点(替代旧版 merge + close_gaps)
|
|
|
|
|
|
* 2. heal_slivers — 检测并移除面积<sliver_area 的退化面
|
|
|
|
|
|
* 3. heal_orientation — 统一面方向(外法线朝外),用欧拉示性数验证
|
|
|
|
|
|
* 4. heal_topology — 一站式调用 1→2→3
|
|
|
|
|
|
* 5. heal_step_import — STEP 导入后自动修复
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* ## 旧版兼容函数
|
|
|
|
|
|
*
|
|
|
|
|
|
* - heal_merge_vertices — 保留以兼容旧代码,内部委托给 heal_gaps
|
|
|
|
|
|
* - heal_merge_edges — 保留以兼容旧代码
|
|
|
|
|
|
* - heal_close_gaps — 保留以兼容旧代码,内部委托给 heal_gaps
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @ingroup brep
|
|
|
|
|
|
*/
|
|
|
|
|
|
#include "vde/brep/brep.h"
|
|
|
|
|
|
#include "vde/brep/brep_validate.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace vde::brep {
|
|
|
|
|
|
|
2026-07-26 20:35:24 +08:00
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// 新版修复 API
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
2026-07-24 15:15:53 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @brief 使用 BFS 合并距离小于 tolerance 的顶点
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* 构建顶点邻接图:两点距离 < tolerance 则视为连通。
|
|
|
|
|
|
* 对每个连通分量,以第一个顶点为代表合并该分量中所有顶点。
|
|
|
|
|
|
* 更新所有边的顶点引用。
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param body 待修复的 B-Rep 模型(原地修改)
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @param tolerance 顶点合并距离容差,默认 1e-6
|
|
|
|
|
|
* @return 合并的顶点对数(即减少的顶点数)
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*/
|
2026-07-26 20:35:24 +08:00
|
|
|
|
int heal_gaps(BrepModel& body, double tolerance = 1e-6);
|
2026-07-24 15:15:53 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @brief 检测并移除退化面(sliver faces)
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* 遍历所有面,计算面的近似面积。面积小于 sliver_area
|
|
|
|
|
|
* (默认取自 ToleranceConfig::global().sliver_area = 1e-12)的面被移除。
|
|
|
|
|
|
* 更新壳的面引用并压缩面数组。
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param body 待修复的 B-Rep 模型(原地修改)
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @return 移除的退化面数量
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*/
|
2026-07-26 20:35:24 +08:00
|
|
|
|
int heal_slivers(BrepModel& body);
|
2026-07-24 15:15:53 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @brief 统一面方向(全部向外),用欧拉示性数验证
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* 通过符号体积计算确保所有面法向量朝外。
|
|
|
|
|
|
* 对于方向朝内的面,翻转其 reversed 标志。
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* 修复后计算欧拉示性数 V - E + F(预期 ≈ 2 对封闭流形),
|
|
|
|
|
|
* 偏差较大时记录但不回滚。
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param body 待修复的 B-Rep 模型(原地修改)
|
|
|
|
|
|
* @return 翻转的面数
|
|
|
|
|
|
*/
|
|
|
|
|
|
int heal_orientation(BrepModel& body);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @brief 一站式拓扑修复流水线
|
|
|
|
|
|
*
|
|
|
|
|
|
* 按推荐顺序执行:
|
|
|
|
|
|
* 1. heal_gaps (BFS 顶点合并 + 间隙闭合)
|
|
|
|
|
|
* 2. heal_slivers (移除退化面)
|
|
|
|
|
|
* 3. heal_orientation (统一面方向,欧拉验证)
|
2026-07-24 15:15:53 +00:00
|
|
|
|
*
|
|
|
|
|
|
* 最后调用 validate() 检查修复结果。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param body 待修复的 B-Rep 模型(原地修改)
|
2026-07-26 20:35:24 +08:00
|
|
|
|
* @param tolerance 顶点合并距离容差,默认 1e-6
|
2026-07-24 15:15:53 +00:00
|
|
|
|
* @return true 如果修复后模型通过验证
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool heal_topology(BrepModel& body, double tolerance = 1e-6);
|
|
|
|
|
|
|
2026-07-27 20:14:52 +08:00
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// AutoHealReport — 五步流水线修复报告
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 单步修复结果
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct StepResult {
|
|
|
|
|
|
bool success = false; ///< 本步是否成功执行
|
|
|
|
|
|
std::string step_name; ///< 步骤名称
|
|
|
|
|
|
int items_fixed = 0; ///< 修复的元素数量
|
|
|
|
|
|
std::vector<std::string> warnings; ///< 本步产生的警告
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief ACIS风格五步自动修复流水线报告
|
|
|
|
|
|
*
|
|
|
|
|
|
* 包含每一步的详细结果、总体评分和剩余警告。
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct AutoHealReport {
|
|
|
|
|
|
StepResult stitch; ///< Step 1: 缝合
|
|
|
|
|
|
StepResult simplify; ///< Step 2: 简化
|
|
|
|
|
|
StepResult regularize; ///< Step 3: 正则化
|
|
|
|
|
|
StepResult orient; ///< Step 4: 定向
|
|
|
|
|
|
StepResult check; ///< Step 5: 验证
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 总体评分 (0-100),基于每步成功率和修复量 */
|
|
|
|
|
|
int overall_score = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 剩余警告列表(跨步骤汇总) */
|
|
|
|
|
|
std::vector<std::string> warnings;
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 总修复元素数 */
|
|
|
|
|
|
[[nodiscard]] int total_fixed() const {
|
|
|
|
|
|
return stitch.items_fixed + simplify.items_fixed +
|
|
|
|
|
|
regularize.items_fixed + orient.items_fixed +
|
|
|
|
|
|
check.items_fixed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 成功步数 */
|
|
|
|
|
|
[[nodiscard]] int successful_steps() const {
|
|
|
|
|
|
return (stitch.success ? 1 : 0) +
|
|
|
|
|
|
(simplify.success ? 1 : 0) +
|
|
|
|
|
|
(regularize.success ? 1 : 0) +
|
|
|
|
|
|
(orient.success ? 1 : 0) +
|
|
|
|
|
|
(check.success ? 1 : 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief ACIS风格五步自动修复流水线
|
|
|
|
|
|
*
|
|
|
|
|
|
* 按顺序执行以下五个独立步骤,前一步失败不影响后一步:
|
|
|
|
|
|
*
|
|
|
|
|
|
* | 步骤 | 名称 | 操作 |
|
|
|
|
|
|
* |------|-------------|----------------------------------------------------------|
|
|
|
|
|
|
* | 1 | Stitch | 检测距离<tol的边→缝合(合并重合边) |
|
|
|
|
|
|
* | 2 | Simplify | 移除退化边(长度<tol)+合并共线边+合并共面小面 |
|
|
|
|
|
|
* | 3 | Regularize | 移除孤立顶点/边、修复翻转面、确保每边恰好属于2面 |
|
|
|
|
|
|
* | 4 | Orient | 统一面法线向外指向 |
|
|
|
|
|
|
* | 5 | Check | 欧拉-庞加莱公式验证+边面关联验证 |
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param body 待修复的 B-Rep 模型(原地修改)
|
|
|
|
|
|
* @param tolerance 缝合/简化容差,默认 1e-6
|
|
|
|
|
|
* @return AutoHealReport 包含每步详细结果、修复数量和总体评分
|
|
|
|
|
|
*
|
|
|
|
|
|
* @note 每一步捕获异常,失败后继续执行后续步骤。
|
|
|
|
|
|
* 最终评分 (0-100): 基础分=每步成功20分,警告扣分。
|
|
|
|
|
|
*/
|
|
|
|
|
|
[[nodiscard]] AutoHealReport auto_heal_pipeline(
|
|
|
|
|
|
BrepModel& body, double tolerance = 1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
// ── 旧版兼容 ──
|
|
|
|
|
|
|
2026-07-26 20:35:24 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief STEP 导入后自动修复
|
|
|
|
|
|
*
|
|
|
|
|
|
* 使用 auto_tolerance() 根据模型实际尺寸计算自适应容差,
|
|
|
|
|
|
* 然后执行 heal_topology()。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param body 从 STEP 导入的 B-Rep 模型(原地修改)
|
|
|
|
|
|
* @return 修复结果
|
|
|
|
|
|
* - >0: 修复成功,返回修复项总数
|
|
|
|
|
|
* - 0: 无需修复
|
|
|
|
|
|
* - <0: 修复失败
|
|
|
|
|
|
*/
|
|
|
|
|
|
int heal_step_import(BrepModel& body);
|
|
|
|
|
|
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// 旧版兼容函数(委托给新版实现)
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 合并重合顶点(旧版兼容)
|
|
|
|
|
|
* @deprecated 请使用 heal_gaps()
|
|
|
|
|
|
*/
|
|
|
|
|
|
int heal_merge_vertices(BrepModel& body, double tolerance = 1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 合并重合边(旧版兼容)
|
|
|
|
|
|
*/
|
|
|
|
|
|
int heal_merge_edges(BrepModel& body, double tolerance = 1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 闭合面之间的微小间隙(旧版兼容)
|
|
|
|
|
|
* @deprecated 请使用 heal_gaps()
|
|
|
|
|
|
*/
|
|
|
|
|
|
int heal_close_gaps(BrepModel& body, double max_gap = 1e-4);
|
|
|
|
|
|
|
2026-07-24 15:15:53 +00:00
|
|
|
|
} // namespace vde::brep
|