#pragma once /** * @file tolerant_modeling.h * @brief 容错建模 — 对标 Parasolid 的容差感知 B-Rep 操作 * * 提供带容差范围的拓扑元素、自适应合并、间隙桥接、重叠面检测、 * 容差感知布尔运算和 STEP 导入一站式修复流水线。 * * ## 核心能力 * * 1. **TolerantVertex/TolerantEdge** — 带容差范围的拓扑元素 * 2. **merge_within_tolerance** — BFS 自适应顶点合并 * 3. **gap_bridging** — 间隙检测 + 自动三角填充 * 4. **overlap_resolution** — 重叠面检测 + 移除 * 5. **tolerant_boolean** — 容差感知布尔 (heal → boolean → heal) * 6. **import_heal_pipeline** — STEP 导入一站式修复 * * @ingroup brep */ #include "vde/brep/brep.h" #include "vde/brep/brep_heal.h" #include "vde/brep/tolerance.h" #include "vde/core/point.h" #include #include #include #include namespace vde::brep { using core::Point3D; using core::Vector3D; using core::AABB3D; // ═══════════════════════════════════════════════════════════ // TolerantVertex / TolerantEdge // ═══════════════════════════════════════════════════════════ /** * @brief 带容差范围的拓扑顶点 * * 除了基本坐标外,额外存储: * - tolerance: 该顶点的合并容差(可独立于全局配置) * - merged_from: 若此顶点由多个原始顶点合并而来,记录合并数 * - is_degenerate: 标记退化顶点(如切触引起的退化边端点) */ struct TolerantVertex { int id; ///< 顶点 ID(对应 BrepModel 中的索引) Point3D point; ///< 三维坐标 double tolerance = 1e-6; ///< 该顶点的独立容差 int merged_from = 1; ///< 合并来源顶点数(1 = 未合并) bool is_degenerate = false; ///< 是否属于退化拓扑 /// 从普通 TopoVertex 构造 static TolerantVertex from_topo(const TopoVertex& tv) { TolerantVertex res; res.id = tv.id; res.point = tv.point; res.tolerance = tv.tolerance; return res; } }; /** * @brief 带容差范围的拓扑边(管状边模型) * * 将边建模为以其中心线为轴、tube_radius 为半径的圆柱管。 * 额外存储: * - tolerance: 边的曲线拟合容差 * - tube_radius: 管半径(自适应=该边两端点容差的最大值) * - path_tolerance: 路径允许最大偏移(曲线拟合误差上限) * - is_degenerate: 退化边(两端点重合或长度 failed_faces; ///< 失败面列表 std::string error_message; ///< 错误信息 /// 诊断是否包含失败面 [[nodiscard]] bool has_failures() const { return !failed_faces.empty() || !error_message.empty(); } /// 生成可读的诊断报告 [[nodiscard]] std::string report() const; }; // ═══════════════════════════════════════════════════════════ // ToleranceConflict — 容差冲突自动检测 // ═══════════════════════════════════════════════════════════ /// 容差冲突类型 enum class ConflictType { VertexInSphere, ///< 顶点球体重叠但未合并 EdgeInTube, ///< 边管相交但未共线 FaceGap ///< 面间间隙 < 容差 }; /** * @brief 容差冲突记录 * * 记录检测到的容差冲突类型、涉及元素和推荐修复策略。 */ struct ToleranceConflict { ConflictType type; ///< 冲突类型 int element_id_a = -1; ///< 冲突元素 A 的 ID int element_id_b = -1; ///< 冲突元素 B 的 ID double gap_size = 0.0; ///< 冲突的几何尺寸(距离/间隙值) std::string resolution; ///< 建议的合并/修复策略 /// 是否为顶点球体冲突 [[nodiscard]] bool is_vertex_conflict() const { return type == ConflictType::VertexInSphere; } /// 是否为边管冲突 [[nodiscard]] bool is_edge_conflict() const { return type == ConflictType::EdgeInTube; } /// 是否为面间隙冲突 [[nodiscard]] bool is_face_conflict() const { return type == ConflictType::FaceGap; } }; /** * @brief 检测 B-Rep 模型中的容差冲突 * * 执行三项检测: * 1. 顶点球体重叠:两点距离 < tolerance_a + tolerance_b 但尚未合并 * 2. 边管相交:两条边的管状区域相交但边不共线 * 3. 面间间隙:面之间存在微小间隙(自由边距离 < 容差) * * @param body 待检测的 B-Rep 模型 * @param vertex_tolerance 顶点合并容差,默认 1e-6 * @param edge_tolerance 边管容差倍率,默认 2.0(顶点容差的倍数) * @param face_gap_tolerance 面间隙容差,默认 1e-4 * @return 检测到的冲突列表 */ [[nodiscard]] std::vector detect_tolerance_conflicts( const BrepModel& body, double vertex_tolerance = 1e-6, double edge_tolerance = 2.0, double face_gap_tolerance = 1e-4); /** * @brief 解析并修复容差冲突 * * 按冲突类型分类处理: * - VertexInSphere → 调用 heal_gaps 合并顶点 * - EdgeInTube → 调用 heal_merge_edges 合并边 * - FaceGap → 调用 heal_gaps 闭合间隙 * * @param body 待修复的 B-Rep 模型(原地修改) * @param conflicts 冲突列表(来自 detect_tolerance_conflicts) * @return 修复的冲突数量 */ int resolve_tolerance_conflicts( BrepModel& body, const std::vector& conflicts); // ═══════════════════════════════════════════════════════════ // Public API // ═══════════════════════════════════════════════════════════ /** * @brief BFS 自适应顶点合并 * * 与 heal_gaps 类似,但支持: * - 每顶点独立容差(TolerantVertex::tolerance) * - 自适应容差:根据局部几何特征动态调整合并阈值 * - 退化顶点检测:标记切触产生的退化顶点 * * @param body 待修复的 B-Rep 模型(原地修改) * @param tolerance 全局合并容差,默认 1e-6 * @return 合并的顶点对数 */ int merge_within_tolerance(BrepModel& body, double tolerance = 1e-6); /** * @brief 间隙检测 + 自动三角填充 * * 检测面之间的微小间隙(距离 < max_gap), * 自动生成三角填充面以桥接间隙。 * * 算法: * 1. 遍历所有边,查找自由边(仅属于一个面) * 2. 对自由边配对:距离 < max_gap 的边视为间隙边界 * 3. 对每对自由边生成三角填充面 * * @param body 待修复的 B-Rep 模型(原地修改) * @param max_gap 最大间隙尺寸,默认 1e-4 * @return 填充的间隙数 */ int gap_bridging(BrepModel& body, double max_gap = 1e-4); /** * @brief 重叠面检测 + 移除 * * 检测并移除重叠/重复的面: * 1. 计算每对面的法向量和位置相似度 * 2. 共面且重叠 → 保留面积较大的面,移除较小的面 * 3. 更新壳的面引用 * * @param body 待修复的 B-Rep 模型(原地修改) * @return 移除的重叠面数 */ int overlap_resolution(BrepModel& body); /** * @brief 容差感知布尔运算 * * 完整流水线:heal → boolean → heal * 1. 预处理:对 A 和 B 分别执行 heal_topology * 2. 退化检测:共面/共线/切触 → 记录诊断信息 * 3. 执行布尔运算(委托给 ssi_boolean_*) * 4. 后处理:gap_bridging + overlap_resolution + heal_topology * * @param a 第一个 B-Rep 实体 * @param b 第二个 B-Rep 实体 * @param op 布尔操作类型:0=union, 1=intersection, 2=difference * @return BooleanDiagnostic 含结果模型和诊断信息 */ [[nodiscard]] BooleanDiagnostic tolerant_boolean( const BrepModel& a, const BrepModel& b, int op); /** * @brief STEP 导入一站式修复流水线 * * 导入 STEP 数据后自动执行完整修复: * 1. 导入 STEP(内部调用 import_step_from_string) * 2. 对每个 body 执行 merge_within_tolerance * 3. 执行 gap_bridging 闭合微小间隙 * 4. 执行 overlap_resolution 移除重复面 * 5. 执行 heal_orientation 统一方向 * 6. 验证最终结果 * * @param step_data STEP 文件内容(字符串形式) * @return 修复后的 B-Rep 体列表 * * @note 与直接调用 import_step_from_string() + heal_topology() 不同, * 此函数按容错建模流水线顺序执行,包含 gap_bridging 和 * overlap_resolution 步骤。 */ [[nodiscard]] std::vector import_heal_pipeline(const std::string& step_data); // ═══════════════════════════════════════════════════════════ // Internal utilities(跨编译单元可见) // ═══════════════════════════════════════════════════════════ /// 检测两个面是否为退化共面对 [[nodiscard]] bool detect_coplanar_faces( const BrepModel& body, int face_a, int face_b, double tolerance = 1e-6); /// 检测两个面是否为退化切触对 [[nodiscard]] bool detect_tangent_contact( const BrepModel& body, int face_a, int face_b, double tolerance = 1e-6); /// 检测边是否为退化边(长度 < tolerance) [[nodiscard]] bool detect_degenerate_edge( const BrepModel& body, int edge_id, double tolerance = 1e-6); /// 构建 TolerantVertex 映射表 [[nodiscard]] std::vector build_tolerant_vertices( const BrepModel& body, double global_tolerance = 1e-6); /// 构建 TolerantEdge 映射表 [[nodiscard]] std::vector build_tolerant_edges( const BrepModel& body, double global_tolerance = 1e-6); } // namespace vde::brep