Files
茂之钳 089442fb69
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 31s
fix: more /* */ inside doxygen blocks in octree/boolean_mesh
2026-07-24 11:17:46 +00:00

192 lines
5.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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