192 lines
5.5 KiB
C++
192 lines
5.5 KiB
C++
/**
|
||
* @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
|