/** * @file boolean_mesh.h * @brief 三维网格布尔运算 * * 基于半边的网格布尔操作:并集、交集、差集、对称差。 * 通过面片重心内外判定 (ray-casting) 实现拓扑分类。 * * @ingroup boolean */ #pragma once #include "vde/boolean/boolean_2d.h" #include "vde/core/polygon.h" #include "vde/mesh/halfedge_mesh.h" namespace vde::boolean { using core::Point2D; using core::Polygon2D; using mesh::HalfedgeMesh; // ── Core 3D mesh boolean operations ────────────────────────────── /** * @brief 网格并集 A ∪ B * * 保留网格 A 中重心在网格 B 外的面片, * 以及网格 B 中重心在网格 A 外的面片。 * 合并后形成两个网格的并集体积。 * * 原理:对每个面片计算重心坐标,用射线投射判断 * 该点是否在对方网格内部,据此决定保留或剔除。 * * @param a 网格 A * @param b 网格 B * @return A ∪ B 的合并网格 * * @code{.cpp} * HalfedgeMesh result = mesh_union(cube, sphere); * @endcode * * @see mesh_intersection, mesh_difference, is_point_inside_mesh */ HalfedgeMesh mesh_union(const HalfedgeMesh& a, const HalfedgeMesh& b); /** * @brief 网格交集 A ∩ B * * 保留网格 A 中重心在网格 B 内的面片, * 以及网格 B 中重心在网格 A 内的面片。 * * @param a 网格 A * @param b 网格 B * @return A ∩ B 的交集网格 * * @note 结果体积为两网格公共区域 * * @see mesh_union, mesh_difference */ HalfedgeMesh mesh_intersection(const HalfedgeMesh& a, const HalfedgeMesh& b); /** * @brief 网格差集 A − B * * 保留网格 A 中重心在网格 B 外的面片, * 以及网格 B 中重心在网格 A 内的面片(翻转法线)。 * * @param a 网格 A * @param b 网格 B * @return A − B 的差集网格 * * @note 结果中来自 B 的面片会被翻转法线以保持内-外一致性 * * @see mesh_union, mesh_intersection, mesh_sym_diff */ HalfedgeMesh mesh_difference(const HalfedgeMesh& a, const HalfedgeMesh& b); /** * @brief 网格对称差 (A − B) ∪ (B − A) * * 等价于: * @code{.cpp} * mesh_union(mesh_difference(a, b), mesh_difference(b, a)) * @endcode * * @param a 网格 A * @param b 网格 B * @return 对称差网格 * * @see mesh_difference, mesh_union */ HalfedgeMesh mesh_sym_diff(const HalfedgeMesh& a, const HalfedgeMesh& b); // ── Helpers ───────────────────────────────────────────────────── /** * @brief 用网格 B 裁剪网格 A * * 保留网格 A 中位于 B 体外的面片。 * 是 mesh_difference 的简化变体,仅输出来自 A 的面片。 * * @param a 待裁剪网格 * @param b 裁剪体网格 * @param invert_b 若为 true,将 B 的内外判定取反(裁剪外部) * @return 裁剪后的网格(仅包含 A 的面片) * * @code{.cpp} * // 裁剪 cube 外部的 sphere 面片 * auto clipped = clip_mesh(sphere, cube, false // invert_b); * // 保留 cube 内部的 sphere 面片 * auto inner = clip_mesh(sphere, cube, true // invert_b); * @endcode * * @see mesh_difference, is_point_inside_mesh */ HalfedgeMesh clip_mesh(const HalfedgeMesh& a, const HalfedgeMesh& b, bool invert_b = false); /** * @brief 翻转网格所有面片的法线方向 * * 遍历所有面片,反转其顶点环绕顺序。 * 常用于生成负体积(反向外壳)或差集操作中。 * * @param m 原始网格 * @return 法线翻转后的网格 * * @see mesh_difference */ HalfedgeMesh invert_mesh(const HalfedgeMesh& m); /** * @brief 合并两个网格 * * 将两个网格的顶点和面片直接拼接,不做布尔操作。 * 用于将分离的网格组件合并到单个数据结构中。 * * @param a 网格 A * @param b 网格 B * @return 包含 A 和 B 全部顶点和面片的合并网格 * * @note 不处理重叠区域;仅做纯几何拼接 * * @see mesh_union(做布尔合并) */ HalfedgeMesh merge_meshes(const HalfedgeMesh& a, const HalfedgeMesh& b); /** * @brief 网格布尔运算统一接口 * * 根据布尔操作类型分发到对应的具体函数。 * * @param a 网格 A * @param b 网格 B * @param op 布尔操作类型 * @return 结果网格 * * @code{.cpp} * auto result = mesh_boolean(cube, sphere, BooleanOp::Intersection); * @endcode * * @see BooleanOp, mesh_union, mesh_intersection, mesh_difference, mesh_sym_diff */ HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op); // ── Point classification ──────────────────────────────────────── /** * @brief 判断三维点是否在封闭网格内部 * * 使用射线投射法:从点 p 向任意方向射出射线, * 统计与网格面片的交点数量。 * 奇数表示在内部,偶数表示在外部。 * * 算法: * 1. 构造从 p 出发沿 +x 方向的射线 * 2. 遍历所有三角形进行射线-三角形求交 * 3. 统计交点数量 * 4. 返回奇偶性判定结果 * * @param p 待判定点 * @param mesh 封闭网格 * @return 点在网格内部返回 true * * @note 网格必须是封闭(水密)的,否则结果不可靠。 * 点恰好落在面上时行为未定义。 * * @see clip_mesh, mesh_difference */ bool is_point_inside_mesh(const core::Point3D& p, const HalfedgeMesh& mesh); } // namespace vde::boolean