2026-07-27 00:33:30 +08:00
|
|
|
|
#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 <string>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-07-27 21:01:33 +08:00
|
|
|
|
* @brief 带容差范围的拓扑边(管状边模型)
|
2026-07-27 00:33:30 +08:00
|
|
|
|
*
|
2026-07-27 21:01:33 +08:00
|
|
|
|
* 将边建模为以其中心线为轴、tube_radius 为半径的圆柱管。
|
2026-07-27 00:33:30 +08:00
|
|
|
|
* 额外存储:
|
|
|
|
|
|
* - tolerance: 边的曲线拟合容差
|
2026-07-27 21:01:33 +08:00
|
|
|
|
* - tube_radius: 管半径(自适应=该边两端点容差的最大值)
|
|
|
|
|
|
* - path_tolerance: 路径允许最大偏移(曲线拟合误差上限)
|
2026-07-27 00:33:30 +08:00
|
|
|
|
* - is_degenerate: 退化边(两端点重合或长度<tolerance)
|
|
|
|
|
|
* - gap_flag: 标记此边参与间隙桥接
|
2026-07-27 21:01:33 +08:00
|
|
|
|
*
|
|
|
|
|
|
* 管状边用于容差冲突检测:若两条边的管相交但边本身不共线,
|
|
|
|
|
|
* 则判定为 EdgeInTube 冲突。
|
2026-07-27 00:33:30 +08:00
|
|
|
|
*/
|
|
|
|
|
|
struct TolerantEdge {
|
2026-07-27 21:01:33 +08:00
|
|
|
|
int id; ///< 边 ID(即 edge_id)
|
2026-07-27 00:33:30 +08:00
|
|
|
|
int v_start, v_end; ///< 端点顶点 ID
|
|
|
|
|
|
double tolerance = 1e-6; ///< 曲线拟合容差
|
2026-07-27 21:01:33 +08:00
|
|
|
|
double tube_radius = 1e-6; ///< 管半径(自适应=两端点容差的最大值)
|
|
|
|
|
|
double path_tolerance = 1e-4; ///< 路径允许最大偏移
|
2026-07-27 00:33:30 +08:00
|
|
|
|
bool is_degenerate = false; ///< 退化边(长度 < tolerance)
|
|
|
|
|
|
bool gap_flag = false; ///< 参与间隙桥接
|
|
|
|
|
|
bool is_tangent_contact = false; ///< 切触边(奇异性处理)
|
|
|
|
|
|
|
2026-07-27 21:01:33 +08:00
|
|
|
|
// ── 缓存的端点坐标(用于 is_within_tube / intersects 的无 body 调用) ──
|
|
|
|
|
|
Point3D p_start; ///< 起点坐标(缓存)
|
|
|
|
|
|
Point3D p_end; ///< 终点坐标(缓存)
|
|
|
|
|
|
|
2026-07-27 00:33:30 +08:00
|
|
|
|
/// 从普通 TopoEdge 构造
|
|
|
|
|
|
static TolerantEdge from_topo(const TopoEdge& te) {
|
|
|
|
|
|
TolerantEdge res;
|
|
|
|
|
|
res.id = te.id;
|
|
|
|
|
|
res.v_start = te.v_start;
|
|
|
|
|
|
res.v_end = te.v_end;
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 判断是否为退化边
|
|
|
|
|
|
[[nodiscard]] bool check_degenerate(const BrepModel& body) const {
|
|
|
|
|
|
const auto& v0 = body.vertex(v_start);
|
|
|
|
|
|
const auto& v1 = body.vertex(v_end);
|
|
|
|
|
|
return (v1.point - v0.point).norm() < tolerance;
|
|
|
|
|
|
}
|
2026-07-27 21:01:33 +08:00
|
|
|
|
|
|
|
|
|
|
/// 从 BrepModel 计算并缓存端点坐标 + 自适应管半径
|
|
|
|
|
|
void cache_from_body(const BrepModel& body) {
|
|
|
|
|
|
p_start = body.vertex(v_start).point;
|
|
|
|
|
|
p_end = body.vertex(v_end).point;
|
|
|
|
|
|
tube_radius = std::max(body.vertex(v_start).tolerance,
|
|
|
|
|
|
body.vertex(v_end).tolerance);
|
|
|
|
|
|
if (tube_radius < tolerance) tube_radius = tolerance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 检测点是否在管状边内部(点到线段距离 < tube_radius)
|
|
|
|
|
|
[[nodiscard]] bool is_within_tube(const Point3D& point) const {
|
|
|
|
|
|
Vector3D ab = p_end - p_start;
|
|
|
|
|
|
double len_sq = ab.squaredNorm();
|
|
|
|
|
|
if (len_sq < 1e-20) {
|
|
|
|
|
|
// 退化边:退化为球体
|
|
|
|
|
|
return (point - p_start).norm() < tube_radius;
|
|
|
|
|
|
}
|
|
|
|
|
|
Vector3D ap = point - p_start;
|
|
|
|
|
|
double t = ap.dot(ab) / len_sq;
|
|
|
|
|
|
t = std::max(0.0, std::min(1.0, t));
|
|
|
|
|
|
Point3D closest = p_start + ab * t;
|
|
|
|
|
|
return (point - closest).norm() < tube_radius;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 检测两条边管是否相交(线段间最小距离 < tube_radius_a + tube_radius_b)
|
|
|
|
|
|
[[nodiscard]] bool intersects(const TolerantEdge& other) const {
|
|
|
|
|
|
double min_dist = segment_segment_distance(
|
|
|
|
|
|
p_start, p_end, other.p_start, other.p_end);
|
|
|
|
|
|
return min_dist < (tube_radius + other.tube_radius);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 两条线段之间的最小距离
|
|
|
|
|
|
[[nodiscard]] static double segment_segment_distance(
|
|
|
|
|
|
const Point3D& a0, const Point3D& a1,
|
|
|
|
|
|
const Point3D& b0, const Point3D& b1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3D d1 = a1 - a0;
|
|
|
|
|
|
Vector3D d2 = b1 - b0;
|
|
|
|
|
|
Vector3D r = a0 - b0;
|
|
|
|
|
|
|
|
|
|
|
|
double a = d1.squaredNorm();
|
|
|
|
|
|
double e = d2.squaredNorm();
|
|
|
|
|
|
double f = d2.dot(r);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理退化线段
|
|
|
|
|
|
double s, t;
|
|
|
|
|
|
|
|
|
|
|
|
if (a < 1e-20 && e < 1e-20) {
|
|
|
|
|
|
// 两条线段都退化为点
|
|
|
|
|
|
return r.norm();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (a < 1e-20) {
|
|
|
|
|
|
// 第一条线段退化为点
|
|
|
|
|
|
s = 0.0;
|
|
|
|
|
|
t = std::max(0.0, std::min(1.0, f / e));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
double c = d1.dot(r);
|
|
|
|
|
|
if (e < 1e-20) {
|
|
|
|
|
|
// 第二条线段退化为点
|
|
|
|
|
|
t = 0.0;
|
|
|
|
|
|
s = std::max(0.0, std::min(1.0, -c / a));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
double b = d1.dot(d2);
|
|
|
|
|
|
double denom = a * e - b * b;
|
|
|
|
|
|
// 并行线段特殊处理
|
|
|
|
|
|
if (std::abs(denom) < 1e-20) {
|
|
|
|
|
|
s = 0.0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
s = std::max(0.0, std::min(1.0, (b * f - c * e) / denom));
|
|
|
|
|
|
}
|
|
|
|
|
|
double tnom = b * s + f;
|
|
|
|
|
|
t = std::max(0.0, std::min(1.0, tnom / e));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Point3D closest_a = a0 + d1 * s;
|
|
|
|
|
|
Point3D closest_b = b0 + d2 * t;
|
|
|
|
|
|
return (closest_a - closest_b).norm();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 获取边的单位方向向量
|
|
|
|
|
|
[[nodiscard]] Vector3D direction() const {
|
|
|
|
|
|
Vector3D d = p_end - p_start;
|
|
|
|
|
|
double n = d.norm();
|
|
|
|
|
|
if (n < 1e-12) return Vector3D(1, 0, 0);
|
|
|
|
|
|
return d / n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 获取边的长度
|
|
|
|
|
|
[[nodiscard]] double length() const {
|
|
|
|
|
|
return (p_end - p_start).norm();
|
|
|
|
|
|
}
|
2026-07-27 00:33:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// BooleanDiagnostic — 布尔运算失败面诊断报告
|
|
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 布尔运算失败面的诊断信息
|
|
|
|
|
|
*
|
|
|
|
|
|
* 记录每个失败面的原因、位置和容差建议。
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct FailedFaceInfo {
|
|
|
|
|
|
int face_id = -1; ///< 失败的面 ID
|
|
|
|
|
|
std::string reason; ///< 失败原因描述
|
|
|
|
|
|
int related_face_id = -1; ///< 关联面 ID(如有)
|
|
|
|
|
|
double suggested_tolerance = 0.0; ///< 建议的容差增大值
|
|
|
|
|
|
Point3D location; ///< 失败位置(近似)
|
|
|
|
|
|
bool is_coplanar = false; ///< 共面退化
|
|
|
|
|
|
bool is_tangent = false; ///< 切触退化
|
|
|
|
|
|
bool is_near_miss = false; ///< 接近但未精确相交
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 容差感知布尔运算的诊断结果
|
|
|
|
|
|
*
|
|
|
|
|
|
* 包含布尔运算的完整诊断信息,包括预处理/后处理统计、
|
|
|
|
|
|
* 失败面列表和建议修复方案。
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct BooleanDiagnostic {
|
|
|
|
|
|
bool success = false; ///< 布尔运算是否成功
|
|
|
|
|
|
BrepModel result; ///< 结果模型
|
|
|
|
|
|
|
|
|
|
|
|
// ── 预处理统计 ──
|
|
|
|
|
|
int pre_heal_merged_vertices = 0; ///< 预处理合并的顶点数
|
|
|
|
|
|
int pre_heal_closed_gaps = 0; ///< 预处理闭合的间隙数
|
|
|
|
|
|
int pre_heal_removed_slivers = 0; ///< 预处理移除的退化面数
|
|
|
|
|
|
|
|
|
|
|
|
// ── 布尔运算统计 ──
|
|
|
|
|
|
int degeneracy_detections = 0; ///< 检测到的退化情况数
|
|
|
|
|
|
int coplanar_pairs = 0; ///< 共面对数量
|
|
|
|
|
|
int tangent_contacts = 0; ///< 切触对数量
|
|
|
|
|
|
int exact_predicate_upgrades = 0; ///< 升级到精确谓词的次数
|
|
|
|
|
|
|
|
|
|
|
|
// ── 后处理统计 ──
|
|
|
|
|
|
int post_heal_merged_vertices = 0; ///< 后处理合并的顶点数
|
|
|
|
|
|
int post_heal_bridged_gaps = 0; ///< 后处理桥接的间隙数
|
|
|
|
|
|
int post_heal_resolved_overlaps = 0;///< 后处理解决的重叠面数
|
|
|
|
|
|
|
|
|
|
|
|
// ── 失败诊断 ──
|
|
|
|
|
|
std::vector<FailedFaceInfo> failed_faces; ///< 失败面列表
|
|
|
|
|
|
std::string error_message; ///< 错误信息
|
|
|
|
|
|
|
|
|
|
|
|
/// 诊断是否包含失败面
|
|
|
|
|
|
[[nodiscard]] bool has_failures() const {
|
|
|
|
|
|
return !failed_faces.empty() || !error_message.empty();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 生成可读的诊断报告
|
|
|
|
|
|
[[nodiscard]] std::string report() const;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-07-27 21:01:33 +08:00
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// 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<ToleranceConflict> 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<ToleranceConflict>& conflicts);
|
|
|
|
|
|
|
2026-07-27 00:33:30 +08:00
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
|
|
// 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<BrepModel> 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<TolerantVertex> build_tolerant_vertices(
|
|
|
|
|
|
const BrepModel& body, double global_tolerance = 1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
/// 构建 TolerantEdge 映射表
|
|
|
|
|
|
[[nodiscard]] std::vector<TolerantEdge> build_tolerant_edges(
|
|
|
|
|
|
const BrepModel& body, double global_tolerance = 1e-6);
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace vde::brep
|