#pragma once /** * @file brep.h * @brief 边界表示(B-Rep)核心数据结构 * * B-Rep(Boundary Representation)是 CAD 系统中最常用的实体表示方法, * 通过拓扑层次结构描述三维几何体的边界。 * * ## 拓扑层次结构 * * ``` * Body (体) — 一个或多个封闭壳(含名称) * └─ Shell (壳) — 一组面的连续集合 * └─ Face (面) — 曲面上由环界定的区域 * └─ Loop (环) — 封闭的边界曲线(外环 + 内环/孔) * └─ Edge (边) — 曲面的边界段 * └─ Vertex (顶点) — 边的端点 * ``` * * ## 实体引用关系 * * 每个实体通过整数 ID 唯一标识。父实体通过 ID 向量引用子实体。 * 曲面(NURBS Surface)独立存储,由面通过 surface_id 引用。 * 曲线(NURBS Curve)作为边的几何定义存储。 * * ## 使用模式 * * @code{.cpp} * BrepModel model; * // 从顶点层开始构建 * int v0 = model.add_vertex(Point3D(0, 0, 0)); * int v1 = model.add_vertex(Point3D(1, 0, 0)); * int e0 = model.add_edge(v0, v1); * int loop0 = model.add_loop({e0}); * int s0 = model.add_surface(plane_surface); * int f0 = model.add_face(s0, {loop0}); * int shell0 = model.add_shell({f0}); * int body0 = model.add_body({shell0}, "MyPart"); * @endcode * * 更常见的方式是使用 modeling.h 中的高层 API(make_box, extrude 等)。 * * @ingroup brep */ #include "vde/core/point.h" #include "vde/core/aabb.h" #include "vde/curves/nurbs_curve.h" #include "vde/curves/nurbs_surface.h" #include "vde/mesh/halfedge_mesh.h" #include #include #include namespace vde::brep { using core::Point3D; using core::Vector3D; using core::AABB3D; /** * @brief 边曲线类型枚举 * * 指定边所使用的曲线表示类别, * 影响 tessellation、布尔运算和文件交换时的处理方式。 */ enum class CurveType { Line, Circle, Bezier, BSpline, Nurbs }; // ═══════════════════════════════════════════════ // 拓扑实体定义 // ═══════════════════════════════════════════════ /** * @brief 拓扑顶点 * * 三维空间中的一个点,带有容差信息。 * 容差用于判断顶点的"等同性"——在容差范围内的点被视为同一顶点。 */ struct TopoVertex { int id; ///< 唯一定点 ID Point3D point; ///< 三维坐标 double tolerance = 1e-6; ///< 几何容差 }; /** * @brief 拓扑边 * * 连接两个顶点的有向曲线段。 * - `reversed = false`: 方向从 v_start 到 v_end * - `reversed = true`: 方向从 v_end 到 v_start * - `curve` 可以是 nullptr(隐含直线边) */ struct TopoEdge { int id; ///< 唯一边 ID int v_start, v_end; ///< 起点和终点顶点 ID std::shared_ptr curve; ///< 边的几何曲线(可为空,表示直线) bool reversed = false; ///< 是否相对于曲线参数方向反转 }; /** * @brief 拓扑环(Loop) * * 一组首尾相连的边构成的封闭边界。 * - 外环 (is_outer = true): 面的外部边界,逆时针为正 * - 内环 (is_outer = false): 面上的孔,顺时针为正 */ struct TopoLoop { int id; ///< 唯一环 ID std::vector edges; ///< 边 ID 序列(按环的遍历顺序) bool is_outer = true; ///< true = 外环, false = 内环(孔) }; /** * @brief 拓扑面 * * 曲面上由一个或多个环界定的区域。 * 面的正方向与曲面的法向量一致。 * reversed = true 表示法向量取反。 */ struct TopoFace { int id; ///< 唯一面 ID int surface_id; ///< 关联的曲面 ID std::vector loops; ///< 环 ID 列表(第一个为外环,后续为内环) bool reversed = false; ///< 面法向量是否反转 }; /** * @brief 拓扑壳 * * 一组面的连续集合,构成空间的封闭或开放边界。 * closed = true 表示壳封闭一个体积(水密)。 */ struct TopoShell { int id; ///< 唯一壳 ID std::vector faces; ///< 面 ID 列表 bool closed = true; ///< 是否为封闭壳 }; /** * @brief 拓扑体 * * 一个或多个壳的集合,构成完整的几何实体。 * name 用于在 STEP/IGES 文件中标识零件。 */ struct TopoBody { int id; ///< 唯一体 ID std::vector shells; ///< 壳 ID 列表 std::string name; ///< 体名称(对应 STEP 中的 PRODUCT) }; // ═══════════════════════════════════════════════ // B-Rep 模型类 // ═══════════════════════════════════════════════ /** * @brief B-Rep 模型 * * 完整的三维边界表示模型,包含几何和拓扑数据。 * * ## 主要职责 * * - **构建**: 通过 add_* 方法从底层构建拓扑结构 * - **查询**: 获取顶点、面、边及它们的拓扑关系 * - **导出**: 转换为三角网格(用于渲染)或导出到文件格式 * - **验证**: 检查水密性和拓扑一致性 * * ## 容差约定 * * | 容差 | 典型值 | 用途 | * |-------------|---------|--------------------------| * | 顶点容差 | 1e-6 | 判断两点是否视为同一点 | * | 边曲线容差 | 1e-5 | 曲线拟合精度 | * | tessellation | 0.01 | 曲面转网格的弦高误差 | * * @see brep_validate.h 验证 * @see modeling.h 高层建模 API * @see brep_boolean.h 布尔运算 */ class BrepModel { public: BrepModel() = default; /** * @brief 添加顶点 * @param p 顶点坐标 * @return 新顶点的 ID */ int add_vertex(const Point3D& p); /** * @brief 添加直线边 * @param v0 起点顶点 ID * @param v1 终点顶点 ID * @return 新边的 ID */ int add_edge(int v0, int v1); /** * @brief 添加曲线边 * @param v0 起点顶点 ID * @param v1 终点顶点 ID * @param curve 边的几何曲线 * @return 新边的 ID */ int add_edge(int v0, int v1, const curves::NurbsCurve& curve); /** * @brief 添加环 * @param edges 环中边的 ID 序列(顺序连接) * @param outer true = 外环, false = 内环 * @return 新环的 ID */ int add_loop(const std::vector& edges, bool outer = true); /** * @brief 添加面 * @param surface_id 关联曲面 ID * @param loops 环 ID 列表 * @return 新面的 ID */ int add_face(int surface_id, const std::vector& loops); /** * @brief 添加壳 * @param faces 面 ID 列表 * @param closed 是否为封闭壳 * @return 新壳的 ID */ int add_shell(const std::vector& faces, bool closed = true); /** * @brief 添加体 * @param shells 壳 ID 列表 * @param name 体名称 * @return 新体的 ID */ int add_body(const std::vector& shells, const std::string& name = ""); /** * @brief 添加 NURBS 曲面 * @param surf NURBS 曲面定义 * @return 新曲面的 ID */ int add_surface(const curves::NurbsSurface& surf); // ── 计数查询 ── /** @brief 顶点数量 */ [[nodiscard]] size_t num_vertices() const { return vertices_.size(); } /** @brief 边数量 */ [[nodiscard]] size_t num_edges() const { return edges_.size(); } /** @brief 面数量 */ [[nodiscard]] size_t num_faces() const { return faces_.size(); } /** @brief 体数量 */ [[nodiscard]] size_t num_bodies() const { return bodies_.size(); } /** @brief 曲面数量 */ [[nodiscard]] size_t num_surfaces() const { return surfaces_.size(); } // ── 元素访问(按数组索引 — 更快,适合顺序遍历) ── /** @brief 按数组索引访问顶点 */ [[nodiscard]] const TopoVertex& vertex(int id) const { return vertices_[id]; } /** @brief 按唯一 ID 访问顶点(适用于边数据中的 ID 引用) */ [[nodiscard]] const TopoVertex& vertex_by_id(int id) const; /** @brief 按数组索引访问边 */ [[nodiscard]] const TopoEdge& edge(int id) const { return edges_[id]; } /** @brief 按数组索引访问面 */ [[nodiscard]] const TopoFace& face(int id) const { return faces_[id]; } /** @brief 按数组索引访问曲面 */ [[nodiscard]] const curves::NurbsSurface& surface(int id) const { return surfaces_[id]; } /** @brief 按唯一 ID 访问环 */ [[nodiscard]] const TopoLoop& loop_by_id(int id) const; /** @brief 获取所有环的只读引用 */ [[nodiscard]] const std::vector& all_loops() const { return loops_; } // ── 几何/拓扑查询 ── /** * @brief 计算模型的轴对齐包围盒 * * 遍历所有顶点,取最小/最大坐标。 * * @return 包围盒(AABB) */ [[nodiscard]] core::AABB3D bounds() const; /** * @brief 检查模型有效性(快速版本) * * 进行基本检查:是否有顶点/边/面,ID 引用是否有效。 * 完整验证请使用 brep_validate.h 中的 validate()。 * * @return true 如果模型通过基本检查 * * @see validate() 完整验证(水密性、方向一致性等) */ [[nodiscard]] bool is_valid() const; /** * @brief 将 B-Rep 模型 tessellate 为三角网格 * * 所有曲面和曲线以给定的弦高误差 tessellate 为三角形。 * * @param deflection 弦高误差(控制 tessellation 精度,默认 0.01) * @return HalfedgeMesh 三角网格 * * @note deflection 越小网格越精细,但三角形数量显著增加。 */ [[nodiscard]] mesh::HalfedgeMesh to_mesh(double deflection = 0.01) const; // ── 邻接关系查询 ── /** * @brief 获取面的所有边 * * 展开面的所有环,收集其中包含的边 ID。 * * @param face_id 面 ID * @return 边 ID 列表(去重) */ [[nodiscard]] std::vector face_edges(int face_id) const; /** * @brief 获取边的所有相邻面 * * 反向查找:哪些面包含此边。 * 在流形网格中每条边应有恰好 2 个相邻面。 * * @param edge_id 边 ID * @return 相邻面 ID 列表 */ [[nodiscard]] std::vector edge_faces(int edge_id) const; /** * @brief 获取顶点的所有相邻边 * * @param vertex_id 顶点 ID * @return 相邻边 ID 列表 */ [[nodiscard]] std::vector vertex_edges(int vertex_id) const; // ── 友元:拓扑修复需要直接访问内部数据 ── friend int heal_merge_vertices(BrepModel&, double); friend int heal_merge_edges(BrepModel&, double); friend int heal_close_gaps(BrepModel&, double); friend int heal_orientation(BrepModel&); private: std::vector vertices_; std::vector edges_; std::vector loops_; std::vector faces_; std::vector shells_; std::vector bodies_; std::vector surfaces_; int next_id_ = 0; }; } // namespace vde::brep