Files
ViewDesignEngine/docs/API-REFERENCE.md
T
茂之钳 7219791685
CI / Build & Test (push) Failing after 16m49s
CI / Release Build (push) Failing after 1m31s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
docs: Markdown API reference (6942 lines, 76 headers)
2026-07-24 11:58:54 +00:00

6943 lines
163 KiB
Markdown
Raw 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.
# ViewDesignEngine API 参考手册
> 版本 3.2.0 | 76 个头文件
## 基础模块 (`vde::foundation`)
### `error_codes.h`
**全局错误码枚举**
`enum class ErrorCode : int32_t {`
### `exact_predicates.h`
**二维定向测试结果**
`enum class Orientation { Clockwise, CounterClockwise, Collinear }`
**圆测试结果**
`enum class CircleTest { Inside, On, Outside }`
**自适应精度二维定向测试(Shewchuk 算法)**
`Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个点 |
| `b` | 第二个点 |
| `c` | 第三个点 |
**返回**: Orientation::Collinear 若三点共线
> Delaunay 三角剖分、凸包计算等几何算法的核心原语
**参见**: `orient_3d, in_circle`
**自适应精度三维定向测试**
`Orientation orient_3d(const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `a` | 第一个点 |
| `b` | 第二个点 |
| `c` | 第三个点 |
| `d` | 第四个点(测试点) |
**返回**: Orientation::Collinear 若四点共面
> 三维 Delaunay 剖分和凸包计算的核心原语
**参见**: `orient_2d, in_circle`
**自适应精度圆内测试(In-Circle Test**
`CircleTest in_circle(const Point2D& a, const Point2D& b,`
| 参数 | 说明 |
|------|------|
| `a` | 三角形第一个顶点 |
| `b` | 三角形第二个顶点 |
| `c` | 三角形第三个顶点 |
| `d` | 待测试点 |
**返回**: CircleTest::Outside 若 d 在三角形外接圆外部
> Delaunay 三角剖分的空圆性质检查核心原语
**参见**: `orient_2d, orient_3d`
**自适应双精度谓词后端(默认)**
**二维定向测试**
`static exact::Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三个二维点 |
**返回**: 定向结果
**参见**: `exact::orient_2d`
**三维定向测试**
`static exact::Orientation orient_3d(const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c,d` | 四个三维点 |
**返回**: 定向结果
**参见**: `exact::orient_3d`
**圆内测试**
`static exact::CircleTest in_circle(const Point2D& a, const Point2D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三角形三顶点 |
| `d` | 待测试点 |
**返回**: 圆测试结果
**参见**: `exact::in_circle`
### `exact_predicates_gmp.h`
**GMP 精确算术谓词后端**
`struct GmpExact {`
> 仅在定义了 VDE_USE_GMP 宏且链接了 GMP 库时可用
**精确有理数二维定向测试**
`static Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {`
| 参数 | 说明 |
|------|------|
| `a` | 第一个点 |
| `b` | 第二个点 |
| `c` | 第三个点 |
**返回**: 定向结果(保证正确,无舍入误差)
**参见**: `GmpExact::orient_3d, GmpExact::in_circle`
**精确有理数三维定向测试**
`static Orientation orient_3d(const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 定义平面的三点 |
| `d` | 待测试点 |
**返回**: 定向结果(零误差)
**参见**: `GmpExact::orient_2d`
**精确有理数圆内测试**
`static CircleTest in_circle(const Point2D& a, const Point2D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三角形三顶点 |
| `d` | 待测试点 |
**返回**: 圆测试结果(零误差)
**参见**: `GmpExact::orient_2d`
### `format_utils.h`
**以 CAD 级别精度格式化双精度浮点数**
`inline std::string fmt_double(double v, int precision = 12) {`
| 参数 | 说明 |
|------|------|
| `v` | 要格式化的双精度数 |
| `precision` | 有效数字位数(默认 12 |
**返回**: 格式化后的字符串,如 "1.234567890123e+02"
> 总是确保指数部分带符号(如 "e+00" 而非 "e00"),便于解析器统一处理
**参见**: `fmt_iges_real, fmt_point`
**IGES 格式实数输出**
`inline std::string fmt_iges_real(double v, int /*precision*/ = 12) {`
| 参数 | 说明 |
|------|------|
| `v` | 要格式化的双精度数 |
**返回**: IGES 格式字符串,如 "3.141592653590D+00"
**参见**: `fmt_double`
**格式化三维点为逗号分隔字符串**
`inline std::string fmt_point(const core::Point3D& p, bool use_d = false) {`
| 参数 | 说明 |
|------|------|
| `p` | 三维点 |
| `use_d` | 若为 true,使用 IGES 风格 D 指数标记 |
**返回**: 逗号分隔的坐标字符串
**参见**: `fmt_double, fmt_iges_real`
**将字符串填充到恰好 72 个字符**
`inline std::string pad72(const std::string& s) {`
| 参数 | 说明 |
|------|------|
| `s` | 输入字符串 |
**返回**: 恰好 72 字符的字符串(不足右侧补空格,超出截断)
**参见**: `format_iges_line`
**格式化 IGES 段落行**
`inline std::string format_iges_line(const std::string& data, char section_char, int seq) {`
| 参数 | 说明 |
|------|------|
| `data` | 数据内容(最多 72 字符,超出截断) |
| `section_char` | 段落标识符(如 'P' 参数段, 'D' 目录段) |
| `seq` | 行序号(1-based |
**返回**: 完整 IGES 行(含换行符),共 81 字符
**参见**: `pad72`
### `interval.h`
**双精度区间算术类**
**从单值构造精确区间(退化为点)**
`Interval(double v) : lo(v), hi(v) {}`
| 参数 | 说明 |
|------|------|
| `v` | 区间值,[v, v] |
**从上下界构造区间**
`Interval(double l, double h) : lo(std::min(l,h)), hi(std::max(l,h)) {}`
| 参数 | 说明 |
|------|------|
| `l` | 下界 |
| `h` | 上界 |
**区间中点**
`[[nodiscard]] double mid() const { return (lo + hi) * 0.5; }`
**返回**: (lo + hi) / 2
**区间宽度**
`[[nodiscard]] double width() const { return hi - lo; }`
**返回**: hi - lo
**判断区间是否包含给定值**
`[[nodiscard]] bool contains(double v) const { return lo <= v && v <= hi; }`
| 参数 | 说明 |
|------|------|
| `v` | 测试值 |
**返回**: true 若 lo ≤ v ≤ hi
**判断区间是否足够窄(收敛)**
`[[nodiscard]] bool is_exact(double eps = 1e-12) const { return width() < eps; }`
| 参数 | 说明 |
|------|------|
| `eps` | 宽度阈值(默认 1e-12) |
**返回**: true 若区间宽度 < eps
**判断两个区间是否有重叠**
`[[nodiscard]] bool overlaps(const Interval& o) const {`
| 参数 | 说明 |
|------|------|
| `o` | 另一个区间 |
**返回**: true 若存在公共点
**确定性区间比较**
`[[nodiscard]] int cmp(const Interval& o) const {`
| 参数 | 说明 |
|------|------|
| `o` | 另一个区间 |
**返回**: 0 若区间重叠,无法确定
**区间加法**
`Interval operator+(const Interval& o) const {`
**返回**: [this.lo + o.lo, this.hi + o.hi]
**区间减法**
`Interval operator-(const Interval& o) const {`
**返回**: [this.lo - o.hi, this.hi - o.lo](保守估计)
**区间乘法**
`Interval operator*(const Interval& o) const {`
**返回**: [min(a*c,a*d,b*c,b*d), max(a*c,a*d,b*c,b*d)]
**区间除法**
`Interval operator/(const Interval& o) const {`
**返回**: 结果区间或 [-∞, +∞](除数为零区间)
**区间平方根**
`[[nodiscard]] Interval sqrt() const {`
**返回**: [sqrt(max(0, lo)), sqrt(max(0, hi))]
**从双精度值创建区间(含舍入误差带)**
`static Interval from_double(double v, double error = 0) {`
| 参数 | 说明 |
|------|------|
| `v` | 中心值 |
| `error` | 误差半径(默认 0 |
**返回**: [v - error, v + error]
**从坐标值创建区间(含 ULP 误差带)**
`static Interval from_coord(double v) {`
| 参数 | 说明 |
|------|------|
| `v` | 坐标值 |
**返回**: 包含浮点舍入误差的区间
**二维定向行列式的区间验证**
`inline Interval orient_2d_interval(double ax, double ay, double bx, double by, double cx, double cy) {`
| 参数 | 说明 |
|------|------|
| `ax,ay` | 点 a 的坐标 |
| `bx,by` | 点 b 的坐标 |
| `cx,cy` | 点 c 的坐标 |
**返回**: 行列式的区间值
**参见**: `orient_2d_verified`
**使用区间算术验证 orient_2d 结果**
`inline int orient_2d_verified(double ax, double ay, double bx, double by, double cx, double cy) {`
| 参数 | 说明 |
|------|------|
| `ax,ay` | 点 a 的坐标 |
| `bx,by` | 点 b 的坐标 |
| `cx,cy` | 点 c 的坐标 |
**返回**: 1 确认 CounterClockwise
**参见**: `orient_2d_interval, Interval::cmp`
### `io_gltf.h`
**glTF 2.0 导出选项**
`struct GltfOptions {`
**导出网格为 glTF 2.0 / GLB 格式**
`bool write_gltf(const std::string& filepath, const mesh::HalfedgeMesh& mesh,`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径(.glb 或 .gltf |
| `mesh` | 要导出的半边网格 |
| `options` | 导出选项(格式、法线、颜色等) |
**返回**: false 导出失败(文件无法创建等)
> 生成的 glTF 符合 2.0 规范,兼容 Blender、three.js、Unreal Engine 等工具
**参见**: `write_brep_gltf, GltfOptions`
**导出 B-Rep 模型为 GLB 格式(通过面片化)**
`bool write_brep_gltf(const std::string& filepath, const brep::BrepModel& model,`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径(建议 .glb) |
| `model` | 要导出的 B-Rep 模型 |
| `tessellation_res` | 每条边的离散段数(默认 32),越大越精确 |
**返回**: false 导出失败
**参见**: `write_gltf`
### `io_obj.h`
**OBJ 文件解析结果数据结构**
`struct ObjMeshData {`
**每个面的顶点索引列表(0-based)**
`std::vector<std::vector<int>> faces`
**每个面的纹理坐标索引列表(0-based)**
`std::vector<std::vector<int>> face_texcoords`
**每个面的法线索引列表(0-based)**
`std::vector<std::vector<int>> face_normals`
**每个面对应的材质名称**
`std::vector<std::string> face_materials`
**读取 Wavefront OBJ 文件**
`ObjMeshData read_obj(const std::string& filepath)`
| 参数 | 说明 |
|------|------|
| `filepath` | OBJ 文件路径 |
**返回**: 解析后的 ObjMeshData
> 不解析 MTL 材质文件,仅记录 usemtl 指令中的材质名称
> 面索引在内部转换为 0-based;若文件中使用相对索引(负值),自动转换为正向
**参见**: `write_obj, ObjMeshData`
**写入 Wavefront OBJ 文件**
`void write_obj(const std::string& filepath, const ObjMeshData& data)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径 |
| `data` | 要写出的网格数据 |
> 输出的面索引为 1-based(OBJ 标准)
**参见**: `read_obj`
### `io_ply.h`
**读取 PLY 文件(Stanford Polygon Format**
`mesh::HalfedgeMesh read_ply(const std::string& filepath)`
| 参数 | 说明 |
|------|------|
| `filepath` | PLY 文件路径 |
**返回**: 解析后的半边网格
> 自动检测文件头部 magic number 判断 ASCII / 二进制格式
> 二进制格式仅支持小端序(little-endian
> 返回类型为 HalfedgeMesh,内部自动建立半边拓扑
**参见**: `write_ply`
**写入 PLY 文件(ASCII 格式)**
`void write_ply(const std::string& filepath, const mesh::HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径 |
| `mesh` | 要导出的半边网格 |
> 输出的 PLY 为 ASCII 编码,易于人工阅读和编辑
> 若需要二进制输出以提高性能,请使用 BinarySerializer
**参见**: `read_ply, BinarySerializer`
### `io_stl.h`
**STL 三角形面片**
`struct StlTriangle {`
**读取 STL 文件(自动检测格式)**
`std::vector<StlTriangle> read_stl(const std::string& filepath)`
| 参数 | 说明 |
|------|------|
| `filepath` | STL 文件路径 |
**返回**: 三角形面片列表
> 自动格式检测:二进制 STL 的 80 字节头后跟 4 字节三角形数量
> ASCII STL 以 "solid name" 开头
**参见**: `write_stl, write_stl_ascii`
**写入二进制 STL 文件**
`void write_stl(const std::string& filepath, const std::vector<StlTriangle>& tris)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径 |
| `tris` | 三角形面片列表 |
> 二进制 STL 格式:80 字节头 + 4 字节三角形数 + 每三角形 50 字节
> 法向量在写入时自动归一化
**参见**: `read_stl, write_stl_ascii`
**写入 ASCII STL 文件**
`void write_stl_ascii(const std::string& filepath, const std::vector<StlTriangle>& tris)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径 |
| `tris` | 三角形面片列表 |
**参见**: `read_stl, write_stl`
### `math_types.h`
**通用 N 维点类型(使用 Eigen 列向量)**
`template <typename T, size_t Dim>`
**通用 N 维向量类型(与 Point 相同的列向量表示)**
`template <typename T, size_t Dim>`
**基础模块提供 VDE 引擎的核心基础设施:**
`/** @} */ // end of foundation group`
### `memory_pool.h`
**固定块大小的内存池**
`template <typename T>`
> 内存池不调用对象的构造函数/析构函数,仅管理原始内存
> 适合 POD 类型或通过 placement new 手动管理生命周期的类型
**构造内存池**
`explicit MemoryPool(size_t chunk_size = 1024) : chunk_size_(chunk_size) {}`
| 参数 | 说明 |
|------|------|
| `chunk_size` | 每个内存块可容纳的对象数(默认 1024) |
**析构内存池,释放所有已分配的内存块**
`~MemoryPool() { for (auto* p : chunks_) ::operator delete(p); }`
**从池中分配 n 个 T 对象的内存**
`T* allocate(size_t n = 1) {`
| 参数 | 说明 |
|------|------|
| `n` | 对象数量(当前未使用,保留用于 API 兼容) |
**返回**: 指向未初始化内存的指针
**将内存归还到池中**
`void deallocate(T* p, size_t = 1) {`
| 参数 | 说明 |
|------|------|
| `p` | 之前从 allocate() 获取的指针 |
**分配一个新的内存块并初始化空闲链表**
`void allocate_chunk() {`
### `predicates.h`
**统一谓词接口 — 编译时选择 GMP 或自适应双精度后端**
`struct Predicates {`
**二维定向测试**
`static exact::Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三点 |
**返回**: 定向结果
**三维定向测试**
`static exact::Orientation orient_3d(const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c,d` | 四点 |
**返回**: 定向结果
**圆内测试**
`static exact::CircleTest in_circle(const Point2D& a, const Point2D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三角形三顶点 |
| `d` | 测试点 |
**返回**: 圆测试结果
**二维定向测试便捷封装**
`inline exact::Orientation orient(const Point2D& a, const Point2D& b, const Point2D& c) {`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三个二维点 |
**返回**: Orientation::Clockwise / CounterClockwise / Collinear
**三维定向测试便捷封装**
`inline exact::Orientation orient(const Point3D& a, const Point3D& b, const Point3D& c, const Point3D& d) {`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 定义平面的三点 |
| `d` | 测试点 |
**返回**: Orientation::Clockwise / CounterClockwise / Collinear
**圆内测试便捷封装**
`inline exact::CircleTest in_circle(const Point2D& a, const Point2D& b, const Point2D& c, const Point2D& d) {`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三角形三顶点 |
| `d` | 测试点 |
**返回**: CircleTest::Inside / On / Outside
### `serializer.h`
**二进制序列化格式的网格数据结构**
`struct SerializedMesh {`
**二进制序列化器**
> 该格式专为 VDE 内部快速读写设计,不适用于跨平台数据交换
> 使用 glTF/OBJ/STL 进行外部交换,此格式用于本地缓存
**序列化网格到二进制缓冲区**
`static std::vector<uint8_t> serialize(const mesh::HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 要序列化的半边网格 |
**返回**: 压缩后的二进制数据(含文件头)
**从二进制缓冲区反序列化网格**
`static mesh::HalfedgeMesh deserialize(const std::vector<uint8_t>& data)`
| 参数 | 说明 |
|------|------|
| `data` | 之前由 serialize() 生成的二进制数据 |
**返回**: 恢复的半边网格
**序列化并写入文件**
`static bool write_file(const std::string& path, const mesh::HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `path` | 输出文件路径 |
| `mesh` | 要保存的半边网格 |
**返回**: false 文件创建失败
**参见**: `read_file`
**从文件读取并反序列化**
`static mesh::HalfedgeMesh read_file(const std::string& path)`
| 参数 | 说明 |
|------|------|
| `path` | VDE 二进制格式文件路径 |
**返回**: 恢复的半边网格
**参见**: `write_file`
**VDE 二进制文件魔数:"VDEGEOM\0"**
**VDE 二进制格式当前版本号**
### `tolerance.h`
**分层容差管理类**
**构造容差对象**
`Tolerance(double absolute = 1e-6, double relative = 1e-8,`
| 参数 | 说明 |
|------|------|
| `absolute` | 绝对容差,默认 1e-6 |
| `relative` | 相对容差,默认 1e-8 |
| `angular` | 角度容差(弧度),默认 1e-8 |
| `snapping` | 吸附容差,默认 1e-4 |
**判断两点是否相等(基于绝对容差)**
`bool points_equal(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b) const {`
| 参数 | 说明 |
|------|------|
| `a` | 第一个点(Eigen 矩阵) |
| `b` | 第二个点(Eigen 矩阵) |
**返回**: true 若两点的欧氏距离 < absolute_
**判断值是否接近零**
`template <typename T>`
| 参数 | 说明 |
|------|------|
| `value` | 测试值 |
**返回**: true 若 |value| < absolute_
**混合容差相等判断**
`template <typename T>`
| 参数 | 说明 |
|------|------|
| `a` | 第一个值 |
| `b` | 第二个值 |
**返回**: true 若两值在容差范围内相等
**收紧容差**
`Tolerance tighten(double factor = 0.1) const {`
| 参数 | 说明 |
|------|------|
| `factor` | 收紧因子(默认 0.1 |
**返回**: 收紧后的新容差对象
**放宽容差**
`Tolerance relax(double factor = 10.0) const {`
| 参数 | 说明 |
|------|------|
| `factor` | 放宽因子(默认 10.0 |
**返回**: 放宽后的新容差对象
**合并两个容差,取更严格的(更小的)**
`static Tolerance min(const Tolerance& a, const Tolerance& b) {`
| 参数 | 说明 |
|------|------|
| `a` | 第一个容差 |
| `b` | 第二个容差 |
**返回**: 每项取 min 的新容差
**获取全局容差实例**
`static Tolerance& global() { return global_; }`
**返回**: 全局容差的引用
**设置全局容差**
`static void set_global(const Tolerance& tol) { global_ = tol; }`
| 参数 | 说明 |
|------|------|
| `tol` | 新的全局容差 |
> 推荐使用 ToleranceScope 进行临时修改,确保自动恢复
**局部容差作用域(RAII**
**进入新的容差作用域**
`explicit ToleranceScope(const Tolerance& tol) : previous_(Tolerance::global()) {`
| 参数 | 说明 |
|------|------|
| `tol` | 此作用域内使用的容差 |
**退出容差作用域,恢复之前的全局容差**
`~ToleranceScope() { Tolerance::set_global(previous_); }`
## 核心几何 (`vde::core`)
### `aabb.h`
**轴对齐包围盒(AABB**
`template <typename T>`
> 初始状态为空(min = +∞, max = -∞),需要通过 expand() 初始化
**构造空包围盒**
`AABB() : min_(Point3D::Constant(std::numeric_limits<T>::max())),`
**从两个角点构造包围盒**
`AABB(const Point3D& min, const Point3D& max) : min_(min), max_(max) {}`
| 参数 | 说明 |
|------|------|
| `min` | 最小角点 |
| `max` | 最大角点 |
**扩展包围盒以包含给定点**
`void expand(const Point3D& p) {`
| 参数 | 说明 |
|------|------|
| `p` | 要包含的点 |
**扩展包围盒以包含另一个 AABB**
`void expand(const AABB& other) {`
| 参数 | 说明 |
|------|------|
| `other` | 另一个包围盒 |
**包围盒中心点**
`[[nodiscard]] Point3D center() const { return (min_ + max_) * 0.5; }`
**返回**: (min + max) / 2
**包围盒对角线向量(从 min 到 max)**
`[[nodiscard]] Vector3D extent() const { return max_ - min_; }`
**返回**: max - min
**包围盒表面积**
`[[nodiscard]] T surface_area() const {`
**返回**: 2 * (dx*dy + dy*dz + dz*dx)
**包围盒体积**
`[[nodiscard]] T volume() const {`
**返回**: dx * dy * dz
**测试点是否在包围盒内部(含边界)**
`[[nodiscard]] bool contains(const Point3D& p) const {`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
**返回**: true 若 min ≤ p ≤ max(各分量)
**测试两个包围盒是否相交(含边界接触)**
`[[nodiscard]] bool intersects(const AABB& other) const {`
| 参数 | 说明 |
|------|------|
| `other` | 另一个包围盒 |
**返回**: true 若存在交集
### `convex_hull.h`
**二维凸包计算(Graham Scan 算法)**
`std::vector<Point2D> convex_hull_2d(const std::vector<Point2D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入点集(至少 3 个不共线点) |
**返回**: 凸包顶点序列(逆时针排列),不含共线的中间点
> 自动过滤共线点,返回严格的凸包顶点
> 若所有点共线,返回两个端点
**参见**: `convex_hull_3d, Polygon2D::convex_hull_2d`
**三维凸包计算(QuickHull 算法)**
`std::vector<std::array<Point3D, 3>> convex_hull_3d(const std::vector<Point3D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入点集(至少 4 个不共面点) |
**返回**: 凸包三角形列表,每个三角形三顶点按逆时针排列(从外部观察)
> 返回的三角形法线方向朝外
> 共面/退化点被自动丢弃
**参见**: `convex_hull_2d`
### `distance.h`
**两点之间的欧氏距离**
`double distance(const Point3D& a, const Point3D& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个点 |
| `b` | 第二个点 |
**返回**: ||b - a||
**点到直线的距离**
`double distance(const Point3D& p, const Line3D<double>& line)`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
| `line` | 直线 |
**返回**: 垂直距离
**点到线段的距离**
`double distance(const Point3D& p, const Segment3D<double>& seg)`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
| `seg` | 线段 |
**返回**: 最短距离
**点到平面的距离**
`double distance(const Point3D& p, const Plane<double>& plane)`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
| `plane` | 平面 |
**返回**: 绝对垂直距离
**参见**: `Plane::signed_distance`
**点到三角形的距离**
`double distance(const Point3D& p, const Triangle<double>& tri)`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
| `tri` | 三角形 |
**返回**: 最短距离
**点到包围盒的距离**
`double distance(const Point3D& p, const AABB<double>& box)`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
| `box` | 包围盒 |
**返回**: 最短距离(内部点返回 0
**两条线段之间的最短距离**
`double distance(const Segment3D<double>& a, const Segment3D<double>& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一条线段 |
| `b` | 第二条线段 |
**返回**: 最短距离(若相交则为 0
**两条直线之间的最短距离**
`double distance(const Line3D<double>& a, const Line3D<double>& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一条直线 |
| `b` | 第二条直线 |
**返回**: 最短距离
**两个包围盒之间的最短距离**
`double distance(const AABB<double>& a, const AABB<double>& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个包围盒 |
| `b` | 第二个包围盒 |
**返回**: 最短距离
**两个三角形之间的最短距离**
`double distance(const Triangle<double>& a, const Triangle<double>& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个三角形 |
| `b` | 第二个三角形 |
**返回**: 最短距离(若相交则为 0
**三角形上距给定点最近的点**
`Point3D closest_point(const Point3D& p, const Triangle<double>& tri)`
| 参数 | 说明 |
|------|------|
| `p` | 查询点 |
| `tri` | 三角形 |
**返回**: 三角形上距离 p 最近的点
**线段上距给定点最近的点**
`Point3D closest_point(const Point3D& p, const Segment3D<double>& seg)`
| 参数 | 说明 |
|------|------|
| `p` | 查询点 |
| `seg` | 线段 |
**返回**: 线段上距离 p 最近的点(可能为端点)
**包围盒上距给定点最近的点**
`Point3D closest_point(const Point3D& p, const AABB<double>& box)`
| 参数 | 说明 |
|------|------|
| `p` | 查询点 |
| `box` | 包围盒 |
**返回**: 包围盒边界上(或内部)距离 p 最近的点
**平面上距给定点最近的点(正交投影)**
`Point3D closest_point(const Point3D& p, const Plane<double>& plane)`
| 参数 | 说明 |
|------|------|
| `p` | 查询点 |
| `plane` | 平面 |
**返回**: 点 p 在平面上的正交投影
**参见**: `Plane::project`
### `icp.h`
**ICP(迭代最近点)配准结果**
`struct ICPResult {`
**配准后的均方根误差**
`double rms_error`
**迭代最近点(ICP)刚体点云配准**
`[[nodiscard]] ICPResult icp_register(const std::vector<Point3D>& source,`
| 参数 | 说明 |
|------|------|
| `source` | 源点云(将被移动) |
| `target` | 目标点云(固定参考) |
| `max_iter` | 最大迭代次数(默认 50 |
| `tolerance` | 收敛容差:相邻两次 RMS 变化的阈值(默认 1e-6) |
**返回**: 配准结果,包含最终变换和误差
> source 和 target 点数可以不同
> 初始对齐越好,收敛越快;若初始偏差太大,可能收敛到局部最优
### `line.h`
**三维无限直线**
`template <typename T>`
**从原点和方向构造直线**
`Line3D(const Point3D& origin, const Vector3D& direction)`
| 参数 | 说明 |
|------|------|
| `origin` | 直线上一点 |
| `direction` | 方向向量(自动归一化) |
**参数方程求点**
`[[nodiscard]] Point3D point_at(T t) const { return origin_ + direction_ * t; }`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
**返回**: origin + direction * t
**三维线段**
`template <typename T>`
**从两个端点构造线段**
`Segment3D(const Point3D& p0, const Point3D& p1) : p0_(p0), p1_(p1) {}`
| 参数 | 说明 |
|------|------|
| `p0` | 起点 |
| `p1` | 终点 |
**方向向量(未归一化)**
`[[nodiscard]] Vector3D direction() const { return p1_ - p0_; }`
**返回**: p1 - p0
**线段长度**
`[[nodiscard]] T length() const { return direction().norm(); }`
**返回**: ||p1 - p0||
**三维射线**
`template <typename T>`
**从原点和方向构造射线**
`Ray3D(const Point3D& origin, const Vector3D& direction)`
| 参数 | 说明 |
|------|------|
| `origin` | 射线起点 |
| `direction` | 方向向量(自动归一化) |
**参数方程求点(t ≥ 0**
`[[nodiscard]] Point3D point_at(T t) const { return origin_ + direction_ * t; }`
| 参数 | 说明 |
|------|------|
| `t` | 参数值(应为非负) |
**返回**: origin + direction * t
### `plane.h`
**三维平面**
`template <typename T>`
**从点和法线构造平面**
`Plane(const Point3D& point, const Vector3D& normal)`
| 参数 | 说明 |
|------|------|
| `point` | 平面上一点 |
| `normal` | 法向量(自动归一化) |
**从三点构造平面**
`Plane(const Point3D& a, const Point3D& b, const Point3D& c)`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 平面上不共线的三点(右手定则决定法线方向) |
**获取平面方程常数 d**
`[[nodiscard]] T d() const { return d_; }`
**返回**: d 值
**有向点到平面距离**
`[[nodiscard]] T signed_distance(const Point3D& p) const { return normal_.dot(p) + d_; }`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
**返回**: normal · p + d
**绝对点到平面距离**
`[[nodiscard]] T distance(const Point3D& p) const { return std::abs(signed_distance(p)); }`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
**返回**: |signed_distance(p)|
**点在平面上的正交投影**
`[[nodiscard]] Point3D project(const Point3D& p) const {`
| 参数 | 说明 |
|------|------|
| `p` | 原点 |
**返回**: 投影点(满足在平面上且连线垂直于平面)
### `point.h`
**核心模块提供 VDE 引擎的几何操作 API:**
**通用 N 维点类型(重新导出,便于 core 模块使用)**
`template <typename T, size_t Dim>`
**通用 N 维向量类型(重新导出)**
`template <typename T, size_t Dim>`
### `polygon.h`
**二维平面多边形**
> 内部假设简单多边形(无自交),非简单多边形的行为未定义
> 所有几何计算基于(假设的)XY 平面
**从顶点列表构造多边形**
`explicit Polygon2D(std::vector<Point2D> vertices) : vertices_(std::move(vertices)) {}`
| 参数 | 说明 |
|------|------|
| `vertices` | 顶点序列(逆时针或顺时针均可) |
**有向面积(Shoelace 公式)**
`[[nodiscard]] double signed_area() const`
**返回**: 有向面积
**绝对面积**
`[[nodiscard]] double area() const { return std::abs(signed_area()); }`
**返回**: |signed_area()|
**周长(各边长之和)**
`[[nodiscard]] double perimeter() const`
**返回**: 总边长
**面积加权质心**
`[[nodiscard]] Point2D centroid() const`
**返回**: 质心坐标
**二维轴对齐包围盒**
`[[nodiscard]] AABB<double> bounding_box() const`
**返回**: 包围盒
**点包含测试(射线法)**
`[[nodiscard]] bool contains(const Point2D& p) const`
| 参数 | 说明 |
|------|------|
| `p` | 测试点 |
**返回**: true 若点在多边形内部或边界上
> 边界上的点也返回 true
**多边形是否为逆时针方向**
`[[nodiscard]] bool is_ccw() const { return signed_area() > 0; }`
**返回**: signed_area() > 0
**Douglas-Peucker 简化**
`[[nodiscard]] Polygon2D simplify(double tolerance) const`
| 参数 | 说明 |
|------|------|
| `tolerance` | 允许的最大偏差 |
**返回**: 简化后的新多边形
**参见**: `triangulate`
**耳切法三角剖分(Ear Clipping**
`[[nodiscard]] std::vector<std::array<int, 3>> triangulate() const`
**返回**: 三角形列表,每个元素为 {i, j, k} 表示顶点索引
> 时间复杂度 O(n²),适用于顶点数 < 1000 的多边形
**参见**: `simplify`
**Andrew's Monotone Chain 二维凸包**
`static Polygon2D convex_hull_2d(const std::vector<Point2D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入点集 |
**返回**: 凸包多边形(CCW,不含共线中间点)
**参见**: `convex_hull_2d`
### `transform.h`
**三维仿射变换类型**
`using Transform3D = Eigen::Transform<double, 3, Eigen::Affine>`
**创建平移变换**
`inline Transform3D translate(const Vector3D& v) {`
| 参数 | 说明 |
|------|------|
| `v` | 平移向量 |
**返回**: 平移变换矩阵
**创建平移变换(分量形式)**
`inline Transform3D translate(double x, double y, double z) {`
| 参数 | 说明 |
|------|------|
| `x` | X 方向位移 |
| `y` | Y 方向位移 |
| `z` | Z 方向位移 |
**返回**: 平移变换矩阵
**创建旋转变换(轴-角表示)**
`inline Transform3D rotate(const Vector3D& axis, double angle_rad) {`
| 参数 | 说明 |
|------|------|
| `axis` | 旋转轴(自动归一化) |
| `angle_rad` | 旋转角度(弧度) |
**返回**: 旋转变换矩阵
**绕 X 轴旋转**
`inline Transform3D rotate_x(double rad) { return rotate(Vector3D::UnitX(), rad); }`
| 参数 | 说明 |
|------|------|
| `rad` | 旋转角度(弧度) |
**返回**: 旋转变换矩阵
**绕 Y 轴旋转**
`inline Transform3D rotate_y(double rad) { return rotate(Vector3D::UnitY(), rad); }`
| 参数 | 说明 |
|------|------|
| `rad` | 旋转角度(弧度) |
**返回**: 旋转变换矩阵
**绕 Z 轴旋转**
`inline Transform3D rotate_z(double rad) { return rotate(Vector3D::UnitZ(), rad); }`
| 参数 | 说明 |
|------|------|
| `rad` | 旋转角度(弧度) |
**返回**: 旋转变换矩阵
**创建非均匀缩放变换**
`inline Transform3D scale(double sx, double sy, double sz) {`
| 参数 | 说明 |
|------|------|
| `sx` | X 方向缩放因子 |
| `sy` | Y 方向缩放因子 |
| `sz` | Z 方向缩放因子 |
**返回**: 缩放变换矩阵
> 非均匀缩放可能导致法线方向不准确;使用场景中应考虑法线变换 = (M^{-1})^T
**创建均匀缩放变换**
`inline Transform3D scale(double s) { return scale(s, s, s); }`
| 参数 | 说明 |
|------|------|
| `s` | 各方向统一的缩放因子 |
**返回**: 缩放变换矩阵
### `triangle.h`
**三维三角形**
`template <typename T>`
**从三个顶点构造三角形**
`Triangle(const Point3D& v0, const Point3D& v1, const Point3D& v2)`
| 参数 | 说明 |
|------|------|
| `v0` | 第一个顶点 |
| `v1` | 第二个顶点 |
| `v2` | 第三个顶点 |
**获取第 i 个顶点**
`[[nodiscard]] const Point3D& v(int i) const { return v_[i]; }`
| 参数 | 说明 |
|------|------|
| `i` | 顶点索引(0, 1, 2 |
**返回**: 顶点引用
**三角形单位法向量**
`[[nodiscard]] Vector3D normal() const {`
**返回**: 单位法向量
> 若三角形退化(面积为零),返回零向量
**三角形面积**
`[[nodiscard]] T area() const {`
**返回**: 0.5 * ||(v1 - v0) × (v2 - v0)||
**三角形质心(几何中心)**
`[[nodiscard]] Point3D centroid() const {`
**返回**: (v0 + v1 + v2) / 3
**重心坐标包含测试**
`[[nodiscard]] bool contains(const Point3D& p) const {`
| 参数 | 说明 |
|------|------|
| `p` | 测试点(三维空间中的任意点) |
**返回**: true 若投影点在三角形内部或边界上
> 该测试等效于三维点在三角形上的包含测试(先投影再测试)
### `voronoi.h`
**Voronoi 单元格**
`struct VoronoiCell {`
**单元格边界顶点(按逆时针顺序排列)**
`std::vector<Point2D> vertices`
**单元格边界边**
`std::vector<std::array<int, 2>> edges`
**二维 Voronoi 图生成(通过 Delaunay 对偶图)**
`std::vector<VoronoiCell> voronoi_2d(const std::vector<Point2D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入点集(站点) |
**返回**: 每个站点对应的 VoronoiCell 列表(顺序与输入一致)
> 对于凸包边界上的站点,对应的 Voronoi 单元格无界,顶点不完全闭合
> 内部使用 Delaunay 三角剖分作为中间步骤
## 曲线曲面 (`vde::curves`)
### `bezier_curve.h`
**任意阶 Bézier 曲线**
**构造 Bézier 曲线**
`explicit BezierCurve(std::vector<Point3D> control_points)`
| 参数 | 说明 |
|------|------|
| `control_points` | 控制点序列,点数 = degree + 1,最少 2 个 |
> 控制点数量决定了曲线阶次;点数越多,曲线越灵活但计算越昂贵
**在参数 t 处求值曲线点**
`[[nodiscard]] Point3D evaluate(double t) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值,范围 [0, 1] |
**返回**: 曲线上对应 t 的点坐标
> 使用 de Casteljau 递推算法,O(n²) 复杂度
**在参数 t 处求导数**
`[[nodiscard]] Vector3D derivative(double t, int order = 1) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值,范围 [0, 1] |
| `order` | 导数阶数,1 = 一阶(切向量),2 = 二阶(曲率相关) |
**返回**: 导数向量
> 高阶导数通过降阶 Bézier 曲线计算:
**曲线阶次**
`[[nodiscard]] int degree() const { return static_cast<int>(cp_.size()) - 1; }`
**返回**: 阶次 = 控制点数 - 1
**参数定义域**
`[[nodiscard]] std::pair<double, double> domain() const { return {0.0, 1.0}; }`
**返回**: 固定为 [0, 1]
**控制点访问**
`[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }`
**返回**: 控制点向量的只读引用
**在 t 处将曲线一分为二**
`[[nodiscard]] std::pair<BezierCurve, BezierCurve> split(double t) const`
| 参数 | 说明 |
|------|------|
| `t` | 分割参数,范围 [0, 1] |
**返回**: 左段 + 右段两条 Bézier 曲线
> 使用 de Casteljau 分割算法,分割点为三角阵的对角线
**升阶操作**
`[[nodiscard]] BezierCurve degree_elevate(int times = 1) const`
| 参数 | 说明 |
|------|------|
| `times` | 升阶次数,≥ 1 |
**返回**: 升阶后的 Bézier 曲线(控制点数增加 times,形状不变)
> 通过反复应用公式 P_i' = i/(n+1) P_{i-1} + (1 - i/(n+1)) P_i
**参见**: `split`
### `bezier_surface.h`
**Bézier 张量积曲面**
**构造 Bézier 曲面**
`BezierSurface(std::vector<std::vector<Point3D>> control_grid)`
| 参数 | 说明 |
|------|------|
| `control_grid` | 控制点网格,grid[i][j] 对应 u 方向第 i 个、v 方向第 j 个控制点 |
> grid 必须矩整(所有行等长);grid.size() = degree_u+1, grid[0].size() = degree_v+1
**求曲面点 S(u,v)**
`[[nodiscard]] Point3D evaluate(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数,范围 [0, 1] |
| `v` | v 参数,范围 [0, 1] |
**返回**: 曲面上对应 (u,v) 的 3D 坐标
> 张量积求值:先按 v 方向对每行做 de Casteljau,再沿 u 方向对结果做一次
**u 方向偏导数 ∂S/∂u**
`[[nodiscard]] Vector3D derivative_u(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: u 方向切向量
> 通过降阶 Bézier 曲线计算:对 v 求值后沿 u 求导
**v 方向偏导数 ∂S/∂v**
`[[nodiscard]] Vector3D derivative_v(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: v 方向切向量
**单位法向量 N(u,v) = (∂S/∂u × ∂S/∂v) / |…|**
`[[nodiscard]] Vector3D normal(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: 归一化法向量(指向曲面的特选侧)
> 当两个偏导数平行时返回零向量(奇异点)
**u 向阶次**
`[[nodiscard]] int degree_u() const { return static_cast<int>(cp_.size()) - 1; }`
**返回**: u 方向阶次(控制点行数 - 1)
**v 向阶次**
`[[nodiscard]] int degree_v() const { return static_cast<int>(cp_[0].size()) - 1; }`
**返回**: v 方向阶次(控制点列数 - 1)
**一维 de Casteljau 求值(内部辅助)**
`[[nodiscard]] Point3D de_casteljau(double t, const std::vector<Point3D>& pts) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数 |
| `pts` | 一维控制点序列 |
**返回**: 求值结果
### `bspline_curve.h`
**B 样条曲线(非有理、均匀/非均匀节点)**
**构造 B 样条曲线**
`BSplineCurve(std::vector<Point3D> control_points,`
| 参数 | 说明 |
|------|------|
| `control_points` | n+1 个控制点 |
| `knots` | 节点向量,必须为非递减序列 |
| `degree` | 阶次 p |
> 节点数量 = 控制点数 + 阶次 + 1;clamped 端点多重度为 p+1
**在参数 t 处求值曲线点**
`[[nodiscard]] Point3D evaluate(double t) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值,必须在 domain() 范围内 |
**返回**: 曲线上对应 t 的点坐标
> 使用 de BoorCox-de Boor)递推算法
**在参数 t 处求导数**
`[[nodiscard]] Vector3D derivative(double t, int order = 1) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
| `order` | 导数阶数,1 = 一切向量 |
**返回**: 导数向量
> B 样条导数公式:
**曲线阶次**
`[[nodiscard]] int degree() const { return degree_; }`
**返回**: 阶次 p
**参数定义域**
`[[nodiscard]] std::pair<double, double> domain() const`
**返回**: 有效参数范围 [knots[p], knots[n+1]]
**控制点访问**
`[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }`
**返回**: 控制点数组只读引用
**节点向量访问**
`[[nodiscard]] const std::vector<double>& knots() const { return knots_; }`
**返回**: 节点向量只读引用
**查找 t 所在的节点区间**
`[[nodiscard]] int find_span(double t) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
**返回**: 节点区间索引 i 满足 knots[i] ≤ t < knots[i+1]
> 使用二分查找,O(log n);求值和基函数的前置步骤
**在 t 处求非零基函数值**
`[[nodiscard]] std::vector<double> basis_functions(double t, int span = -1) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
| `span` | 节点区间索引,-1 表示自动查找 |
**返回**: N_{span-p}(t), ..., N_{span}(t) 共 p+1 个值
> 仅返回 p+1 个非零基函数;用于端点求值及插值
**参见**: `find_span`
**在 t 处求非零基函数的一阶导数**
`[[nodiscard]] std::vector<double> basis_derivatives(double t, int span = -1) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
| `span` | 节点区间索引,-1 表示自动查找 |
**返回**: dN_{span-p}/du, ..., dN_{span}/du 共 p+1 个值
> B 样条基函数导数递推:
**参见**: `basis_functions`
### `bspline_surface.h`
**B 样条张量积曲面(非有理)**
**构造 B 样条曲面**
`BSplineSurface(std::vector<std::vector<Point3D>> control_grid,`
| 参数 | 说明 |
|------|------|
| `control_grid` | (nu+1)×(nv+1) 控制点网格 |
| `knots_u` | u 向节点向量,长度 = nu + pu + 1 |
| `knots_v` | v 向节点向量,长度 = nv + pv + 1 |
| `degree_u` | u 向阶次 pu |
| `degree_v` | v 向阶次 pv |
**求曲面点 S(u,v)**
`[[nodiscard]] Point3D evaluate(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: 曲面上的 3D 点
> 张量积分解:先行后列(或先列后行)做两次 B 样条求值
**u 向偏导数 ∂S/∂u**
`[[nodiscard]] Vector3D derivative_u(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: u 向切向量
**v 向偏导数 ∂S/∂v**
`[[nodiscard]] Vector3D derivative_v(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: v 向切向量
**单位法向量**
`[[nodiscard]] Vector3D normal(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: N(u,v) = (∂S/∂u × ∂S/∂v) / |…|
**u 向阶次**
`[[nodiscard]] int degree_u() const { return degree_u_; }`
**返回**: pu
**v 向阶次**
`[[nodiscard]] int degree_v() const { return degree_v_; }`
**返回**: pv
**u 向节点向量**
`[[nodiscard]] const std::vector<double>& knots_u() const { return knots_u_; }`
**返回**: 只读引用
**v 向节点向量**
`[[nodiscard]] const std::vector<double>& knots_v() const { return knots_v_; }`
**返回**: 只读引用
### `nurbs_curve.h`
**NURBS 曲线(Non-Uniform Rational B-Spline**
**构造 NURBS 曲线**
`NurbsCurve(std::vector<Point3D> control_points, std::vector<double> knots,`
| 参数 | 说明 |
|------|------|
| `control_points` | 控制点序列 |
| `knots` | 节点向量 |
| `weights` | 权重序列,必须与 control_points 等长,各分量 > 0 |
| `degree` | 阶次 p |
> 所有权重必须 > 0 以保证分母不为零(非退化)
**在参数 t 处求值**
`[[nodiscard]] Point3D evaluate(double t) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
**返回**: 曲线上对应 t 的点坐标
> 内部将 (w·P, w) 提升为齐次坐标的 B 样条,求值后投影回 3D
**在参数 t 处求导数**
`[[nodiscard]] Vector3D derivative(double t, int order = 1) const`
| 参数 | 说明 |
|------|------|
| `t` | 参数值 |
| `order` | 导数阶数 |
**返回**: 导数向量
> 有理导数公式:
**曲线阶次**
`[[nodiscard]] int degree() const { return degree_; }`
**返回**: p
**参数定义域**
`[[nodiscard]] std::pair<double, double> domain() const`
**返回**: [knots[degree], knots[n+1]]
**控制点访问**
`[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }`
**返回**: 只读引用
**权重访问**
`[[nodiscard]] const std::vector<double>& weights() const { return weights_; }`
**返回**: 只读引用
**节点向量访问**
`[[nodiscard]] const std::vector<double>& knots() const { return knots_; }`
**返回**: 只读引用
### `nurbs_operations.h`
**NURBS 曲面等距偏移**
`[[nodiscard]] NurbsSurface offset_surface(const NurbsSurface& surf, double distance)`
| 参数 | 说明 |
|------|------|
| `surf` | 输入 NURBS 曲面 |
| `distance` | 偏移距离(正值 = 沿法向外,负值 = 向内) |
**返回**: 偏移后的 NURBS 曲面(近似,阶次与原曲面相同)
> 这是几何近似,非精确偏移。对于大变曲率曲面,增大控制点数量
> 偏移可能导致自交(distance 超过曲面局部曲率半径时)
**参见**: `trim_surface blend_surfaces`
**NURBS 曲面参数域裁剪**
`[[nodiscard]] NurbsSurface trim_surface(const NurbsSurface& surf,`
| 参数 | 说明 |
|------|------|
| `surf` | 输入曲面 |
| `u_min,u_max` | 裁剪后的 u 参数范围(必须在原 domain 内) |
| `v_min,v_max` | 裁剪后的 v 参数范围(必须在原 domain 内) |
**返回**: 裁剪后的 NURBS 曲面
> 裁剪是"软裁剪"——几何不变,仅改变参数化。如需"硬裁剪"
**两 NURBS 曲面沿边界边的过渡面**
`[[nodiscard]] NurbsSurface blend_surfaces(const NurbsSurface& surf_a,`
| 参数 | 说明 |
|------|------|
| `surf_a` | 第一个曲面 |
| `surf_b` | 第二个曲面 |
| `edge_a` | surf_a 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max |
| `edge_b` | surf_b 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max |
| `blend_radius` | 过渡半径 |
**返回**: 过渡 NURBS 曲面(在偏移边界曲线间的直纹面)
> 过渡面与原始曲面在边界处为 C⁰ 连续(非切线连续)
**参见**: `ruled_surface`
**两 NURBS 曲线间的直纹面**
`[[nodiscard]] NurbsSurface ruled_surface(const NurbsCurve& curve_a,`
| 参数 | 说明 |
|------|------|
| `curve_a` | 第一条曲线(v=0 边界) |
| `curve_b` | 第二条曲线(v=1 边界) |
**返回**: 直纹 NURBS 曲面
> 两条曲线需有兼容的阶次和节点结构(内部执行升阶和节点精化)
**参见**: `coons_patch blend_surfaces`
**由四条边界曲线创建 Coons 曲面**
`[[nodiscard]] NurbsSurface coons_patch(const NurbsCurve& curve_u0,`
| 参数 | 说明 |
|------|------|
| `curve_u0` | v=0 处边界(沿 u 方向) |
| `curve_u1` | v=1 处边界(沿 u 方向) |
| `curve_v0` | u=0 处边界(沿 v 方向) |
| `curve_v1` | u=1 处边界(沿 v 方向) |
**返回**: Coons 曲面
> 仅保证边界插值,不保证内部形状与设计意图一致
**参见**: `ruled_surface`
**沿方向向量拉伸 NURBS 曲线为曲面**
`[[nodiscard]] NurbsSurface extrude_curve(const NurbsCurve& curve,`
| 参数 | 说明 |
|------|------|
| `curve` | 截面曲线 |
| `direction` | 拉伸方向(内部归一化) |
| `length` | 拉伸长度 |
**返回**: 拉伸 NURBS 曲面
**提取 NURBS 曲面的等参边界曲线**
`[[nodiscard]] NurbsCurve extract_boundary_curve(const NurbsSurface& surf, int edge)`
| 参数 | 说明 |
|------|------|
| `surf` | 输入曲面 |
| `edge` | 边界索引:0=u_min, 1=u_max, 2=v_min, 3=v_max |
**返回**: 指定边界上的 NURBS 曲线
> 边界曲线继承原曲面该方向的阶次和节点向量
### `nurbs_surface.h`
**NURBS 张量积曲面**
**构造 NURBS 曲面**
`NurbsSurface(std::vector<std::vector<Point3D>> control_grid,`
| 参数 | 说明 |
|------|------|
| `control_grid` | 控制点网格 |
| `knots_u` | u 向节点向量 |
| `knots_v` | v 向节点向量 |
| `weights` | 权重网格,维度与 control_grid 一致,所有值 > 0 |
| `degree_u` | u 向阶次 |
| `degree_v` | v 向阶次 |
**求曲面点 S(u,v)**
`[[nodiscard]] Point3D evaluate(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: 曲面上对应 (u,v) 的 3D 点
**u 向偏导数**
`[[nodiscard]] Vector3D derivative_u(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: ∂S/∂u
**v 向偏导数**
`[[nodiscard]] Vector3D derivative_v(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: ∂S/∂v
**单位法向量**
`[[nodiscard]] Vector3D normal(double u, double v) const`
| 参数 | 说明 |
|------|------|
| `u` | u 参数 |
| `v` | v 参数 |
**返回**: N(u,v) = normalize(∂S/∂u × ∂S/∂v)
**u 向阶次**
`[[nodiscard]] int degree_u() const { return degree_u_; }`
**返回**: pu
**v 向阶次**
`[[nodiscard]] int degree_v() const { return degree_v_; }`
**返回**: pv
**控制点数量**
`[[nodiscard]] std::array<int, 2> num_control_points() const {`
**返回**: {nu+1, nv+1},即网格的行数和列数
**u 向节点向量**
`[[nodiscard]] const std::vector<double>& knots_u() const { return knots_u_; }`
**返回**: 只读引用
**v 向节点向量**
`[[nodiscard]] const std::vector<double>& knots_v() const { return knots_v_; }`
**返回**: 只读引用
**控制点网格访问**
`[[nodiscard]] const std::vector<std::vector<Point3D>>& control_points() const { return cp_; }`
**返回**: 只读引用
**权重网格访问**
`[[nodiscard]] const std::vector<std::vector<double>>& weights() const { return weights_; }`
**返回**: 只读引用
**由两条 NURBS 曲线创建直纹面**
`static NurbsSurface ruled(const NurbsCurve& c1, const NurbsCurve& c2)`
| 参数 | 说明 |
|------|------|
| `c1` | 起始曲线(v=0 边界) |
| `c2` | 终止曲线(v=1 边界) |
**返回**: 直纹 NURBS 曲面
> 两条曲线需具有兼容的阶次和节点结构(内部做升阶和节点精化对齐)
**参见**: `blend_surfaces ruled_surface`
**由截面曲线旋转生成旋转曲面**
`static NurbsSurface revolve(const NurbsCurve& profile, const Point3D& axis_origin,`
| 参数 | 说明 |
|------|------|
| `profile` | 截面 NURBS 曲线 |
| `axis_origin` | 旋转轴上一点 |
| `axis_dir` | 旋转轴方向 |
| `angle_rad` | 旋转角度(弧度),≤ 2π |
**返回**: 旋转 NURBS 曲面
> 使用 NURBS 表示圆弧的权重方案;完整旋转生成闭曲面
**将 NURBS 曲面三角化**
`[[nodiscard]] std::pair<std::vector<Point3D>, std::vector<std::array<int,3>>>`
| 参数 | 说明 |
|------|------|
| `res_u` | u 方向采样分辨率 |
| `res_v` | v 方向采样分辨率 |
**返回**: {顶点数组, 三角形索引数组},每个三角形为 {i0,i1,i2}
> 生成 res_u×res_v 均匀网格,每个单元格拆为两个三角形
**参见**: `tessellate`
### `tessellation.h`
**均匀参数化曲面三角化**
`std::pair<std::vector<Point3D>, std::vector<std::array<int, 3>>>`
| 参数 | 说明 |
|------|------|
| `eval` | 曲面求值函数 eval(u,v) -> Point3D,参数 (u,v) ∈ [0,1]×[0,1] |
| `res_u` | u 方向子分段数(≥ 1 |
| `res_v` | v 方向子分段数(≥ 1 |
**返回**: {顶点数组, 三角形索引数组},三角形为 {i0,i1,i2}
> 总顶点数 = (res_u+1)×(res_v+1),三角形数 = 2×res_u×res_v
**参见**: `adaptive_tessellate`
**自适应曲面三角化**
`std::pair<std::vector<Point3D>, std::vector<std::array<int, 3>>>`
| 参数 | 说明 |
|------|------|
| `eval` | 曲面求值函数 eval(u,v) -> Point3D |
| `normal_fn` | 单位法向函数 normal_fn(u,v) -> Vector3D |
| `min_res` | 初始每向子分段数(≥ 1),默认 2 |
| `max_depth` | 最大递归深度,限制总面数,默认 6 |
| `angle_threshold_deg` | 法向角度偏差阈值(度),默认 5.0 |
**返回**: {顶点数组, 三角形索引数组}
> 最终面数上限约为 2·min_res²·4^max_depth(实际远小于此上限)
**参见**: `tessellate`
## 网格处理 (`vde::mesh`)
### `alpha_shapes.h`
**Alpha Shapes 点云表面重建**
`TetrahedronMesh alpha_shapes(const std::vector<Point3D>& points, double alpha)`
| 参数 | 说明 |
|------|------|
| `points` | 输入 3D 点云 |
| `alpha` | α 半径阈值,通常取平均点间距的 1~3 倍 |
**返回**: TetrahedronMesh 保留的四面体网格
**参见**: `alpha_shapes_surface delaunay_3d`
**将 Alpha Shapes 四面体网格的表面提取为三角形网格**
`std::pair<std::vector<Point3D>, std::vector<std::array<int,3>>>`
| 参数 | 说明 |
|------|------|
| `tet_mesh` | Alpha Shapes 输出的四面体网格 |
**返回**: {顶点数组, 三角形索引数组}
> 表面三角形法向指向四面体外部(右手定则)
**参见**: `alpha_shapes`
### `cdt_2d.h`
**约束 Delaunay 三角化(CDT**
`DelaunayResult constrained_delaunay_2d(`
| 参数 | 说明 |
|------|------|
| `points` | 输入 2D 点集 |
| `constraints` | 约束边列表,每项为 {起点索引, 终点索引} |
**返回**: DelaunayResult 含约束边的三角化结果
> 约束边不能相交(否则行为未定义);自相交约束需先分割交点
**参见**: `delaunay_2d`
### `delaunay_2d.h`
**2D Delaunay 三角化结果**
`struct DelaunayResult {`
**2D Delaunay 三角化(Bowyer-Watson 增量算法)**
`DelaunayResult delaunay_2d(const std::vector<Point2D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入 2D 点集(至少 3 个不共线点) |
**返回**: DelaunayResult 三角化结果
> 时间复杂度:平均 O(n log n),最坏 O(n²)
**参见**: `constrained_delaunay_2d`
### `delaunay_3d.h`
**四面体网格结构**
`struct TetrahedronMesh {`
**3D Delaunay 四面体化(Bowyer-Watson 增量算法)**
`TetrahedronMesh delaunay_3d(const std::vector<Point3D>& points)`
| 参数 | 说明 |
|------|------|
| `points` | 输入 3D 点集(至少 4 个不共面点) |
**返回**: TetrahedronMesh 四面体网格
> 时间复杂度与 2D 类似:平均 O(n log n),最坏 O(n²)
> 输出包括内部和边界四面体;通过 alpha_shapes 可提取表面
**参见**: `alpha_shapes`
### `geodesic.h`
**热方法(Heat Method)计算测地距离**
`std::vector<double> geodesic_distance(const HalfedgeMesh& mesh,`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
| `sources` | 源顶点索引列表(距离为 0 的顶点) |
| `t` | 时间步长,< 0 时自动设为平均边长平方 |
**返回**: 每顶点到最近源点的测地距离
> 要求网格为连通流形;时间步长 t 越小精度越高但数值越不稳定
### `halfedge_mesh.h`
**半边数据结构元素**
`struct Halfedge {`
**面元素**
`struct Face {`
**半边数据结构三角网格**
**清空所有数据**
`void clear()`
**添加顶点**
`int add_vertex(const Point3D& p)`
| 参数 | 说明 |
|------|------|
| `p` | 3D 坐标 |
**返回**: 新顶点的索引(0-based
**添加面**
`int add_face(const std::vector<int>& vertex_indices)`
| 参数 | 说明 |
|------|------|
| `vertex_indices` | 按逆时针顺序排列的顶点索引(至少 3 个) |
**返回**: 新面的索引,失败返回 -1
> 自动创建/查找半边并设置对侧关系;面法向遵循右手定则
**从三角形列表批量构建半边形网格**
`void build_from_triangles(const std::vector<Point3D>& verts,`
| 参数 | 说明 |
|------|------|
| `verts` | 顶点位置数组 |
| `tris` | 三角形索引数组,每个 {i0,i1,i2} |
> 等价于反复调用 add_vertex + add_face,但内部做批处理优化
**顶点数量**
`[[nodiscard]] size_t num_vertices() const { return vertices_.size(); }`
**返回**: vertices_ 大小
**面数量**
`[[nodiscard]] size_t num_faces() const { return faces_.size(); }`
**返回**: faces_ 大小
**边数量**
`[[nodiscard]] size_t num_edges() const { return halfedges_.size() / 2; }`
**返回**: halfedges_.size() / 2
**访问顶点**
`[[nodiscard]] const Point3D& vertex(size_t idx) const { return vertices_[idx]; }`
| 参数 | 说明 |
|------|------|
| `idx` | 顶点索引,0 ≤ idx < num_vertices() |
**返回**: 顶点坐标只读引用
**访问面**
`[[nodiscard]] const Face& face(size_t idx) const { return faces_[idx]; }`
| 参数 | 说明 |
|------|------|
| `idx` | 面索引 |
**返回**: Face 只读引用
**访问半边**
`[[nodiscard]] const Halfedge& halfedge(size_t idx) const { return halfedges_[idx]; }`
| 参数 | 说明 |
|------|------|
| `idx` | 半边索引 |
**返回**: Halfedge 只读引用
**更新顶点位置**
`void set_vertex(size_t idx, const Point3D& p) { vertices_[idx] = p; normals_dirty_ = true; }`
| 参数 | 说明 |
|------|------|
| `idx` | 顶点索引 |
| `p` | 新坐标 |
> 标记法向缓存为脏,下次查询时重新计算
**获取面的所有顶点索引(按环绕顺序)**
`[[nodiscard]] std::vector<int> face_vertices(int fi) const`
| 参数 | 说明 |
|------|------|
| `fi` | 面索引 |
**返回**: 顶点索引序列
**获取顶点的邻面索引环**
`[[nodiscard]] std::vector<int> vertex_faces(int vi) const`
| 参数 | 说明 |
|------|------|
| `vi` | 顶点索引 |
**返回**: 所有以 vi 为顶点的面索引
**是否为边界半边**
`[[nodiscard]] bool is_boundary_edge(int hei) const { return halfedges_[hei].face_index < 0; }`
| 参数 | 说明 |
|------|------|
| `hei` | 半边索引 |
**返回**: 没有所属面时为 true
**是否为边界顶点**
`[[nodiscard]] bool is_boundary_vertex(int vi) const`
| 参数 | 说明 |
|------|------|
| `vi` | 顶点索引 |
**返回**: 邻接任何边界半边时为 true
**面法向(几何法向,非归一化?由实现决定)**
`[[nodiscard]] Vector3D face_normal(int fi) const`
| 参数 | 说明 |
|------|------|
| `fi` | 面索引 |
**返回**: (v1-v0)×(v2-v0) 归一化结果
**顶点法向(邻面法向的面积加权平均)**
`[[nodiscard]] Vector3D vertex_normal(int vi) const`
| 参数 | 说明 |
|------|------|
| `vi` | 顶点索引 |
**返回**: 归一化顶点法向
**重新计算所有面法向和顶点法向**
`void update_normals()`
> 修改顶点位置后自动标记脏位,调用此方法触发重新计算
**网格包围盒**
`[[nodiscard]] AABB3D bounds() const`
**返回**: AABB3D 轴对齐包围盒
**面迭代器范围(支持 for-range)**
**顶点单邻环迭代器**
**获取所有面范围(range-based for 支持)**
`[[nodiscard]] FaceRange faces_range() const`
**返回**: FaceRange 对象
**获取顶点的 1-ring 邻域迭代器**
`[[nodiscard]] VertexOneRing vertex_one_ring(int vi) const`
| 参数 | 说明 |
|------|------|
| `vi` | 顶点索引 |
**返回**: VertexOneRing 对象
**查找或创建半边 (v0→v1)**
`int find_or_create_edge(int v0, int v1)`
| 参数 | 说明 |
|------|------|
| `v0` | 起点顶点索引 |
| `v1` | 终点顶点索引 |
**返回**: 半边索引
### `marching_cubes.h`
**Marching Cubes 输出网格**
`struct MCMesh {`
**Marching Cubes 等值面提取**
`MCMesh marching_cubes(const std::function<double(double,double,double)>& f,`
| 参数 | 说明 |
|------|------|
| `f` | 标量场函数 f(x,y,z) → double |
| `iso_level` | 等值面值(默认 0 |
| `bmin` | 包围盒最小角 |
| `bmax` | 包围盒最大角 |
| `resolution` | 每轴采样分辨率(≥ 1),总网格 = resolution³ 个立方体 |
**返回**: MCMesh 三角形网格
> 使用经典的 256 查表法(Lorensen & Cline 1987
**参见**: `sdf_sphere sdf_box`
**SDF 球体函数**
`inline double sdf_sphere(double x, double y, double z, double cx, double cy, double cz, double r) {`
| 参数 | 说明 |
|------|------|
| `x,y,z` | 采样点坐标 |
| `cx,cy,cz` | 球心坐标 |
| `r` | 半径 |
**返回**: 有符号距离:内部 < 0,表面 = 0,外部 > 0
**SDF 立方体函数(轴对齐,中心在原点)**
`inline double sdf_box(double x, double y, double z, double hx, double hy, double hz) {`
| 参数 | 说明 |
|------|------|
| `x,y,z` | 采样点坐标 |
| `hx,hy,hz` | 半边长 |
**返回**: 有符号距离
**SDF 平滑并集(Smooth Union**
| 参数 | 说明 |
|------|------|
| `d1,d2` | 两个 SDF 值 |
| `k` | 平滑宽度(> 0),值越大过渡越平滑 |
**返回**: 混合后的 SDF 值
**SDF 平滑差集(Smooth Subtraction**
`inline double sdf_smooth_subtraction(double d1, double d2, double k) {`
| 参数 | 说明 |
|------|------|
| `d1,d2` | 两个 SDF 值 |
| `k` | 平滑宽度(> 0 |
**返回**: 混合后的 SDF 值
### `mesh_boolean.h`
**布尔运算类型(CSG 组合)**
`enum class BooleanOp {`
**三角网格布尔运算**
`HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个三角网格(必须为封闭流形) |
| `b` | 第二个三角网格(必须为封闭流形) |
| `op` | 布尔运算类型 |
**返回**: 结果三角网格
> 要求输入网格为封闭流形(watertight),否则分类不可靠
### `mesh_curvature.h`
**离散曲率计算结果**
`struct CurvatureResult {`
**离散曲率计算(Cotan 公式,Meyer et al. 2003**
`CurvatureResult compute_curvature(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
**返回**: CurvatureResult 每顶点曲率
> 要求网格为流形;边界顶点曲率使用近似公式
### `mesh_parameterize.h`
**Tutte 参数化(调和参数化)**
`[[nodiscard]] std::vector<Point2D> tutte_parameterization(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格(需含边界) |
**返回**: 每顶点 UV 坐标(Point2D),顺序与 mesh 顶点一致
> 网格必须有边界(开网格);闭曲面需先切割为拓扑圆盘
**参见**: `lscm_parameterization`
**LSCMLeast Squares Conformal Maps)参数化**
`[[nodiscard]] std::vector<Point2D> lscm_parameterization(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
**返回**: 每顶点 UV 坐标(Point2D
> 简化实现,不包含完整 Lévy 论文中所有的退化处理
**参见**: `tutte_parameterization`
### `mesh_quality.h`
**三角网格质量指标**
`struct MeshQuality {`
**评估三角网格质量**
`MeshQuality evaluate_mesh_quality(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
**返回**: MeshQuality 质量指标汇总
**四面体网格质量指标**
`struct TetQuality {`
**评估三角网格作为四面体边界的质量**
`TetQuality evaluate_tet_quality(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 封闭三角网格(volume boundary |
**返回**: TetQuality 四面体质量指标
> 这不是真正的四面体网格质量评估——仅用于表面网格的代理指标
**单元类型枚举**
`enum class ElementType {`
**通用单元质量指标**
`struct ElemQuality {`
**按单元类型分派的网格质量评估**
`ElemQuality evaluate_element_quality(const HalfedgeMesh& mesh, ElementType type)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格 |
| `type` | 单元类型 |
**返回**: ElemQuality 质量指标
> 目前仅 Tri 和 Tet 完整实现;Quad / Hex 返回 stub(全零)
**详细质量报告**
`struct QualityReport {`
**生成三角网格的完整质量报告**
`QualityReport mesh_quality_report(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
**返回**: QualityReport 完整质量报告
**生成四面体网格的完整质量报告**
`QualityReport mesh_quality_report_tet(const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 封闭三角网格 |
**返回**: QualityReport 完整质量报告
**三角形归一化 Jacobian**
`double tri_scaled_jacobian(const Point3D& a, const Point3D& b, const Point3D& c)`
| 参数 | 说明 |
|------|------|
| `a,b,c` | 三角形三个顶点 |
**返回**: 归一化 Jacobian [-1, 1]
**四面体归一化 Jacobian**
`double tet_scaled_jacobian(const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `a,b,c,d` | 四面体四个顶点 |
**返回**: 归一化 Jacobian [0, 1]
### `mesh_repair.h`
**网格修复选项**
`struct RepairOptions {`
**自动网格修复**
`HalfedgeMesh repair_mesh(const HalfedgeMesh& mesh, const RepairOptions& opts = {})`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格(可能有缺陷) |
| `opts` | 修复选项(默认全部启用) |
**返回**: 修复后的网格
> 修复为启发式算法,不保证 100% 成功;孔洞过大或非流形边可能仍有残留问题
### `mesh_simplify.h`
**网格简化选项**
`struct SimplifyOptions {`
**QEMQuadric Error Metrics)网格简化**
`HalfedgeMesh simplify_mesh(const HalfedgeMesh& mesh, const SimplifyOptions& opts = {})`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
| `opts` | 简化选项 |
**返回**: 简化后的网格
> preserve_boundary 模式下,边界边通过惩罚项(大代价)被保护
### `mesh_smooth.h`
**网格光顺方法**
`enum class SmoothMethod {`
**网格光顺参数**
`struct SmoothOptions {`
**网格光顺(通用分发器)**
`HalfedgeMesh smooth_mesh(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入三角网格 |
| `opts` | 光顺选项 |
**返回**: 光顺后的网格(顶点位置更新,拓扑不变)
**标准拉普拉斯光顺**
`HalfedgeMesh smooth_laplacian(const HalfedgeMesh& mesh, int iterations, double lambda)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格 |
| `iterations` | 迭代次数 |
| `lambda` | 步长系数 (0, 1] |
**返回**: 光顺后的网格
> 迭代过多会导致网格坍塌;对于体积关键的应用优先选 Taubin 或 HC
**参见**: `smooth_taubin smooth_hc_laplacian`
**Taubin λ|μ 光顺(体积保持)**
`HalfedgeMesh smooth_taubin(const HalfedgeMesh& mesh, int iterations, double lambda, double mu)`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格 |
| `iterations` | 完整 λ/μ 循环次数 |
| `lambda` | 正步系数 (0, 1] |
| `mu` | 负步系数,需满足 mu < 0 且 |mu| > lambda |
**返回**: 光顺后的网格
> 典型值:λ = 0.5, μ = -0.53;|mu| 过大可能导致不稳定振荡
**HC 拉普拉斯光顺(Humphrey's Classes**
`HalfedgeMesh smooth_hc_laplacian(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格 |
| `opts` | 光顺选项(使用 hc_alpha 和 hc_beta 字段) |
**返回**: 光顺后的网格
**双边网格滤波**
`HalfedgeMesh smooth_bilateral(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})`
| 参数 | 说明 |
|------|------|
| `mesh` | 输入网格 |
| `opts` | 光顺选项(使用 bilateral_ 前缀字段) |
**返回**: 光顺后的网格
## 空间索引 (`vde::spatial`)
### `bvh.h`
**包围盒层次结构 (Bounding Volume Hierarchy)**
**BVH 构建分裂策略**
`enum class BVHSplitStrategy {`
**< 按最长轴中点分裂**
`Equal, /**< 按数量均等分裂 */`
**< 按数量均等分裂**
`SAH /**< Surface Area Heuristic — 最小化射线击中概率期望 */`
**< Surface Area Heuristic — 最小化射线击中概率期望**
`}`
**BVH 构建选项**
`struct BVHBuildOptions {`
**< 分裂策略**
`int leaf_size = 4; /**< 叶节点最大图元数 */`
**< 叶节点最大图元数**
`int max_depth = 64; /**< 树的最大深度 */`
**< 树的最大深度**
`}`
**包围盒层次结构 — 三角形网格加速结构**
**参见**: `SpatialIndex, Octree, KDTree, RTree`
**构造 BVH 并指定构建选项**
`explicit BVH(const BVHBuildOptions& opts = {}) : opts_(opts) {}`
| 参数 | 说明 |
|------|------|
| `opts` | 构建选项(分裂策略、叶节点大小、最大深度) |
**清除已有数据并重建 BVH**
`void build(const std::vector<Triangle3D>& tris) override`
| 参数 | 说明 |
|------|------|
| `tris` | 三角形数组 |
**插入单个三角形**
`void insert(const Triangle3D& tri) override`
| 参数 | 说明 |
|------|------|
| `tri` | 要插入的三角形 |
**删除三角形**
`bool remove(const Triangle3D& tri) override`
| 参数 | 说明 |
|------|------|
| `tri` | 要删除的三角形 |
**返回**: 删除成功返回 true
**AABB 范围查询**
`std::vector<Triangle3D> query_range(const AABB3D& range) const override`
| 参数 | 说明 |
|------|------|
| `range` | 查询包围盒 |
**返回**: 与 range 相交的三角形列表
**K 近邻查询**
`std::vector<Triangle3D> query_knn(const Point3D& point, size_t k) const override`
| 参数 | 说明 |
|------|------|
| `point` | 查询点 |
| `k` | 返回数量 |
**返回**: 最近的 k 个三角形
**射线查询:返回所有命中的三角形**
`std::vector<Triangle3D> query_ray(const Ray3Dd& ray) const override`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 按命中顺序排列的三角形列表
**清空 BVH 树和所有三角形**
`void clear() override`
**三角形数量**
`size_t size() const override { return primitives_.size(); }`
**返回**: 当前索引的三角形总数
**射线最近命中查询结果**
`struct HitResult {`
**< 沿射线的参数 t**
`Triangle3D tri; /**< 命中的三角形 */`
**< 命中的三角形**
`Point3D point; /**< 命中点的世界坐标 = origin + t * dir */`
**< 命中点的世界坐标 = origin + t * dir**
`}`
**射线最近命中查询**
`std::optional<HitResult> query_ray_nearest(const Ray3Dd& ray) const`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 最近命中结果(若无命中则返回空)
> 比 query_ray() 更高效,仅返回最近命中
**BVH 节点**
`struct Node {`
**< 节点的包围盒(所有子节点/图元的并集)**
`int left = -1; /**< 左子节点索引,叶节点为 -1 */`
**< 左子节点索引,叶节点为 -1**
`int right = -1; /**< 右子节点索引,叶节点为 -1 */`
**< 右子节点索引,叶节点为 -1**
`int first_prim = 0; /**< 叶节点第一个图元的索引 */`
**< 叶节点第一个图元的索引**
`int prim_count = 0; /**< 叶节点图元数量 */`
**< 叶节点图元数量**
`/** @brief 判断是否为叶节点 */`
**判断是否为叶节点**
`bool leaf() const { return left < 0; }`
**< 节点数组(根节点为 nodes_[0]**
`std::vector<Triangle3D> primitives_; /**< 图元数组 */`
**< 图元数组**
`BVHBuildOptions opts_; /**< 构建选项 */`
**< 构建选项**
`/**`
**递归构建 BVH 子树**
`void build_recursive(int node, int first, int count, int depth)`
| 参数 | 说明 |
|------|------|
| `node` | 当前节点索引 |
| `first` | 图元范围的起始索引 |
| `count` | 图元数量 |
| `depth` | 当前递归深度 |
**计算 SAH 分裂代价**
`double sah_cost(int n_left, int n_right, const AABB3D& left, const AABB3D& right) const`
| 参数 | 说明 |
|------|------|
| `n_left` | 左子树图元数 |
| `n_right` | 右子树图元数 |
| `left` | 左子树包围盒 |
| `right` | 右子树包围盒 |
**返回**: SAH 代价估值
### `kd_tree.h`
**k-d 树 (K-Dimensional Tree) 空间划分结构**
**k-d 树空间索引**
`template <typename T>`
> k-d 树在维度约 2~6 时效率最佳。三维场景中,
**参见**: `SpatialIndex, BVH, Octree`
**批量构建 k-d 树**
`void build(const std::vector<T>& items) override`
| 参数 | 说明 |
|------|------|
| `items` | 待索引的对象数组 |
**插入单个对象**
`void insert(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待插入的空间对象 |
**删除对象**
`bool remove(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待删除的空间对象 |
**返回**: 删除成功返回 true
**范围查询**
`std::vector<T> query_range(const AABB3D& range) const override`
| 参数 | 说明 |
|------|------|
| `range` | 查询包围盒 |
**返回**: 与 range 相交的对象列表
**K 近邻查询**
`std::vector<T> query_knn(const Point3D& point, size_t k) const override`
| 参数 | 说明 |
|------|------|
| `point` | 查询点 |
| `k` | 返回数量 |
**返回**: 最近的 k 个对象
**射线查询**
`std::vector<T> query_ray(const Ray3Dd& ray) const override`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 与射线相交的对象列表
**清空 k-d 树**
`void clear() override`
**对象数量**
`size_t size() const override { return items_.size(); }`
**返回**: 当前索引的对象总数
**k-d 树节点**
`struct Node {`
**< 节点包围盒**
`int item_idx = -1; /**< 叶节点对应的对象索引(-1 表示内部节点) */`
**< 叶节点对应的对象索引(-1 表示内部节点)**
`int split_axis = 0; /**< 分裂轴:0=x, 1=y, 2=z */`
**< 分裂轴:0=x, 1=y, 2=z**
`int left = -1; /**< 左子节点索引 */`
**< 左子节点索引**
`int right = -1; /**< 右子节点索引 */`
**< 右子节点索引**
`}`
**< 对象数组**
`std::vector<Node> nodes_; /**< 节点数组 */`
**< 节点数组**
`int root_ = -1; /**< 根节点索引 */`
**< 根节点索引**
`/**`
**获取对象代表位置(用于空间排序)**
`static Point3D get_position(const T& item)`
| 参数 | 说明 |
|------|------|
| `item` | 空间对象 |
**返回**: 对象的三维代表点
**获取对象的轴对齐包围盒**
`static AABB3D get_aabb(const T& item)`
| 参数 | 说明 |
|------|------|
| `item` | 空间对象 |
**返回**: 包围盒
**判断对象是否与射线相交**
`static bool ray_hits_item(const T& item, const Ray3Dd& ray)`
| 参数 | 说明 |
|------|------|
| `item` | 空间对象 |
| `ray` | 查询射线 |
**返回**: 相交返回 true
**递归构建 k-d 树**
`int build_recursive(int start, int end)`
| 参数 | 说明 |
|------|------|
| `start` | items_ 中当前范围起始索引 |
| `end` | items_ 中当前范围结束索引 |
**返回**: 新节点的索引
**递归范围查询**
`void query_range_recursive(int node_idx, const AABB3D& range,`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `range` | 查询包围盒 |
| `result` | 累积结果 |
**递归射线查询**
`void query_ray_recursive(int node_idx, const Ray3Dd& ray,`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `ray` | 查询射线 |
| `result` | 累积结果 |
### `octree.h`
**八叉树 (Octree) 空间划分结构**
**八叉树空间索引**
`template <typename T>`
> 适用于体积数据、粒子系统、空间哈希等场景。
**参见**: `SpatialIndex, BVH, KDTree`
**构造八叉树**
`explicit Octree(int max_depth = 8, int max_items = 16)`
| 参数 | 说明 |
|------|------|
| `max_depth` | 最大递归深度(默认 8,对应 256³ 分辨率) |
| `max_items` | 节点剖分前可容纳的最大对象数(默认 16) |
**批量构建八叉树**
`void build(const std::vector<T>& items) override`
| 参数 | 说明 |
|------|------|
| `items` | 待索引的对象数组 |
**增量插入对象**
`void insert(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待插入的空间对象 |
**删除对象**
`bool remove(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待删除的空间对象 |
**返回**: 删除成功返回 true;对象不存在返回 false
**范围查询**
`std::vector<T> query_range(const AABB3D& range) const override`
| 参数 | 说明 |
|------|------|
| `range` | 查询包围盒 |
**返回**: 与 range 相交的对象列表
**K 近邻查询**
`std::vector<T> query_knn(const Point3D& point, size_t k) const override`
| 参数 | 说明 |
|------|------|
| `point` | 查询点 |
| `k` | 返回数量 |
**返回**: 最近的 k 个对象
**射线查询**
`std::vector<T> query_ray(const Ray3Dd& ray) const override`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 按命中顺序排列的相交对象列表
**清空八叉树**
`void clear() override`
**当前索引中的对象数量**
`size_t size() const override`
**返回**: 对象总数
**递归插入对象到指定节点**
`void insert_recursive(int node_idx, const T& item, int depth)`
| 参数 | 说明 |
|------|------|
| `node_idx` | 目标节点索引 |
| `item` | 待插入的对象 |
| `depth` | 当前递归深度 |
**递归剖分节点**
`void subdivide_recursive(int node_idx, int depth)`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `depth` | 当前深度 |
**递归范围查询**
`void query_range_recursive(int node_idx, const AABB3D& range,`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `range` | 查询包围盒 |
| `result` | 累积结果 |
**递归射线查询**
`void query_ray_recursive(int node_idx, const Ray3Dd& ray,`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `ray` | 查询射线 |
| `result` | 累积结果 |
**获取对象空间位置(用于剖分分配)**
`static Point3D get_position(const T& item)`
| 参数 | 说明 |
|------|------|
| `item` | 空间对象 |
**返回**: 对象的代表点
**< 八叉树内部数据**
`int max_depth_; /**< 最大递归深度 */`
**< 最大递归深度**
`int max_items_; /**< 节点剖分阈值 */`
**< 节点剖分阈值**
`}`
### `r_tree.h`
**R 树 (R-Tree) 动态空间索引**
**R 树节点**
`template <typename T>`
**< 节点包围盒(子节点/对象 MBR 的并集)**
`bool is_leaf = true; /**< 是否为叶节点 */`
**< 是否为叶节点**
`std::vector<size_t> children; /**< 内部节点:子节点索引列表 */`
**< 内部节点:子节点索引列表**
`std::vector<size_t> item_indices; /**< 叶节点:对象索引列表 */`
**< 叶节点:对象索引列表**
`size_t parent = static_cast<size_t>(-1); /**< 父节点索引 */`
**< 父节点索引**
`}`
**R 树动态空间索引**
`template <typename T>`
> R 树在动态场景(如编辑中的几何体)中比 BVH 更合适。
**参见**: `SpatialIndex, BVH, RStarTree`
**批量构建 R 树**
`void build(const std::vector<T>& items) override`
| 参数 | 说明 |
|------|------|
| `items` | 待索引的对象数组 |
**增量插入对象**
`void insert(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待插入的空间对象 |
**删除对象**
`bool remove(const T& item) override`
| 参数 | 说明 |
|------|------|
| `item` | 待删除的空间对象 |
**返回**: 删除成功返回 true
**范围查询**
`std::vector<T> query_range(const AABB3D& range) const override`
| 参数 | 说明 |
|------|------|
| `range` | 查询包围盒 |
**返回**: 与 range 相交的对象列表
**K 近邻查询**
`std::vector<T> query_knn(const Point3D& point, size_t k) const override`
| 参数 | 说明 |
|------|------|
| `point` | 查询点 |
| `k` | 返回数量 |
**返回**: 最近的 k 个对象
**射线查询**
`std::vector<T> query_ray(const Ray3Dd& ray) const override`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 与射线相交的对象列表
**清空 R 树**
`void clear() override`
**对象数量**
`size_t size() const override { return count_; }`
**返回**: 当前索引的对象总数
**R 树节点总数**
`size_t node_count() const { return nodes_.size(); }`
**返回**: 内部节点 + 叶节点数量
**递归范围查询**
`void query_range_recursive(size_t node_idx, const AABB3D& range,`
| 参数 | 说明 |
|------|------|
| `node_idx` | 当前节点索引 |
| `range` | 查询包围盒 |
| `result` | 累积结果 |
**< 对象数组**
`std::vector<AABB3D> item_bounds_; /**< 对象包围盒数组 */`
**< 对象包围盒数组**
`std::vector<RTreeNode<T>> nodes_; /**< R 树节点数组 */`
**< R 树节点数组**
`size_t root_idx_ = 0; /**< 根节点索引 */`
**< 根节点索引**
`size_t count_ = 0; /**< 对象计数 */`
**< 对象计数**
`}`
### `spatial_index.h`
**空间索引抽象基类**
**空间索引抽象基类**
`template <typename T>`
> 本类为纯虚接口,不可直接实例化
**批量构建索引**
`virtual void build(const std::vector<T>& items) = 0`
| 参数 | 说明 |
|------|------|
| `items` | 待索引的对象数组 |
**插入单个对象**
`virtual void insert(const T& item) = 0`
| 参数 | 说明 |
|------|------|
| `item` | 待插入的空间对象 |
**删除单个对象**
`virtual bool remove(const T& item) = 0`
| 参数 | 说明 |
|------|------|
| `item` | 待删除的空间对象 |
**返回**: true 删除成功;false 对象不存在
**范围查询:返回与 AABB 相交的所有对象**
`virtual std::vector<T> query_range(const AABB3D& range) const = 0`
| 参数 | 说明 |
|------|------|
| `range` | 查询的轴对齐包围盒 |
**返回**: 与 range 相交的对象列表
**K 近邻查询:返回距 point 最近的 k 个对象**
`virtual std::vector<T> query_knn(const Point3D& point, size_t k) const = 0`
| 参数 | 说明 |
|------|------|
| `point` | 查询点 |
| `k` | 需要返回的对象数量 |
**返回**: 按距离升序排列的 k 个最近对象
**射线查询:返回与射线相交的所有对象**
`virtual std::vector<T> query_ray(const Ray3Dd& ray) const = 0`
| 参数 | 说明 |
|------|------|
| `ray` | 查询射线 |
**返回**: 按命中距离升序排列的相交对象列表
**清空索引中所有数据**
`virtual void clear() = 0`
**当前索引中的对象数量**
`virtual size_t size() const = 0`
**返回**: 对象计数
## 布尔运算 (`vde::boolean`)
### `boolean_2d.h`
**二维多边形布尔运算**
**布尔运算类型**
`enum class BooleanOp {`
**< 并集 A B**
`Intersection, /**< 交集 A ∩ B */`
**< 交集 A ∩ B**
`Difference, /**< 差集 A B */`
**< 差集 A B**
`SymDiff /**< 对称差 (A B) (B A) */`
**< 对称差 (A B) (B A)**
`}`
**二维多边形布尔运算**
`std::vector<Polygon2D> boolean_2d(const Polygon2D& a, const Polygon2D& b, BooleanOp op)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个多边形 |
| `b` | 第二个多边形 |
| `op` | 布尔操作类型 |
**返回**: 结果多边形列表(可能有多个分离的组件)
> 当前版本优化了凸多边形路径。对于带孔洞或自交的
**参见**: `BooleanOp, mesh_boolean, polygon_offset`
### `boolean_mesh.h`
**三维网格布尔运算**
**网格并集 A B**
`HalfedgeMesh mesh_union(const HalfedgeMesh& a, const HalfedgeMesh& b)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
**返回**: A B 的合并网格
**参见**: `mesh_intersection, mesh_difference, is_point_inside_mesh`
**网格交集 A ∩ B**
`HalfedgeMesh mesh_intersection(const HalfedgeMesh& a, const HalfedgeMesh& b)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
**返回**: A ∩ B 的交集网格
> 结果体积为两网格公共区域
**参见**: `mesh_union, mesh_difference`
**网格差集 A B**
`HalfedgeMesh mesh_difference(const HalfedgeMesh& a, const HalfedgeMesh& b)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
**返回**: A B 的差集网格
> 结果中来自 B 的面片会被翻转法线以保持内-外一致性
**参见**: `mesh_union, mesh_intersection, mesh_sym_diff`
**网格对称差 (A B) (B A)**
`HalfedgeMesh mesh_sym_diff(const HalfedgeMesh& a, const HalfedgeMesh& b)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
**返回**: 对称差网格
**参见**: `mesh_difference, mesh_union`
**用网格 B 裁剪网格 A**
`HalfedgeMesh clip_mesh(const HalfedgeMesh& a, const HalfedgeMesh& b,`
| 参数 | 说明 |
|------|------|
| `a` | 待裁剪网格 |
| `b` | 裁剪体网格 |
| `invert_b` | 若为 true,将 B 的内外判定取反(裁剪外部) |
**返回**: 裁剪后的网格(仅包含 A 的面片)
**参见**: `mesh_difference, is_point_inside_mesh`
**翻转网格所有面片的法线方向**
`HalfedgeMesh invert_mesh(const HalfedgeMesh& m)`
| 参数 | 说明 |
|------|------|
| `m` | 原始网格 |
**返回**: 法线翻转后的网格
**参见**: `mesh_difference`
**合并两个网格**
`HalfedgeMesh merge_meshes(const HalfedgeMesh& a, const HalfedgeMesh& b)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
**返回**: 包含 A 和 B 全部顶点和面片的合并网格
> 不处理重叠区域;仅做纯几何拼接
**参见**: `mesh_union(做布尔合并)`
**网格布尔运算统一接口**
`HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op)`
| 参数 | 说明 |
|------|------|
| `a` | 网格 A |
| `b` | 网格 B |
| `op` | 布尔操作类型 |
**返回**: 结果网格
**参见**: `BooleanOp, mesh_union, mesh_intersection, mesh_difference, mesh_sym_diff`
**判断三维点是否在封闭网格内部**
`bool is_point_inside_mesh(const core::Point3D& p, const HalfedgeMesh& mesh)`
| 参数 | 说明 |
|------|------|
| `p` | 待判定点 |
| `mesh` | 封闭网格 |
**返回**: 点在网格内部返回 true
> 网格必须是封闭(水密)的,否则结果不可靠。
**参见**: `clip_mesh, mesh_difference`
### `polygon_offset.h`
**多边形等距偏移 (Polygon Offset / Inset)**
**多边形等距偏移**
`std::vector<Polygon2D> polygon_offset(const Polygon2D& poly, double distance)`
| 参数 | 说明 |
|------|------|
| `poly` | 原始多边形 |
| `distance` | 偏移距离(正=外扩,负=内缩) |
**返回**: 偏移后的多边形列表(内缩或自交可能产生多个碎片)
> 使用直骨架近似而非精确圆弧偏移,转角处为斜角连接。
**参见**: `boolean_2d`
## 碰撞检测 (`vde::collision`)
### `gjk.h`
**GJK (GilbertJohnsonKeerthi) 碰撞检测算法**
**支撑函数类型**
`using SupportFunc = std::function<Point3D(const Vector3D&)>`
**GJK 完整检测结果**
`struct GJKResult {`
**< 两凸体是否相交**
`double distance; /**< 最近距离(不相交时 >0,相交时为 0) */`
**< 最近距离(不相交时 >0,相交时为 0)**
`Point3D point_a; /**< 形状 A 上的最近点 */`
**< 形状 A 上的最近点**
`Point3D point_b; /**< 形状 B 上的最近点 */`
**< 形状 B 上的最近点**
`}`
**GJK 相交检测(仅判断是否碰撞)**
`bool gjk_intersect(const SupportFunc& shape_a, const SupportFunc& shape_b)`
| 参数 | 说明 |
|------|------|
| `shape_a` | 形状 A 的支撑函数 |
| `shape_b` | 形状 B 的支撑函数 |
**返回**: 相交返回 true
**参见**: `gjk_distance, gjk_full, SupportFunc`
**GJK 最近距离查询**
`double gjk_distance(const SupportFunc& shape_a, const SupportFunc& shape_b)`
| 参数 | 说明 |
|------|------|
| `shape_a` | 形状 A 的支撑函数 |
| `shape_b` | 形状 B 的支撑函数 |
**返回**: 最近距离(相交时返回 0),始终 ≥ 0
**参见**: `gjk_intersect, gjk_full`
**GJK 完整检测:碰撞状态、距离、最近点对**
`GJKResult gjk_full(const SupportFunc& shape_a, const SupportFunc& shape_b)`
| 参数 | 说明 |
|------|------|
| `shape_a` | 形状 A 的支撑函数 |
| `shape_b` | 形状 B 的支撑函数 |
**返回**: GJKResult 包含碰撞状态、距离、最近点对
> 对于连续碰撞检测 (CCD) 或需要分离向量的场景,
**参见**: `gjk_intersect, gjk_distance`
### `ray_intersect.h`
**射线求交工具集**
**射线-三角形求交结果**
`struct RayTriResult {`
**< 沿射线的参数:hit_point = origin + t * dir**
`double u, v; /**< 三角形重心坐标:hit_point = (1uv)*v0 + u*v1 + v*v2 */`
**< 三角形重心坐标:hit_point = (1uv)*v0 + u*v1 + v*v2**
`Point3D point; /**< 命中点的世界坐标 */`
**< 命中点的世界坐标**
`}`
**射线-三角形求交(Möller-Trumbore 算法)**
`std::optional<RayTriResult> ray_triangle_intersect(`
| 参数 | 说明 |
|------|------|
| `origin` | 射线起点 |
| `dir` | 射线方向(需归一化以获得正确 t 值) |
| `tri` | 三角形 |
**返回**: 命中返回 RayTriResult;未命中返回空
**参见**: `ray_mesh_intersect`
**射线-三角形求交(Ray3Dd 重载)**
`inline std::optional<RayTriResult> ray_triangle_intersect(`
| 参数 | 说明 |
|------|------|
| `ray` | 射线 |
| `tri` | 三角形 |
**返回**: 命中返回 RayTriResult;未命中返回空
**参见**: `ray_triangle_intersect(origin, dir, tri)`
**射线-AABB 求交(slab 方法)**
`bool ray_aabb_intersect(const Ray3Dd& ray, const AABB3D& box,`
| 参数 | 说明 |
|------|------|
| `ray` | 射线 |
| `box` | 轴对齐包围盒 |
| `tmin_out` | [输出] 进入包围盒的参数 t |
| `tmax_out` | [输出] 离开包围盒的参数 t |
**返回**: 命中返回 true
> 常用于 BVH 遍历节点的快速 rejection test
**参见**: `ray_triangle_intersect`
**射线-球体求交结果**
`struct RaySphereResult {`
**< 命中参数(通常取较小的 t)**
`Point3D point; /**< 命中点世界坐标 */`
**< 命中点世界坐标**
`}`
**射线-球体求交(解析法)**
`std::optional<RaySphereResult> ray_sphere_intersect(`
| 参数 | 说明 |
|------|------|
| `origin` | 射线起点 |
| `dir` | 射线方向 |
| `center` | 球心 |
| `radius` | 球半径 |
**返回**: 命中返回 RaySphereResult(最近交点);未命中返回空
**参见**: `ray_sphere_intersect(ray, center, radius)`
**射线-球体求交(Ray3Dd 重载)**
`inline std::optional<RaySphereResult> ray_sphere_intersect(`
| 参数 | 说明 |
|------|------|
| `ray` | 射线 |
| `center` | 球心 |
| `radius` | 球半径 |
**返回**: 命中返回 RaySphereResult;未命中返回空
**射线-平面求交**
`std::optional<double> ray_plane_intersect(`
| 参数 | 说明 |
|------|------|
| `origin` | 射线起点 |
| `dir` | 射线方向 |
| `plane_point` | 平面上一点 |
| `plane_normal` | 平面法线(需归一化以获得正确 t) |
**返回**: 命中返回参数 t;未命中(平行或反向)返回空
**射线-平面求交(Ray3Dd 重载)**
`inline std::optional<double> ray_plane_intersect(`
| 参数 | 说明 |
|------|------|
| `ray` | 射线 |
| `plane_point` | 平面上一点 |
| `plane_normal` | 平面法线 |
**返回**: 命中返回参数 t;未命中返回空
**射线-网格求交(暴力遍历)**
`std::optional<RayTriResult> ray_mesh_intersect(`
| 参数 | 说明 |
|------|------|
| `origin` | 射线起点 |
| `dir` | 射线方向 |
| `triangles` | 三角形列表 |
**返回**: 最近命中结果;无命中返回空
> 对于大型网格建议配合 BVH 使用:
**参见**: `ray_tri_intersect.h, query_ray_nearest (BVH)`
**射线-网格求交(Ray3Dd 重载)**
`inline std::optional<RayTriResult> ray_mesh_intersect(`
| 参数 | 说明 |
|------|------|
| `ray` | 射线 |
| `triangles` | 三角形列表 |
**返回**: 最近命中结果;无命中返回空
### `sat.h`
**SAT (Separating Axis Theorem) 碰撞检测**
**SAT 凸多面体相交检测**
`bool sat_intersect(const std::vector<Point3D>& verts_a,`
| 参数 | 说明 |
|------|------|
| `verts_a` | 多面体 A 的顶点数组 |
| `faces_a` | 多面体 A 的面索引数组(每个面为 {v0, v1, v2} |
| `verts_b` | 多面体 B 的顶点数组 |
| `faces_b` | 多面体 B 的面索引数组 |
**返回**: 相交返回 true
> 适用于任意凸多面体。对于胶囊/球等光滑形状,GJK 更合适。
**参见**: `gjk_intersect, tri_tri_intersect`
### `tri_intersect.h`
**三角形-三角形 / 三角形-AABB 相交检测**
**三角形-三角形相交检测(布尔测试)**
`bool tri_tri_intersect(const Triangle3D& t1, const Triangle3D& t2)`
| 参数 | 说明 |
|------|------|
| `t1` | 三角形 1 |
| `t2` | 三角形 2 |
**返回**: 相交返回 true
**参见**: `tri_tri_intersect_detailed, sat_intersect`
**三角形-三角形相交线段**
`struct TriTriIntersection {`
**< 是否相交**
`Point3D p0; /**< 交点段起点 */`
**< 交点段起点**
`Point3D p1; /**< 交点段终点 */`
**< 交点段终点**
`}`
**三角形-三角形详细相交检测**
`TriTriIntersection tri_tri_intersect_detailed(const Triangle3D& t1,`
| 参数 | 说明 |
|------|------|
| `t1` | 三角形 1 |
| `t2` | 三角形 2 |
**返回**: TriTriIntersection:相交标志 + 交点段端点
> 共面情况交集段可能退化为单点(p0 == p1)
**参见**: `tri_tri_intersect`
**三角形-AABB 快速相交测试**
`bool tri_aabb_overlap(const Triangle3D& tri, const AABB3D& box)`
| 参数 | 说明 |
|------|------|
| `tri` | 三角形 |
| `box` | 轴对齐包围盒 |
**返回**: 相交返回 true
> AABB 碰撞比三角剖分后的三角-三角检测更高效,
**参见**: `tri_tri_intersect, ray_aabb_intersect`
## B-Rep建模 (`vde::brep`)
### `assembly.h`
**装配体节点**
`struct AssemblyNode {`
**装配体**
`struct Assembly {`
### `brep.h`
**边界表示(B-Rep)核心数据结构**
**边曲线类型枚举**
`enum class CurveType { Line, Circle, Bezier, BSpline, Nurbs }`
**拓扑顶点**
`struct TopoVertex {`
**拓扑边**
`struct TopoEdge {`
**拓扑环(Loop**
`struct TopoLoop {`
**拓扑面**
`struct TopoFace {`
**拓扑壳**
`struct TopoShell {`
**拓扑体**
`struct TopoBody {`
**B-Rep 模型**
**参见**: `brep_validate.h 验证`, `modeling.h 高层建模 API`, `brep_boolean.h 布尔运算`
**添加顶点**
`int add_vertex(const Point3D& p)`
| 参数 | 说明 |
|------|------|
| `p` | 顶点坐标 |
**返回**: 新顶点的 ID
**添加直线边**
`int add_edge(int v0, int v1)`
| 参数 | 说明 |
|------|------|
| `v0` | 起点顶点 ID |
| `v1` | 终点顶点 ID |
**返回**: 新边的 ID
**添加曲线边**
`int add_edge(int v0, int v1, const curves::NurbsCurve& curve)`
| 参数 | 说明 |
|------|------|
| `v0` | 起点顶点 ID |
| `v1` | 终点顶点 ID |
| `curve` | 边的几何曲线 |
**返回**: 新边的 ID
**添加环**
`int add_loop(const std::vector<int>& edges, bool outer = true)`
| 参数 | 说明 |
|------|------|
| `edges` | 环中边的 ID 序列(顺序连接) |
| `outer` | true = 外环, false = 内环 |
**返回**: 新环的 ID
**添加面**
`int add_face(int surface_id, const std::vector<int>& loops)`
| 参数 | 说明 |
|------|------|
| `surface_id` | 关联曲面 ID |
| `loops` | 环 ID 列表 |
**返回**: 新面的 ID
**添加壳**
`int add_shell(const std::vector<int>& faces, bool closed = true)`
| 参数 | 说明 |
|------|------|
| `faces` | 面 ID 列表 |
| `closed` | 是否为封闭壳 |
**返回**: 新壳的 ID
**添加体**
`int add_body(const std::vector<int>& shells, const std::string& name = "")`
| 参数 | 说明 |
|------|------|
| `shells` | 壳 ID 列表 |
| `name` | 体名称 |
**返回**: 新体的 ID
**添加 NURBS 曲面**
`int add_surface(const curves::NurbsSurface& surf)`
| 参数 | 说明 |
|------|------|
| `surf` | NURBS 曲面定义 |
**返回**: 新曲面的 ID
**顶点数量**
`[[nodiscard]] size_t num_vertices() const { return vertices_.size(); }`
**边数量**
`[[nodiscard]] size_t num_edges() const { return edges_.size(); }`
**面数量**
`[[nodiscard]] size_t num_faces() const { return faces_.size(); }`
**体数量**
`[[nodiscard]] size_t num_bodies() const { return bodies_.size(); }`
**曲面数量**
`[[nodiscard]] size_t num_surfaces() const { return surfaces_.size(); }`
**按数组索引访问顶点**
`[[nodiscard]] const TopoVertex& vertex(int id) const { return vertices_[id]; }`
**按唯一 ID 访问顶点(适用于边数据中的 ID 引用)**
`[[nodiscard]] const TopoVertex& vertex_by_id(int id) const`
**按数组索引访问边**
`[[nodiscard]] const TopoEdge& edge(int id) const { return edges_[id]; }`
**按数组索引访问面**
`[[nodiscard]] const TopoFace& face(int id) const { return faces_[id]; }`
**按数组索引访问曲面**
`[[nodiscard]] const curves::NurbsSurface& surface(int id) const { return surfaces_[id]; }`
**按唯一 ID 访问环**
`[[nodiscard]] const TopoLoop& loop_by_id(int id) const`
**获取所有环的只读引用**
`[[nodiscard]] const std::vector<TopoLoop>& all_loops() const { return loops_; }`
**计算模型的轴对齐包围盒**
`[[nodiscard]] core::AABB3D bounds() const`
**返回**: 包围盒(AABB
**检查模型有效性(快速版本)**
`[[nodiscard]] bool is_valid() const`
**返回**: true 如果模型通过基本检查
**参见**: `validate() 完整验证(水密性、方向一致性等)`
**将 B-Rep 模型 tessellate 为三角网格**
`[[nodiscard]] mesh::HalfedgeMesh to_mesh(double deflection = 0.01) const`
| 参数 | 说明 |
|------|------|
| `deflection` | 弦高误差(控制 tessellation 精度,默认 0.01 |
**返回**: HalfedgeMesh 三角网格
> deflection 越小网格越精细,但三角形数量显著增加。
**获取面的所有边**
`[[nodiscard]] std::vector<int> face_edges(int face_id) const`
| 参数 | 说明 |
|------|------|
| `face_id` | 面 ID |
**返回**: 边 ID 列表(去重)
**获取边的所有相邻面**
`[[nodiscard]] std::vector<int> edge_faces(int edge_id) const`
| 参数 | 说明 |
|------|------|
| `edge_id` | 边 ID |
**返回**: 相邻面 ID 列表
**获取顶点的所有相邻边**
`[[nodiscard]] std::vector<int> vertex_edges(int vertex_id) const`
| 参数 | 说明 |
|------|------|
| `vertex_id` | 顶点 ID |
**返回**: 相邻边 ID 列表
### `brep_boolean.h`
**B-Rep 级别的布尔运算**
**B-Rep 布尔并集: A B**
`[[nodiscard]] BrepModel brep_union(const BrepModel& a, const BrepModel& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个 B-Rep 实体 |
| `b` | 第二个 B-Rep 实体 |
**返回**: 新的 B-Rep 实体(a b
**参见**: `brep_intersection 交集`, `brep_difference 差集`
**B-Rep 布尔交集: A ∩ B**
`[[nodiscard]] BrepModel brep_intersection(const BrepModel& a, const BrepModel& b)`
| 参数 | 说明 |
|------|------|
| `a` | 第一个 B-Rep 实体 |
| `b` | 第二个 B-Rep 实体 |
**返回**: 新的 B-Rep 实体(a ∩ b
**参见**: `brep_union 并集`, `brep_difference 差集`
**B-Rep 布尔差集: A \ B**
`[[nodiscard]] BrepModel brep_difference(const BrepModel& a, const BrepModel& b)`
| 参数 | 说明 |
|------|------|
| `a` | 被减实体 A |
| `b` | 减去实体 B |
**返回**: 新的 B-Rep 实体(a \ b
**参见**: `brep_union 并集`, `brep_intersection 交集`
### `brep_validate.h`
**B-Rep 模型综合验证**
**B-Rep 模型的综合验证结果**
`struct ValidationResult {`
**是否通过所有必要检查**
`bool valid = true`
**错误信息列表(导致 valid = false**
`std::vector<std::string> errors`
**警告信息列表(不影响 valid**
`std::vector<std::string> warnings`
**水密性比率:恰好有 2 个相邻面的边的比例(1.0 = 完美水密)**
`double watertightness = 1.0`
**无自交比率:不与其他面内部相交的面对比例(1.0 = 无自交)**
`double self_intersection_free = 1.0`
**最短边的长度(用于检测退化边)**
`double min_edge_length = std::numeric_limits<double>::max()`
**最长边的长度(用于检测超长边)**
`double max_edge_length = 0.0`
**非流形边数(相邻面 ≠ 2 的边)**
`size_t non_manifold_edges = 0`
**悬挂边数(无相邻面的边)**
`size_t dangling_edges = 0`
**方向不一致的面数**
`size_t inconsistent_orientations = 0`
**总边数**
`size_t total_edges = 0`
**总面数**
`size_t total_faces = 0`
**对 BrepModel 执行综合验证**
`[[nodiscard]] ValidationResult validate(const BrepModel& body)`
| 参数 | 说明 |
|------|------|
| `body` | 待验证的 B-Rep 模型 |
**返回**: ValidationResult 包含所有检查结果的详细报告
> 自交检测是最昂贵的检查项(O(n²) 面对数),
**参见**: `BrepModel::is_valid() 快速有效性检查(无详细报告)`
### `iges_export.h`
**IGES 文件导出(版本 5.3**
**将 B-Rep 体导出为 IGES 格式字符串(版本 5.3)**
`[[nodiscard]] std::string export_iges(const std::vector<BrepModel>& bodies)`
| 参数 | 说明 |
|------|------|
| `bodies` | B-Rep 体列表 |
**返回**: IGES 5.3 格式字符串
**参见**: `export_iges_file 直接写入文件`, `export_step STEP 格式导出`
**将 B-Rep 体导出为 IGES 文件**
`void export_iges_file(const std::string& filepath, const std::vector<BrepModel>& bodies)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径(建议扩展名 .igs 或 .iges |
| `bodies` | B-Rep 体列表 |
**参见**: `export_iges 获取字符串输出`
### `iges_import.h`
**IGES 文件导入(ANSI Y14.26M**
**IGES 导入错误码**
`enum class IgesError {`
**从文件导入 IGES**
`[[nodiscard]] std::vector<BrepModel> import_iges(const std::string& filepath)`
| 参数 | 说明 |
|------|------|
| `filepath` | .igs 或 .iges 文件路径 |
**返回**: B-Rep 体列表
> IGES 格式较为宽松,不同 CAD 系统的实现差异很大。
**参见**: `import_iges_from_string 从字符串导入`, `iges_last_error 获取错误码`
**从字符串导入 IGES(用于测试)**
`[[nodiscard]] std::vector<BrepModel> import_iges_from_string(const std::string& data)`
| 参数 | 说明 |
|------|------|
| `data` | IGES 文件完整内容(字符串形式) |
**返回**: B-Rep 体列表
**参见**: `import_iges 从文件导入`
**获取最近一次 IGES 导入的错误码**
`[[nodiscard]] IgesError iges_last_error()`
**返回**: IgesError 枚举值
**参见**: `iges_last_error_message 获取可读描述`
**获取最近一次 IGES 导入的可读错误描述**
`[[nodiscard]] const std::string& iges_last_error_message()`
**返回**: 错误描述字符串
**参见**: `iges_last_error 获取枚举错误码`
### `modeling.h`
**高层 B-Rep 建模 API**
**沿方向挤出平面轮廓**
`[[nodiscard]] BrepModel extrude(const curves::NurbsCurve& profile, const Vector3D& dir)`
| 参数 | 说明 |
|------|------|
| `profile` | 轮廓曲线(必须位于一个平面内) |
| `dir` | 挤出方向向量(其长度决定挤出距离) |
**返回**: 挤出后的 B-Rep 实体
**参见**: `revolve 旋转扫掠`, `sweep 沿任意路径扫掠`
**绕轴旋转平面轮廓**
`[[nodiscard]] BrepModel revolve(const curves::NurbsCurve& profile,`
| 参数 | 说明 |
|------|------|
| `profile` | 轮廓曲线(通常位于轴的半平面中) |
| `axis_origin` | 旋转轴上的一个点 |
| `axis_dir` | 旋转轴方向(单位向量) |
| `angle_rad` | 旋转角度(弧度,默认 2π = 完整的旋转体) |
**返回**: 旋转后的 B-Rep 实体
**参见**: `extrude 线性挤出`, `make_sphere 直接创建球体`
**沿任意路径扫掠轮廓**
`[[nodiscard]] BrepModel sweep(const curves::NurbsCurve& profile,`
| 参数 | 说明 |
|------|------|
| `profile` | 截面轮廓(需位于路径起点的垂直平面内) |
| `path` | 扫掠路径曲线 |
**返回**: 扫掠后的 B-Rep 实体
> 路径曲率过大处可能出现自交,需要控制路径的光滑性。
**参见**: `extrude 直线挤出`, `revolve 旋转扫掠`
**在两个或多个轮廓曲线之间放样**
`[[nodiscard]] BrepModel loft(const std::vector<curves::NurbsCurve>& profiles)`
| 参数 | 说明 |
|------|------|
| `profiles` | 轮廓曲线列表(至少 2 条) |
**返回**: 放样后的 B-Rep 实体
**参见**: `extrude 单轮廓挤出`
**创建立方体**
`[[nodiscard]] BrepModel make_box(double w, double h, double d)`
| 参数 | 说明 |
|------|------|
| `w` | 宽度(X 方向),必须 > 0 |
| `h` | 高度(Y 方向),必须 > 0 |
| `d` | 深度(Z 方向),必须 > 0 |
**返回**: 实心立方体 B-Rep
**参见**: `make_cylinder 圆柱体`, `make_sphere 球体`
**创建圆柱体**
`[[nodiscard]] BrepModel make_cylinder(double radius, double height, int segments = 32)`
| 参数 | 说明 |
|------|------|
| `radius` | 截面半径,必须 > 0 |
| `height` | 总高度,沿 Y 轴从 -h/2 到 +h/2 |
| `segments` | 截面分段数(边数,默认 32) |
**返回**: 实心圆柱体 B-Rep
> segments 越大圆柱越光滑,但面和边数增加。
**参见**: `make_box 立方体`, `make_sphere 球体`
**创建球体**
`[[nodiscard]] BrepModel make_sphere(double radius, int segments_u = 32, int segments_v = 16)`
| 参数 | 说明 |
|------|------|
| `radius` | 球半径,必须 > 0 |
| `segments_u` | 经度方向分段数(默认 32) |
| `segments_v` | 纬度方向分段数(默认 16) |
**返回**: 实心球体 B-Rep
**参见**: `make_cylinder 圆柱体`
**对边做圆角处理**
`[[nodiscard]] BrepModel fillet(const BrepModel& body, int edge_id, double radius)`
| 参数 | 说明 |
|------|------|
| `body` | 输入实体 |
| `edge_id` | 要倒圆的边 ID |
| `radius` | 圆角半径,必须 > 0 |
**返回**: 圆角后的新实体
> 圆角半径不能超过相邻面的最小宽度,否则会产生自交。
> 只支持恒定半径圆角。变半径圆角尚未实现。
**参见**: `chamfer 倒角`, `shell 抽壳`
**对边做倒角**
`[[nodiscard]] BrepModel chamfer(const BrepModel& body, int edge_id, double distance)`
| 参数 | 说明 |
|------|------|
| `body` | 输入实体 |
| `edge_id` | 要倒角的边 ID |
| `distance` | 倒角距离(从原边沿两个面各偏移的距离) |
**返回**: 倒角后的新实体
**参见**: `fillet 圆角`
**抽壳(挖空实体)**
`[[nodiscard]] BrepModel shell(const BrepModel& body, int face_id, double thickness)`
| 参数 | 说明 |
|------|------|
| `body` | 输入实心实体 |
| `face_id` | 要移除的面 ID(形成开口),-1 表示封闭壳(不开口) |
| `thickness` | 壁厚(正值 = 向外偏移,负值 = 向内偏移) |
**返回**: 抽壳后的新实体
> 壁厚不应超过实体最小尺寸的一半。
> 当 face_id = -1 时,结果是一个封闭的壳(中空但没有开口)。
**参见**: `fillet 圆角`
### `step_export.h`
**STEP 文件导出(ISO 10303-214**
**将 B-Rep 体导出为 STEP AP214 字符串**
`[[nodiscard]] std::string export_step(const std::vector<BrepModel>& bodies)`
| 参数 | 说明 |
|------|------|
| `bodies` | B-Rep 体列表(每个体对应一个 PRODUCT) |
**返回**: STEP AP214 格式字符串
> 输出包含所有必要的 ISO 10303-21 头部信息。
**参见**: `export_step_file 直接写入文件`, `export_iges IGES 格式导出`
**将 B-Rep 体导出为 STEP 文件**
`void export_step_file(const std::string& filepath, const std::vector<BrepModel>& bodies)`
| 参数 | 说明 |
|------|------|
| `filepath` | 输出文件路径(建议扩展名 .step 或 .stp |
| `bodies` | B-Rep 体列表 |
**参见**: `export_step 获取字符串输出`
### `step_import.h`
**STEP 文件导入(ISO 10303**
**STEP 导入错误码**
`enum class StepError {`
**从文件导入 STEPAP203/AP214**
`[[nodiscard]] std::vector<BrepModel> import_step(const std::string& filepath)`
| 参数 | 说明 |
|------|------|
| `filepath` | .step 或 .stp 文件路径 |
**返回**: B-Rep 体列表(每个文件中的 PRODUCT 一个)
> 大型 STEP 文件(> 100 MB)可能需要数秒到数十秒进行解析。
**参见**: `import_step_from_string 从内存字符串导入(测试用)`, `step_last_error 获取错误码`
**从字符串导入 STEP(用于测试和嵌入式场景)**
`[[nodiscard]] std::vector<BrepModel> import_step_from_string(const std::string& step_data)`
| 参数 | 说明 |
|------|------|
| `step_data` | 完整的 STEP 文件内容(字符串形式) |
**返回**: B-Rep 体列表
**参见**: `import_step 从文件导入`
**获取最近一次 STEP 导入的错误码**
`[[nodiscard]] StepError step_last_error()`
**返回**: StepError 枚举值
**参见**: `step_last_error_message 获取可读的错误描述`
**获取最近一次 STEP 导入的可读错误描述**
`[[nodiscard]] const std::string& step_last_error_message()`
**返回**: 错误描述字符串(如 "Missing entity reference #42"
**参见**: `step_last_error 获取枚举错误码`
## SDF隐式建模 (`vde::sdf`)
### `sdf_gradient.h`
**SDF 梯度计算(数值微分、解析梯度、链式法则)**
**SDF 的空间梯度(中心差分近似)**
`[[nodiscard]] inline Vector3D gradient(`
| 参数 | 说明 |
|------|------|
| `f` | SDF 函数(接受 Point3D 参数) |
| `p` | 求值点 |
| `h` | 差分步长(默认 1e-6 |
**返回**: 梯度向量 ∇f(p)
> 步长太小会导致舍入误差主导,太大导致截断误差主导。
> 对于含不连续性的 SDF(如 sharp CSG),有限差分可能在边界产生错误梯度。
**参见**: `evaluate_with_gradient 一次性获取值和梯度`
**前向模梯度结果: SDF 值 + 梯度**
`struct GradResult {`
**同时计算 SDF 值和梯度的便捷函数**
`[[nodiscard]] inline GradResult evaluate_with_gradient(`
| 参数 | 说明 |
|------|------|
| `f` | SDF 函数 |
| `p` | 求值点 |
| `h` | 差分步长 |
**返回**: value + grad 结构
**参见**: `gradient 仅计算梯度`
**球体 SDF 对半径的参数梯度 ∂f/∂r**
`[[nodiscard]] inline double sphere_radius_gradient(const Point3D& p, double radius, double h = 1e-6)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 球体半径 |
| `h` | 差分步长(默认 1e-6 |
**返回**: ∂f/∂radius
> 对于球体,解析梯度为 -1(球面上),但此函数提供与实现无关的数值验证。
**参见**: `sphere_param_grad 封装版本`
**长方体 SDF 对各轴半尺寸的参数梯度 ∂f/∂extent[i]**
`[[nodiscard]] inline double box_extent_gradient(const Point3D& p, const Point3D& extents,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `extents` | 半边长 |
| `axis` | 轴索引: 0=x, 1=y, 2=z |
| `h` | 差分步长 |
**返回**: ∂f/∂extent[axis]
**参见**: `box_param_grad 封装版本`
**圆环 SDF 对主半径的参数梯度 ∂f/∂major_r**
`[[nodiscard]] inline double torus_major_gradient(const Point3D& p, double major_r, double minor_r,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `major_r` | 主半径 |
| `minor_r` | 副半径 |
| `h` | 差分步长 |
**返回**: 参数梯度
**圆环 SDF 对副半径的参数梯度 ∂f/∂minor_r**
`[[nodiscard]] inline double torus_minor_gradient(const Point3D& p, double major_r, double minor_r,`
**返回**: 参数梯度
**圆柱 SDF 对高度的参数梯度 ∂f/∂height**
`[[nodiscard]] inline double cylinder_height_gradient(const Point3D& p, double radius, double height,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 圆柱半径 |
| `height` | 圆柱高度 |
| `h` | 差分步长 |
**返回**: 参数梯度
**圆柱 SDF 对半径的参数梯度 ∂f/∂radius**
`[[nodiscard]] inline double cylinder_radius_gradient(const Point3D& p, double radius, double height,`
**返回**: 参数梯度
**球体 SDF 的解析梯度**
`[[nodiscard]] inline Vector3D sphere_gradient_analytic(const Point3D& p, double /*radius*/)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 球半径(当前未使用,保留以保持接口一致) |
**返回**: 解析梯度(单位向量)
> 在表面上 (|p| = radius),梯度即为外法向量。
**长方体 SDF 的解析梯度**
`[[nodiscard]] inline Vector3D box_gradient_analytic(const Point3D& p, const Point3D& half_extents)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `half_extents` | 半边长 |
**返回**: 解析梯度
**圆环 SDF 的解析梯度**
`[[nodiscard]] inline Vector3D torus_gradient_analytic(const Point3D& p, double major_r, double minor_r)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `major_r` | 主半径 |
| `minor_r` | 副半径 |
**返回**: 解析梯度
**无限圆柱(沿 Y 轴)的解析梯度**
`[[nodiscard]] inline Vector3D cylinder_gradient_analytic(const Point3D& p, double /*radius*/)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 圆柱半径(未使用,保留接口一致) |
**返回**: 解析梯度
**平面的解析梯度**
`[[nodiscard]] inline Vector3D plane_gradient_analytic(const Vector3D& normal)`
| 参数 | 说明 |
|------|------|
| `normal` | 单位法向量 |
**返回**: 梯度(等于 normal
> 这是最简单的解析梯度,因为平面 SDF 是线性的。
**胶囊体 SDF 的解析梯度**
`[[nodiscard]] inline Vector3D capsule_gradient_analytic(const Point3D& p,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `a` | 线段起点 |
| `b` | 线段终点 |
| `radius` | 扫掠球半径 |
**返回**: 解析梯度
**并集操作后的梯度传递**
`[[nodiscard]] inline Vector3D chain_union(const Vector3D& grad_a, const Vector3D& grad_b,`
| 参数 | 说明 |
|------|------|
| `grad_a` | 子对象 A 的梯度 |
| `grad_b` | 子对象 B 的梯度 |
| `d1` | A 的 SDF 值 |
| `d2` | B 的 SDF 值 |
**返回**: 合并后的梯度
**参见**: `chain_smooth_union 避免不连续的平滑版本`
**交集操作后的梯度传递**
`[[nodiscard]] inline Vector3D chain_intersection(const Vector3D& grad_a, const Vector3D& grad_b,`
**返回**: 合并后的梯度
**差集操作后的梯度传递**
`[[nodiscard]] inline Vector3D chain_difference(const Vector3D& grad_a, const Vector3D& grad_b,`
| 参数 | 说明 |
|------|------|
| `grad_a` | 子对象 A 的梯度 |
| `grad_b` | 子对象 B 的梯度 |
| `d1` | f_A |
| `d2` | f_B |
**返回**: 合并后的梯度
**平滑并集操作的梯度传递(含完整链式法则)**
`[[nodiscard]] inline Vector3D chain_smooth_union(const Vector3D& grad_a, const Vector3D& grad_b,`
| 参数 | 说明 |
|------|------|
| `grad_a` | 子对象 A 的梯度 |
| `grad_b` | 子对象 B 的梯度 |
| `d1` | f_A |
| `d2` | f_B |
| `k` | 混合参数 |
**返回**: 平滑合并后的梯度
**参见**: `op_smooth_union 对应的平滑并集 SDF 操作`, `chain_union 硬切换版本`
**平移变换后的梯度传递(梯度不变)**
`[[nodiscard]] inline GradResult chain_translate(const GradResult& child_result, const Point3D& /*offset*/)`
| 参数 | 说明 |
|------|------|
| `child_result` | 变换空间中的子对象求值结果 |
| `offset` | 平移量(仅接口保留) |
**返回**: 相同梯度
**绕 Y 轴旋转后的梯度传递**
`[[nodiscard]] inline GradResult chain_rotate(const GradResult& child_result, double angle_rad)`
| 参数 | 说明 |
|------|------|
| `child_result` | 旋转后坐标系中的子对象求值 |
| `angle_rad` | 旋转角度 |
**返回**: 世界坐标系的梯度
**参见**: `op_rotate 对应的域变形操作`
**非均匀缩放后的梯度传递**
`[[nodiscard]] inline GradResult chain_scale(const GradResult& child_result, const Point3D& factors)`
| 参数 | 说明 |
|------|------|
| `child_result` | 缩放后坐标系中的子对象求值 |
| `factors` | 缩放因子 |
**返回**: 世界坐标系的梯度
> 缩放后梯度不再是单位长度,除非是均匀缩放。
**扭曲变换后的梯度传递(含完整雅可比)**
`[[nodiscard]] inline GradResult chain_twist(const GradResult& child_result,`
| 参数 | 说明 |
|------|------|
| `child_result` | 扭曲空间中的子对象求值 |
| `amount` | 单位高度的旋转量 |
| `p` | 原始采样点 |
**返回**: 世界坐标系的梯度
**参见**: `op_twist 对应的域变形操作`, `chain_rotate 不含 Y 依赖的简化旋转梯度传递`
**周期重复后的梯度传递(梯度不变)**
`[[nodiscard]] inline GradResult chain_repeat(const GradResult& child_result,`
| 参数 | 说明 |
|------|------|
| `child_result` | 中心晶格内的子对象求值 |
| `cell` | 晶格尺寸(仅接口保留) |
| `p` | 原始采样点(仅接口保留) |
**返回**: 相同梯度
**参数梯度结构体**
`struct ParamGrad {`
**参见**: `sphere_param_grad, box_param_grad, cylinder_param_grad`
**球体所有参数的梯度(当前仅 radius 有意义)**
`[[nodiscard]] inline ParamGrad sphere_param_grad(const Point3D& p, double radius, double h = 1e-6)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 球体半径 |
| `h` | 差分步长 |
**返回**: 参数梯度(仅 d_radius 非零)
**参见**: `sphere_radius_gradient 底层数值差分`
**长方体所有参数的梯度**
`[[nodiscard]] inline ParamGrad box_param_grad(const Point3D& p, const Point3D& half_extents,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `half_extents` | 半边长 |
| `h` | 差分步长 |
**返回**: 参数梯度(d_extents 分量填充)
**参见**: `box_extent_gradient 底层数值差分`
**圆柱所有参数的梯度**
`[[nodiscard]] inline ParamGrad cylinder_param_grad(const Point3D& p, double radius, double height,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 圆柱半径 |
| `height` | 圆柱高度 |
| `h` | 差分步长 |
**返回**: 参数梯度(d_radius, d_height 填充)
### `sdf_operations.h`
**SDF 布尔运算、修饰算子与域变形**
**布尔并集: A B**
`[[nodiscard]] inline double op_union(double d1, double d2) {`
| 参数 | 说明 |
|------|------|
| `d1` | 第一个对象的 SDF 值 |
| `d2` | 第二个对象的 SDF 值 |
**返回**: 并集的 SDF 值
**参见**: `op_smooth_union 带平滑过渡的并集`, `op_intersection 交集`
**布尔交集: A ∩ B**
`[[nodiscard]] inline double op_intersection(double d1, double d2) {`
| 参数 | 说明 |
|------|------|
| `d1` | 第一个对象的 SDF 值 |
| `d2` | 第二个对象的 SDF 值 |
**返回**: 交集的 SDF 值
**参见**: `op_smooth_intersection 带平滑过渡的交集`
**布尔差集: A \ B**
`[[nodiscard]] inline double op_difference(double d1, double d2) {`
| 参数 | 说明 |
|------|------|
| `d1` | 被减对象 A 的 SDF 值 |
| `d2` | 减去对象 B 的 SDF 值 |
**返回**: 差集的 SDF 值
**参见**: `op_smooth_difference 带平滑过渡的差集`
**平滑并集(带混合过渡)**
`[[nodiscard]] inline double op_smooth_union(double d1, double d2, double k) {`
| 参数 | 说明 |
|------|------|
| `d1` | 第一个对象的 SDF 值 |
| `d2` | 第二个对象的 SDF 值 |
| `k` | 混合强度参数(> 0 时平滑过渡;≤ 0 时退化为普通并集) |
**返回**: 平滑混合后的 SDF 值
> 多项式混合是函数 f(x)=x 在 [0,k] 区间的平滑近似。在 d1=d2 处,f 向下偏移 k/4。
**参见**: `op_union 无平滑的标准并集`, `op_smooth_intersection 平滑交集`, `op_smooth_difference 平滑差集`
**平滑交集(带混合过渡)**
`[[nodiscard]] inline double op_smooth_intersection(double d1, double d2, double k) {`
| 参数 | 说明 |
|------|------|
| `d1` | 第一个对象的 SDF 值 |
| `d2` | 第二个对象的 SDF 值 |
| `k` | 混合强度参数 |
**返回**: 平滑混合后的 SDF 值
**参见**: `op_intersection 无平滑的标准交集`, `op_smooth_union 平滑并集`
**平滑差集(带混合过渡)**
`[[nodiscard]] inline double op_smooth_difference(double d1, double d2, double k) {`
| 参数 | 说明 |
|------|------|
| `d1` | 被减对象 A 的 SDF 值 |
| `d2` | 减去对象 B 的 SDF 值 |
| `k` | 混合强度参数 |
**返回**: 平滑混合后的 SDF 值
**参见**: `op_difference 无平滑的标准差集`, `op_smooth_union 平滑并集`
**圆角偏移: 将等值面向外扩展 r 单位**
`[[nodiscard]] inline double op_round(double d, double r) {`
| 参数 | 说明 |
|------|------|
| `d` | SDF 值 |
| `r` | 偏移距离(正值 = 膨胀,负值 = 收缩) |
**返回**: 偏移后的 SDF 值
**参见**: `op_onion 壳层修饰`, `round_box 特例化的圆角立方体`
**洋葱皮/壳层修饰: 取绝对值后减去厚度**
`[[nodiscard]] inline double op_onion(double d, double thickness) {`
| 参数 | 说明 |
|------|------|
| `d` | SDF 值 |
| `thickness` | 壳层半厚度,必须 > 0 |
**返回**: 壳层的 SDF 值
**参见**: `op_round 圆角偏移`
**无限重复(周期复制)**
`[[nodiscard]] inline Point3D op_repeat(const Point3D& p, const Point3D& cell) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `cell` | 晶格尺寸 (cx, cy, cz),各分量必须 > 0 才生效 |
**返回**: 映射到中心晶格内的点
> 边界处 SDF 可能不连续,需要确保各晶格间映射是连续的。
**镜像对称(X=0 平面),可选偏移**
`[[nodiscard]] inline Point3D op_mirror_x(const Point3D& p, double offset = 0.0) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `offset` | 镜像平面沿 X 轴的偏移量(默认 0 = X=0 平面) |
**返回**: 映射到镜像半空间的点
**参见**: `op_mirror_y YZ 平面镜像`, `op_mirror_z XY 平面镜像`
**镜像对称(Y=0 平面)**
`[[nodiscard]] inline Point3D op_mirror_y(const Point3D& p) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
**返回**: 映射到上半空间的点
**镜像对称(Z=0 平面)**
`[[nodiscard]] inline Point3D op_mirror_z(const Point3D& p) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
**返回**: 映射到前半空间的点
**空间平移(逆变换)**
`[[nodiscard]] inline Point3D op_translate(const Point3D& p, const Point3D& offset) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `offset` | 平移量(对象正向移动的方向) |
**返回**: 逆平移后的采样点
**参见**: `op_rotate 旋转变换`, `op_scale 缩放变换`
**绕 Y 轴旋转(逆变换)**
`[[nodiscard]] inline Point3D op_rotate(const Point3D& p, double angle_rad) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `angle_rad` | 旋转角度(弧度),正值 = 逆时针(从上往下看) |
**返回**: 逆旋转后的采样点
**参见**: `op_twist 绕 Y 轴的扭曲变换`, `op_bend 弯曲变换`
**非均匀缩放(逆变换)**
`[[nodiscard]] inline Point3D op_scale(const Point3D& p, const Point3D& s) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `s` | 各轴缩放因子 (sx, sy, sz),均必须 ≠ 0 |
**返回**: 缩放后的采样点
**参见**: `op_translate 平移(等距变换)`, `op_rotate 旋转(等距变换)`
**绕 Y 轴的扭曲变换**
`[[nodiscard]] inline Point3D op_twist(const Point3D& p, double amount) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `amount` | 单位高度上的旋转量(弧度/单位长度) |
**返回**: 扭曲后的采样点
**参见**: `op_rotate 恒定角度旋转`, `op_bend 弯曲变换`
**弯曲变换(绕 Z 轴弯曲 XZ 平面)**
`[[nodiscard]] inline Point3D op_bend(const Point3D& p, double k) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `k` | 弯曲曲率参数(k 越大弯曲越剧烈) |
**返回**: 弯曲后的采样点
**参见**: `op_cheap_bend 简化版弯曲(仅绕 X 轴)`, `op_twist 扭曲变换`
**拉伸/压扁域变形(消除拉伸方向上的内部体积)**
`[[nodiscard]] inline Point3D op_elongate(const Point3D& p, const Point3D& h) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `h` | 各轴的拉伸阈值 (hx, hy, hz),均 ≥ 0 |
**返回**: 变形后的采样点
**参见**: `op_repeat 周期重复`
**简化弯曲变换(绕 X 轴弯曲 YZ 平面)**
`[[nodiscard]] inline Point3D op_cheap_bend(const Point3D& p, double k) {`
| 参数 | 说明 |
|------|------|
| `p` | 原始采样点 |
| `k` | 弯曲曲率参数 |
**返回**: 弯曲后的采样点
> 使用场景:不需要精确物理弯曲,仅需视觉效果时优先用此函数以节省计算。
**参见**: `op_bend 完整弯曲变换`
**正弦波位移扰动**
`[[nodiscard]] inline double op_displace(double d, const Point3D& p,`
| 参数 | 说明 |
|------|------|
| `d` | 原始 SDF 值 |
| `p` | 采样点(用于扰动计算) |
| `amplitude` | 扰动幅值 |
| `frequency` | 空间频率 |
**返回**: 扰动后的 SDF 值
### `sdf_optimize.h`
**基于梯度的 SDF 形状优化**
**优化结果**
`struct OptimizeResult {`
**损失函数类型**
`using LossFn = std::function<double(const std::function<double(const Point3D&)>&)>`
**参见**: `fit_to_point_cloud 使用该类型的内置实现`
**将参数化形状拟合到目标点云**
`[[nodiscard]] OptimizeResult fit_to_point_cloud(`
| 参数 | 说明 |
|------|------|
| `initial` | 初始形状(sphere, box, cylinder 等),其参数将被优化 |
| `target_points` | 目标点云(表面采样点) |
| `learning_rate` | 梯度下降步长(默认 0.01) |
| `max_iterations` | 最大迭代次数(默认 100) |
**返回**: 优化结果(含优化后的形状和收敛信息)
> 损失函数为 L = mean(|sdf(p_i)|),即点到表面的平均绝对距离。
> initial 的共享子节点不会被复制——返回的 optimize_shape 共享未修改的子树。
**参见**: `fit_surface_to_points 类似但仅最小化 |sdf| 而非有符号距离`, `fit_to_sdf 拟合到另一个 SDF`
**将形状表面移动到目标采样点**
`[[nodiscard]] OptimizeResult fit_surface_to_points(`
| 参数 | 说明 |
|------|------|
| `initial` | 初始形状 |
| `surface_points` | 目标表面点 |
| `learning_rate` | 学习率 |
| `max_iterations` | 最大迭代次数 |
**返回**: 优化结果
**参见**: `fit_to_point_cloud 更通用的点云拟合(可包含内部/外部点)`
**拟合一个 SDF 形状以匹配另一个目标 SDF**
`[[nodiscard]] OptimizeResult fit_to_sdf(`
| 参数 | 说明 |
|------|------|
| `source` | 被优化的参数化形状 |
| `target_sdf` | 目标 SDF 函数 |
| `bmin` | 采样网格最小角点 |
| `bmax` | 采样网格最大角点 |
| `grid_resolution` | 采样网格分辨率(默认 16) |
| `learning_rate` | 学习率 |
| `max_iterations` | 最大迭代次数 |
**返回**: 优化结果
**参见**: `fit_to_point_cloud 拟合到点云`
**通过平移解决两个形状之间的穿透**
`[[nodiscard]] bool resolve_collision(`
| 参数 | 说明 |
|------|------|
| `shape_a` | 形状 A(原地修改) |
| `shape_b` | 形状 B(原地修改) |
| `step_size` | 每次迭代的平移步长(默认 0.1) |
| `max_iterations` | 最大迭代次数(默认 50 |
**返回**: true 如果碰撞被成功解决;false 如果在迭代次数内未能解决
**参见**: `penetration_depth 估算穿透深度`
**估算两个形状之间的最小穿透距离**
`[[nodiscard]] double penetration_depth(`
| 参数 | 说明 |
|------|------|
| `shape_a` | 形状 A |
| `shape_b` | 形状 B |
| `bmin` | 公共包围盒最小角点 |
| `bmax` | 公共包围盒最大角点 |
| `samples` | 蒙地卡罗采样数(默认 1000) |
**返回**: 最大穿透深度(负值表示不重叠时的最小间距)
**参见**: `resolve_collision 解决穿透`
**计算形状表面上点的可及性分数**
`[[nodiscard]] double accessibility(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `p` | 表面点(应满足 |sdf(p)| < ε) |
| `direction` | 接近方向 |
| `hemisphere_samples` | 半球采样光线数量(默认 64) |
**返回**: 可及性分数 [0, 1]
> 采样数越多越精确,但线性增加计算量。
**参见**: `find_accessible_point 找到最大可及性的表面点`
**找到给定接近方向下具有最大可及性的表面点**
`[[nodiscard]] Point3D find_accessible_point(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `approach_dir` | 接近方向(如工具接近方向) |
| `bmin` | 搜索包围盒最小角点 |
| `bmax` | 搜索包围盒最大角点 |
| `grid_res` | 搜索网格分辨率(默认 32) |
**返回**: 最大可及性的表面点
**参见**: `accessibility 单点可及性计算`
**检测形状在给定方向上的反射对称性**
`[[nodiscard]] double symmetry_score(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `bmin` | 包围盒最小角点 |
| `bmax` | 包围盒最大角点 |
| `plane_normal` | 反射平面的法向量 |
| `plane_offset` | 反射平面的偏移量(沿法向量方向,默认 0) |
| `samples` | 采样点对数(默认 1000) |
**返回**: 对称性分数 [0, 1](0 = 完全不对称,1 = 完美对称)
**参见**: `find_symmetry_plane 自动寻找最佳对称平面`
**对称检测结果**
`struct SymmetryResult {`
**自动找到形状的最佳反射对称平面**
`[[nodiscard]] SymmetryResult find_symmetry_plane(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `bmin` | 包围盒最小角点 |
| `bmax` | 包围盒最大角点 |
| `samples` | 每个候选方向的采样数(默认 1000) |
**返回**: 最佳对称平面及其分数
**参见**: `symmetry_score 给定方向的对称性检测`
**通过蒙地卡罗法估算隐式形状的体积**
`[[nodiscard]] double estimate_volume(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `bmin` | 采样包围盒最小角点 |
| `bmax` | 采样包围盒最大角点 |
| `samples` | 蒙地卡罗采样数(默认 10000) |
**返回**: 近似体积
> 精度与 √samples 成正比。10000 采样 ≈ 1% 相对误差。
> 包围盒应尽可能紧致以减小方差。
**参见**: `center_of_mass 蒙地卡罗质心估算`
**通过蒙地卡罗法估算形状的质心**
`[[nodiscard]] Point3D center_of_mass(`
| 参数 | 说明 |
|------|------|
| `shape` | SDF 形状 |
| `bmin` | 采样包围盒最小角点 |
| `bmax` | 采样包围盒最大角点 |
| `samples` | 蒙地卡罗采样数(默认 10000) |
**返回**: 近似质心坐标
**参见**: `estimate_volume 体积估算`
**SDF 树中可变参数的引用**
`struct ParamRef {`
**从叶节点收集所有可变数值参数**
`[[nodiscard]] std::vector<ParamRef> collect_params(SdfNodePtr& root)`
| 参数 | 说明 |
|------|------|
| `root` | SDF 树根节点(可写引用,因为参数将被原地修改) |
**返回**: 可变参数引用列表
**参见**: `numerical_gradient 计算损失对参数的数值梯度`
**计算标量损失对收集到的参数的数值梯度**
`[[nodiscard]] std::vector<double> numerical_gradient(`
| 参数 | 说明 |
|------|------|
| `params` | collect_params() 返回的参数引用列表 |
| `loss_fn` | 损失函数(无参数的可调用对象) |
| `eps` | 差分步长(默认 1e-6 |
**返回**: 梯度向量 grad_lossgrad_loss[i] = ∂loss / ∂params[i].value
**参见**: `collect_params 收集参数`, `GradientDescent 梯度下降优化器`
**固定学习率的简单梯度下降优化器**
**构造优化器**
`explicit GradientDescent(double lr) : lr_(lr) {}`
| 参数 | 说明 |
|------|------|
| `lr` | 学习率(步长因子) |
**执行单步梯度下降**
`double step(std::vector<double>& params,`
| 参数 | 说明 |
|------|------|
| `params` | 参数向量(原地修改) |
| `grad_fn` | 梯度计算函数,签名为 |
**返回**: 当前损失值
**设置学习率**
`void set_learning_rate(double lr) { lr_ = lr; }`
**获取学习率**
`[[nodiscard]] double learning_rate() const { return lr_; }`
**获取当前迭代次数**
`[[nodiscard]] int iteration() const { return iteration_; }`
### `sdf_primitives.h`
**有符号距离函数(SDF)基础图元**
> 所有图元假设未施加变换——坐标系原点即图元中心/基点。
**球体的 SDF**
`[[nodiscard]] inline double sphere(const Point3D& p, double radius) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点(三维坐标) |
| `radius` | 球半径,必须 > 0 |
**返回**: 有符号距离
> 球位于原点。如需其他位置,使用 op_translate 对采样点做反向平移。
**参见**: `ellipsoid 各轴半径不同的椭球`, `cylinder 沿 Y 轴的圆柱`
**轴对齐立方体的 SDF**
`[[nodiscard]] inline double box(const Point3D& p, const Point3D& half_extents) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `half_extents` | 半边长 (hx, hy, hz),均必须 ≥ 0 |
**返回**: 有符号距离
**参见**: `round_box 带圆角的盒子`, `wedge 对角切割的半盒子`
**圆角立方体的 SDF**
`[[nodiscard]] inline double round_box(const Point3D& p, const Point3D& half_extents, double r) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `half_extents` | 半边长 (hx, hy, hz) |
| `r` | 圆角半径,必须 < min(half_extents) 否则整体形态改变 |
**返回**: 有符号距离
**参见**: `box 无圆角的长方体`, `op_round 对任意 SDF 做圆角偏移`
**圆环面的 SDF**
`[[nodiscard]] inline double torus(const Point3D& p, double major_radius, double minor_radius) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `major_radius` | 主半径(环的半径),必须 > 0 |
| `minor_radius` | 副半径(管的粗细),必须 > 0 |
**返回**: 有符号距离
**参见**: `link 双环连接体(两个并行圆环的组合)`
**胶囊体的 SDF**
`[[nodiscard]] inline double capsule(const Point3D& p, const Point3D& a, const Point3D& b, double radius) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `a` | 线段起点 |
| `b` | 线段终点 |
| `radius` | 扫掠球半径,必须 > 0 |
**返回**: 有符号距离
**参见**: `cylinder 两端平头的圆柱(非球形端盖)`
**带平端盖的圆柱体 SDF**
`[[nodiscard]] inline double cylinder(const Point3D& p, double radius, double height) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 圆柱截面半径,必须 > 0 |
| `height` | 圆柱总高度(从 -h/2 到 +h/2),必须 > 0 |
**返回**: 有符号距离
**参见**: `capsule 两端球形端盖的圆柱`, `infinite_cylinder 无限长圆柱`, `cone 圆锥台`
**平面的 SDF**
`[[nodiscard]] inline double plane(const Point3D& p, const Vector3D& normal, double offset) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `normal` | 单位法向量(必须已归一化) |
| `offset` | 沿法向量正方向的偏移量 |
**返回**: 有符号距离
**参见**: `wedge 两个平面+盒子的组合(对角切割)`
**椭球体的 SDF(有界梯度近似)**
`[[nodiscard]] inline double ellipsoid(const Point3D& p, const Point3D& radii) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radii` | 半轴长 (rx, ry, rz),均必须 > 0 |
**返回**: 有符号距离(近似)
> 当三个半径相等时退化为球体,此时使用 sphere() 更精确高效。
> 当点到原点距离远大于最大半径时,近似精度下降。
**参见**: `sphere 精确球体(rx=ry=rz 时的特例)`
**正六棱柱的 SDF**
`[[nodiscard]] inline double hex_prism(const Point3D& p, double radius, double height) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `radius` | 六边形外接圆半径(中心到顶点),必须 > 0 |
| `height` | 挤出总高度(±h/2 沿 Y 轴),必须 > 0 |
**返回**: 有符号距离
**参见**: `extrusion_bounded 通用 bounded extrusion 算子`
**无限长圆柱的 SDF**
`[[nodiscard]] inline double infinite_cylinder(const Point3D& p, const Vector3D& axis, double radius) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `axis` | 圆柱轴线方向(必须归一化,|axis| = 1) |
| `radius` | 截面半径,必须 > 0 |
**返回**: 有符号距离
**参见**: `cylinder 有限长圆柱(带平端盖)`
**楔形体的 SDF**
`[[nodiscard]] inline double wedge(const Point3D& p, double w, double h, double d) {`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `w` | 宽度(X 方向) |
| `h` | 高度(Y 方向) |
| `d` | 深度(Z 方向) |
**返回**: 有符号距离
**参见**: `box 完整立方体`, `plane 独立平面 SDF`
**二维 SDF 沿 Z 轴的无限挤出**
`[[nodiscard]] inline double extrusion(const Point3D& /*p*/, double sdf_2d) {`
| 参数 | 说明 |
|------|------|
| `p` | 三维采样点(仅 x,y 分量被隐式使用——通过 sdf_2d 参数间接) |
| `sdf_2d` | 预计算的二维 SDF 值(在 (p.x, p.y) 处求值) |
**返回**: 三维有符号距离(等于 sdf_2d)
> p 参数仅保持接口一致,实际不影响结果。
> 对于有限长度的挤出,使用 extrusion_bounded()。
**参见**: `extrusion_bounded 有限长度的挤出`, `revolution 二维轮廓绕 Y 轴旋转`
**二维 SDF 的有限长度挤出**
`[[nodiscard]] inline double extrusion_bounded(const Point3D& p, double sdf_2d, double half_height) {`
| 参数 | 说明 |
|------|------|
| `p` | 三维采样点 |
| `sdf_2d` | 预计算的二维 SDF 值(在 (p.x, p.y) 处求值) |
| `half_height` | 挤出半高度(Z 方向),必须 ≥ 0 |
**返回**: 有符号距离
**参见**: `extrusion 无限挤出`, `hex_prism 六棱柱(特例化 bounded extrusion 实现)`
**二维轮廓绕 Y 轴的旋转体 SDF**
`[[nodiscard]] inline double revolution(const Point3D& /*p*/, double sdf_2d, double /*offset*/) {`
| 参数 | 说明 |
|------|------|
| `p` | 三维采样点(接口保留,不直接使用) |
| `sdf_2d` | 预计算的二维 SDF(在 (√(pₓ²+p𝓏²)-offset, p.y) 处求值) |
| `offset` | 径向偏移量(从 Y 轴的起点距离) |
**返回**: 有符号距离
**参见**: `torus 圆环(revolution 的特例:截面为圆)`
**圆锥台的 SDF(非内联实现)**
`[[nodiscard]] double cone(const Point3D& p, double angle_rad, double height)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `angle_rad` | 半锥角(弧度),决定底面半径 |
| `height` | 锥体总高度,必须 > 0 |
**返回**: 有符号距离
**参见**: `cylinder 半锥角为 0 时的退化情况`, `infinite_cone 无限圆锥`
**三角棱柱的 SDF(非内联实现)**
`[[nodiscard]] double triangular_prism(const Point3D& p, const Point3D& a, const Point3D& b,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `a` | 三角形顶点 A(XY 平面内) |
| `b` | 三角形顶点 B(XY 平面内) |
| `c` | 三角形顶点 C(XY 平面内) |
| `height` | 挤出总高度(沿 Z 轴),必须 > 0 |
**返回**: 有符号距离
**参见**: `wedge 直角三角形楔形体`
**双环链接体的 SDF(非内联实现)**
`[[nodiscard]] double link(const Point3D& p, double length, double major_r, double minor_r)`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `length` | 两个环心沿 X 轴的距离 |
| `major_r` | 每个环的主半径(环的半径) |
| `minor_r` | 每个环的管半径(截面的粗细) |
**返回**: 有符号距离
**参见**: `torus 单个圆环`
**无限圆锥的 SDF(非内联实现)**
`[[nodiscard]] double infinite_cone(const Point3D& p, const Point3D& apex,`
| 参数 | 说明 |
|------|------|
| `p` | 采样点 |
| `apex` | 锥顶位置 |
| `axis` | 锥轴方向(必须归一化),锥体沿此方向扩展 |
| `angle_rad` | 半锥角(弧度) |
**返回**: 有符号距离
**参见**: `cone 有限高圆锥台`
### `sdf_to_mesh.h`
**SDF 到三角网格的转换**
**将 SDF 表达式树转换为三角网格**
`[[nodiscard]] mesh::MCMesh sdf_to_mesh(const SdfNodePtr& root,`
| 参数 | 说明 |
|------|------|
| `root` | SDF 表达式树的根节点 |
| `resolution` | 每轴的网格分辨率(例如 64 表示 64³ 体素网格) |
| `iso_level` | 等值面水平(0.0 = 隐式表面) |
**返回**: 包含顶点和三角形索引的 MCMesh
> 分辨率推荐为 2 的幂(32, 64, 128, 256)以获得最佳缓存性能。
> 对于大尺寸但细节少的几何体,使用较低的 resolution 即可获得光滑结果。
**参见**: `sdf_to_mesh_lambda Lambda 版本的 SDF 转网格(Python 友好)`, `estimate_bbox 包围盒估算`
**将 Lambda SDF 函数转换为三角网格**
`[[nodiscard]] mesh::MCMesh sdf_to_mesh_lambda(`
| 参数 | 说明 |
|------|------|
| `f` | SDF 函数,签名为 double(double x, double y, double z) → 有符号距离 |
| `bmin` | 采样包围盒最小角点 |
| `bmax` | 采样包围盒最大角点 |
| `resolution` | 每轴分辨率 |
| `iso_level` | 等值面水平(默认 0.0 |
**返回**: MCMesh 三角网格
**参见**: `sdf_to_mesh 基于 SDF 树的网格转换`
### `sdf_torch.h`
**SDF 批量求值与梯度计算(CPU 后端)**
**在批处理模式下求值 SDF**
`void evaluate_batch(const SdfNodePtr& root,`
| 参数 | 说明 |
|------|------|
| `root` | SDF 表达式树根节点 |
| `points` | 点数组,length = 3·nx,y,z 交替存储 |
| `n` | 点数 |
| `distances` | 输出数组,length = n,写入有符号距离值 |
**参见**: `evaluate 单点求值`, `gradient_batch 批量梯度计算`
**在批处理模式下求值 SDF 的空间梯度**
`void gradient_batch(const SdfNodePtr& root,`
| 参数 | 说明 |
|------|------|
| `root` | SDF 表达式树根节点 |
| `points` | 点数组,length = 3·n |
| `n` | 点数 |
| `gradients` | 输出数组,length = 3·nx,y,z 梯度分量交替存储 |
**参见**: `evaluate_batch 批量距离求值`, `evaluate_with_gradient_batch 同时获取距离和梯度(减少重复采样)`
**一次遍历同时求值 SDF 值和梯度**
`void evaluate_with_gradient_batch(const SdfNodePtr& root,`
| 参数 | 说明 |
|------|------|
| `root` | SDF 表达式树根节点 |
| `points` | 点数组,length = 3·n |
| `n` | 点数 |
| `distances` | 输出距离数组,length = n |
| `gradients` | 输出梯度数组,length = 3·n |
> 对于大量点的场景(n > 1000),推荐使用本函数以获得 ~2× 速度提升。
**参见**: `evaluate_batch 仅求距离`, `gradient_batch 仅求梯度`
### `sdf_tree.h`
**SDF 表达式树结构**
**CSG 树的所有节点类型**
`enum class SdfOp : uint8_t {`
**参见**: `SdfParams 对应的参数结构`
**SDF 节点参数联合体**
`struct SdfParams {`
**SDF 表达式树节点**
> 树是不可变的——节点创建后 op 和子节点关系不变,但 params 可被外部修改以支持参数优化。
**创建球体节点**
`static SdfNodePtr sphere(double r)`
**创建轴对齐长方体节点**
`static SdfNodePtr box(const Point3D& half_extents)`
**创建圆角长方体节点**
`static SdfNodePtr round_box(const Point3D& half_extents, double r)`
**创建圆柱体节点**
`static SdfNodePtr cylinder(double r, double h)`
**创建圆环体节点**
`static SdfNodePtr torus(double major_r, double minor_r)`
**创建胶囊体节点**
`static SdfNodePtr capsule(const Point3D& a, const Point3D& b, double r)`
**创建圆锥台节点**
`static SdfNodePtr cone(double angle_rad, double h)`
**创建平面节点**
`static SdfNodePtr plane(const Vector3D& normal, double offset)`
**创建椭球体节点**
`static SdfNodePtr ellipsoid(const Point3D& radii)`
**创建三角棱柱节点**
`static SdfNodePtr triangular_prism(double h)`
**创建六棱柱节点**
`static SdfNodePtr hex_prism(double h)`
**创建双环链接节点**
`static SdfNodePtr link(double r, double length, double thickness)`
**创建楔形体节点**
`static SdfNodePtr wedge(const Point3D& extents)`
**创建并集节点: A B**
`static SdfNodePtr op_union(SdfNodePtr a, SdfNodePtr b)`
**创建交集节点: A ∩ B**
`static SdfNodePtr op_intersection(SdfNodePtr a, SdfNodePtr b)`
**创建差集节点: A \ B**
`static SdfNodePtr op_difference(SdfNodePtr a, SdfNodePtr b)`
**创建平滑并集节点**
`static SdfNodePtr smooth_union(SdfNodePtr a, SdfNodePtr b, double k)`
**创建平滑交集节点**
`static SdfNodePtr smooth_intersection(SdfNodePtr a, SdfNodePtr b, double k)`
**创建平滑差集节点**
`static SdfNodePtr smooth_difference(SdfNodePtr a, SdfNodePtr b, double k)`
**创建圆角偏移节点**
`static SdfNodePtr round(SdfNodePtr child, double r)`
**创建壳层修饰节点**
`static SdfNodePtr onion(SdfNodePtr child, double thickness)`
**创建周期重复节点**
`static SdfNodePtr repeat(SdfNodePtr child, const Point3D& cell)`
**创建 X 镜像节点**
`static SdfNodePtr mirror_x(SdfNodePtr child)`
**创建 Y 镜像节点**
`static SdfNodePtr mirror_y(SdfNodePtr child)`
**创建 Z 镜像节点**
`static SdfNodePtr mirror_z(SdfNodePtr child)`
**创建平移节点**
`static SdfNodePtr translate(SdfNodePtr child, const Point3D& offset)`
**创建旋转节点(绕 Y 轴)**
`static SdfNodePtr rotate(SdfNodePtr child, double angle_rad)`
**创建缩放节点**
`static SdfNodePtr scale(SdfNodePtr child, const Point3D& factors)`
**创建扭曲节点**
`static SdfNodePtr twist(SdfNodePtr child, double amount)`
**创建弯曲节点**
`static SdfNodePtr bend(SdfNodePtr child, double amount)`
**创建拉伸节点**
`static SdfNodePtr elongate(SdfNodePtr child, const Point3D& h)`
**创建简化弯曲节点**
`static SdfNodePtr cheap_bend(SdfNodePtr child, double amount)`
**创建位移扰动节点**
`static SdfNodePtr displace(SdfNodePtr child, double amplitude, double frequency)`
**前序遍历所有节点**
`template <typename Fn>`
**前序遍历(const 版本)**
`template <typename Fn>`
**参见**: `visit(Fn&&)`
**构造 SDF 节点**
`explicit SdfNode(SdfOp o) : op(o) {}`
| 参数 | 说明 |
|------|------|
| `o` | 操作类型 |
**在空间点 p 处求值 SDF 树**
`[[nodiscard]] double evaluate(const SdfNodePtr& root, const Point3D& p)`
| 参数 | 说明 |
|------|------|
| `root` | SDF 表达式树的根节点 |
| `p` | 世界空间中的采样点 |
**返回**: 有符号距离(负 = 内部,零 = 表面,正 = 外部)
**参见**: `estimate_bounds 估计树的包围盒`
**估算 SDF 树的包围半尺寸**
`[[nodiscard]] Point3D estimate_bounds(const SdfNodePtr& root, double margin = 1.0)`
| 参数 | 说明 |
|------|------|
| `root` | SDF 树的根节点 |
| `margin` | 额外安全边距(默认 1.0) |
**返回**: 包围半边长 (hx, hy, hz)
> 变形节点(旋转/弯曲/扭曲等)会使包围盒放大,以保守估计覆盖变形后区域。
**参见**: `estimate_bbox 完整 AABB 结果`
**SDF 树的包围盒(AABB**
`struct SdfBBox {`
**估算 SDF 树的完整轴对齐包围盒**
`[[nodiscard]] SdfBBox estimate_bbox(const SdfNodePtr& root, double margin = 1.0)`
| 参数 | 说明 |
|------|------|
| `root` | SDF 树的根节点 |
| `margin` | 额外安全边距 |
**返回**: AABB 包围盒
## 草图约束 (`vde::sketch`)
### `constraint_solver.h`
**草图点元素**
`struct SketchPoint {`
**草图线段元素**
`struct SketchLine {`
**草图圆元素**
`struct SketchCircle {`
**约束类型枚举**
`enum class ConstraintType {`
**约束实例**
`struct Constraint {`
**求解器返回结果**
`struct SolverResult {`
**二维几何约束求解器**
**添加自由点**
`int add_point(double x, double y, bool fixed = false)`
| 参数 | 说明 |
|------|------|
| `x` | X 坐标 |
| `y` | Y 坐标 |
| `fixed` | 是否固定(true 则排除变量) |
**返回**: 点 ID
**添加线段**
`int add_line(int p0, int p1)`
| 参数 | 说明 |
|------|------|
| `p0` | 起点 ID |
| `p1` | 终点 ID |
**返回**: 线段 ID
**添加圆**
`int add_circle(int center, double radius)`
| 参数 | 说明 |
|------|------|
| `center` | 圆心点 ID |
| `radius` | 半径 |
**返回**: 圆 ID
**添加约束**
`void add_constraint(ConstraintType type, const std::vector<int>& elements, double val = 0.0)`
| 参数 | 说明 |
|------|------|
| `type` | 约束类型 |
| `elements` | 约束涉及的元素 ID 列表 |
| `val` | 约束值(距离、角度等),默认 0 |
> 不同类型 elements 的语义:
**标记点为固定(硬约束)**
`void fix_point(int pid) {`
| 参数 | 说明 |
|------|------|
| `pid` | 点 ID |
> 固定点不参与变量优化,从自由度中排除
**执行约束求解**
`[[nodiscard]] SolverResult solve(int max_iter = 100, double tol = 1e-8)`
| 参数 | 说明 |
|------|------|
| `max_iter` | 最大 Gauss-Newton 迭代次数,默认 100 |
| `tol` | 收敛容差(梯度范数 < tol 时停止),默认 1e-8 |
**返回**: SolverResult 求解结果
> 收敛判断:||J^T r|| < tol
> 欠约束时(DOF > 0)解不唯一;过约束时(DOF < 0)为最小二乘解
**计算自由度**
`[[nodiscard]] int degrees_of_freedom() const`
**返回**: DOF = 2·N_free - Σ(约束方程数)
> DOF < 0 时系统过约束,求解器仍然工作但解非精确满足所有约束
**当前点集访问**
`[[nodiscard]] const std::vector<SketchPoint>& points() const { return points_; }`
**返回**: SketchPoint 数组只读引用
**查询点坐标**
`[[nodiscard]] Point2D get_point(int id) const`
| 参数 | 说明 |
|------|------|
| `id` | 点 ID |
**返回**: Point2D 当前坐标
**将求解器变量向量同步回 points_(用于 Jacobian 数值计算)**
`void sync_from_vars(const double* vars, int nv)`
| 参数 | 说明 |
|------|------|
| `vars` | 变量数组(长度为 2·N_free) |
| `nv` | 变量数 |
**评估单个约束的残差值**
`double eval_constraint(const Constraint& c) const`
| 参数 | 说明 |
|------|------|
| `c` | 约束 |
**返回**: 残差(方程 → 0 表示约束满足)
**计算单个约束的方程数**
`int count_equations(const Constraint& c) const`
| 参数 | 说明 |
|------|------|
| `c` | 约束 |
**返回**: Coincident/Fixed → 2,其余 → 1
**填充 Jacobian 矩阵中对应约束 ci 的行**
`void fill_jacobian_rows(const Constraint& c, int ci,`
| 参数 | 说明 |
|------|------|
| `c` | 约束 |
| `ci` | 约束索引 |
| `row_map` | 方程行映射 |
| `J_data` | Jacobian 矩阵数据(行优先) |
| `nv` | 变量数 |
| `stride` | 行跨度 |
## C API (`vde::capi`)
### `vde_capi.h`
**ViewDesignEngine C API — 跨语言边界接口**
`extern "C" {`
**参见**: `vde.h C++ 等价接口`
**引擎上下文句柄 — 管理错误状态和内部资源**
`typedef struct VdeContext* VdeHandle`
**三角网格句柄 — 顶点+面集合**
`typedef struct VdeMesh* VdeMeshHandle`
**参数曲线句柄 — NURBS 曲线**
`typedef struct VdeCurve* VdeCurveHandle`
**约束求解器句柄 — 二维草图约束**
`typedef struct VdeSolver* VdeSolverHandle`
**B-Rep 实体句柄 — 边界表示模型**
`typedef struct VdeBody* VdeBodyHandle`
**创建 ViewDesignEngine 上下文**
`VdeHandle vde_create(void)`
**返回**: 新的引擎句柄,不需要时通过 vde_destroy() 释放
**参见**: `vde_destroy 释放上下文`
**销毁引擎上下文**
`void vde_destroy(VdeHandle ctx)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
**参见**: `vde_create`
**获取引擎版本字符串**
`const char* vde_version(void)`
**返回**: 语义版本号字符串(如 "0.5.0"),静态生命周期,无需释放
**获取最后一次操作的错误描述**
`const char* vde_last_error(VdeHandle ctx)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
**返回**: 错误描述字符串(上下文的内部缓冲区,静态生命周期)
> 每次新的失败操作会覆盖此描述。成功操作不会清除它。
**从文件加载三角网格**
`VdeMeshHandle vde_load_mesh(VdeHandle ctx, const char* path)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `path` | 文件路径(UTF-8 编码) |
**返回**: 网格句柄,失败时返回 NULL(通过 vde_last_error() 获取原因)
**参见**: `vde_mesh_free 释放网格`, `vde_save_mesh 保存网格`
**将三角网格保存为文件**
`int vde_save_mesh(VdeHandle ctx, VdeMeshHandle mesh, const char* path, const char* format)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `mesh` | 网格句柄 |
| `path` | 输出文件路径 |
| `format` | 输出格式(当前仅 "obj" 有效) |
**返回**: 成功返回 1,失败返回 0
**参见**: `vde_load_mesh 加载网格`
**获取网格的顶点数量**
`size_t vde_mesh_num_vertices(VdeMeshHandle mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 网格句柄(必须有效且非 NULL) |
**返回**: 顶点数
**参见**: `vde_mesh_num_faces 面数`
**获取网格的三角面数量**
`size_t vde_mesh_num_faces(VdeMeshHandle mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 网格句柄 |
**返回**: 面数
**参见**: `vde_mesh_num_vertices 顶点数`
**获取指定索引的顶点坐标**
`void vde_mesh_get_vertex(VdeMeshHandle mesh, size_t idx,`
| 参数 | 说明 |
|------|------|
| `mesh` | 网格句柄 |
| `idx` | 顶点索引 [0, num_vertices) |
| `out_x` | [out] 顶点 X 坐标 |
| `out_y` | [out] 顶点 Y 坐标 |
| `out_z` | [out] 顶点 Z 坐标 |
**获取网格的轴对齐包围盒**
`void vde_mesh_get_bounds(VdeMeshHandle mesh,`
| 参数 | 说明 |
|------|------|
| `mesh` | 网格句柄 |
| `out_min_x` | [out] 最小 X 坐标 |
| `out_min_y` | [out] 最小 Y 坐标 |
| `out_min_z` | [out] 最小 Z 坐标 |
| `out_max_x` | [out] 最大 X 坐标 |
| `out_max_y` | [out] 最大 Y 坐标 |
| `out_max_z` | [out] 最大 Z 坐标 |
**释放网格句柄及其资源**
`void vde_mesh_free(VdeMeshHandle mesh)`
| 参数 | 说明 |
|------|------|
| `mesh` | 网格句柄 |
**网格简化**
`VdeMeshHandle vde_mesh_simplify(VdeHandle ctx, VdeMeshHandle mesh, double target_ratio)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `mesh` | 输入网格句柄(不修改输入) |
| `target_ratio` | 目标简化比率 [0, 1](0 = 不变,1 = 最大简化) |
**返回**: 简化后的新网格句柄
**参见**: `vde_mesh_smooth 网格平滑`
**网格平滑(Laplacian 或 Taubin 平滑)**
`VdeMeshHandle vde_mesh_smooth(VdeHandle ctx, VdeMeshHandle mesh, int iterations)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `mesh` | 输入网格句柄 |
| `iterations` | 平滑迭代次数 |
**返回**: 平滑后的新网格句柄
**参见**: `vde_mesh_simplify 网格简化`
**网格布尔运算**
`VdeMeshHandle vde_mesh_boolean(VdeHandle ctx, VdeMeshHandle a, VdeMeshHandle b, int operation)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `a` | 网格 A |
| `b` | 网格 B |
| `operation` | 布尔操作类型: 0 = 并集, 1 = 交集, 2 = 差集 (A \ B) |
**返回**: 布尔结果的新网格句柄
**创建 Bézier 曲线**
`VdeCurveHandle vde_curve_create_bezier(VdeHandle ctx, const double* control_points,`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `control_points` | 控制点数组,每 3 个 double 表示一个三维点 (x,y,z) |
| `num_points` | 控制点数量(次数 = num_points - 1 |
| `dim` | 维度(固定为 3 |
**返回**: 曲线句柄
**参见**: `vde_curve_evaluate 求值`, `vde_curve_free 释放`
**在参数 t 处求值曲线**
`void vde_curve_evaluate(VdeCurveHandle curve, double t,`
| 参数 | 说明 |
|------|------|
| `curve` | 曲线句柄 |
| `t` | 参数值 [0, 1] |
| `out_x` | [out] 曲线上点的 X 坐标 |
| `out_y` | [out] 曲线上点的 Y 坐标 |
| `out_z` | [out] 曲线上点的 Z 坐标 |
**获取曲线的次数**
`int vde_curve_degree(VdeCurveHandle curve)`
| 参数 | 说明 |
|------|------|
| `curve` | 曲线句柄 |
**返回**: 曲线次数
**释放曲线句柄**
`void vde_curve_free(VdeCurveHandle curve)`
| 参数 | 说明 |
|------|------|
| `curve` | 曲线句柄 |
**两球体碰撞检测(GJK 算法)**
`int vde_collision_gjk_spheres(VdeHandle ctx,`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `cx1,` | cy1, cz1 第一个球体的球心坐标 |
| `r1` | 第一个球体的半径 |
| `cx2,` | cy2, cz2 第二个球体的球心坐标 |
| `r2` | 第二个球体的半径 |
**返回**: 碰撞返回 1,不碰撞返回 0
**参见**: `vde_collision_ray_mesh 射线-网格相交`
**射线与网格的最近交点查询**
`int vde_collision_ray_mesh(VdeHandle ctx, VdeMeshHandle mesh,`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `mesh` | 目标网格句柄 |
| `ox,` | oy, oz 射线起点 |
| `dx,` | dy, dz 射线方向(无需归一化) |
| `out_t` | [out] 交点参数 t(沿射线的距离) |
| `out_x,` | out_y, out_z [out] 交点坐标 |
**返回**: 命中返回 1,未命中返回 0
**参见**: `vde_collision_gjk_spheres GJK 球体碰撞`
**创建二维约束求解器**
`VdeSolverHandle vde_solver_create(void)`
**返回**: 求解器句柄
**参见**: `vde_solver_free 释放`
**向求解器添加点**
`int vde_solver_add_point(VdeSolverHandle solver, double x, double y, int fixed)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `x` | 初始 X 坐标 |
| `y` | 初始 Y 坐标 |
| `fixed` | 固定点标记(1 = 固定不移动) |
**返回**: 点的 ID(用于后续约束引用)
**参见**: `vde_solver_add_line 添加线段`
**向求解器添加线段(由两个点定义)**
`int vde_solver_add_line(VdeSolverHandle solver, int p0, int p1)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `p0` | 起点 ID |
| `p1` | 终点 ID |
**返回**: 线段的 ID
**参见**: `vde_solver_add_point 添加点`, `vde_solver_add_horizontal 添加水平约束`, `vde_solver_add_vertical 添加垂直约束`
**添加距离约束(两点之间)**
`void vde_solver_add_distance_constraint(VdeSolverHandle solver, int p0, int p1, double d)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `p0` | 第一个点的 ID |
| `p1` | 第二个点的 ID |
| `d` | 目标距离(必须 > 0) |
**参见**: `vde_solver_add_horizontal 水平约束`
**添加水平约束(线段水平)**
`void vde_solver_add_horizontal(VdeSolverHandle solver, int line_id)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `line_id` | 线段 ID |
**参见**: `vde_solver_add_vertical 垂直约束`, `vde_solver_add_line 添加线段`
**添加垂直约束(线段垂直)**
`void vde_solver_add_vertical(VdeSolverHandle solver, int line_id)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `line_id` | 线段 ID |
**参见**: `vde_solver_add_horizontal 水平约束`
**求解约束系统**
`int vde_solver_solve(VdeSolverHandle solver, int max_iter, double tol)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `max_iter` | 最大迭代次数 |
| `tol` | 收敛容差 |
**返回**: 收敛返回 1,未收敛返回 0
**参见**: `vde_solver_get_point 获取求解后的点坐标`
**获取求解后的点坐标**
`void vde_solver_get_point(VdeSolverHandle solver, int idx, double* out_x, double* out_y)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
| `idx` | 点 ID |
| `out_x` | [out] 求解后 X 坐标 |
| `out_y` | [out] 求解后 Y 坐标 |
**释放求解器句柄**
`void vde_solver_free(VdeSolverHandle solver)`
| 参数 | 说明 |
|------|------|
| `solver` | 求解器句柄 |
**创建实心立方体 B-Rep**
`VdeBodyHandle vde_body_create_box(VdeHandle ctx, double w, double h, double d)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `w` | 宽度(X 方向),> 0 |
| `h` | 高度(Y 方向),> 0 |
| `d` | 深度(Z 方向),> 0 |
**返回**: B-Rep 实体句柄
**参见**: `vde_body_create_cylinder 圆柱体`, `vde_body_create_sphere 球体`
**创建实心圆柱体 B-Rep**
`VdeBodyHandle vde_body_create_cylinder(VdeHandle ctx, double r, double h, int segs)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `r` | 截面半径,> 0 |
| `h` | 总高度(从 -h/2 到 +h/2 |
| `segs` | 截面分段数(边数) |
**返回**: B-Rep 实体句柄
**参见**: `vde_body_create_box 立方体`
**创建球体 B-Rep**
`VdeBodyHandle vde_body_create_sphere(VdeHandle ctx, double r, int su, int sv)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `r` | 球半径,> 0 |
| `su` | 经度方向分段数 |
| `sv` | 纬度方向分段数 |
**返回**: B-Rep 实体句柄
**将 B-Rep 实体转换为三角网格**
`VdeMeshHandle vde_body_to_mesh(VdeHandle ctx, VdeBodyHandle body, double deflection)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `body` | B-Rep 实体句柄 |
| `deflection` | 弦高误差(越小 = 越精细,推荐 0.01) |
**返回**: 三角网格句柄
**参见**: `vde_body_free 释放 B-Rep 实体`
**释放 B-Rep 实体句柄**
`void vde_body_free(VdeBodyHandle body)`
| 参数 | 说明 |
|------|------|
| `body` | B-Rep 实体句柄 |
**将网格序列化为二进制字节流**
`size_t vde_serialize_mesh(VdeHandle ctx, VdeMeshHandle mesh, uint8_t** out_data)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `mesh` | 网格句柄 |
| `out_data` | [out] 指向序列化字节数组的指针 |
**返回**: 字节数
> 输出的缓冲区由库管理,调用方不得直接 free/delete。
**参见**: `vde_deserialize_mesh 反序列化`, `vde_free_buffer 释放序列化缓冲区`
**从二进制字节流反序列化为网格**
`VdeMeshHandle vde_deserialize_mesh(VdeHandle ctx, const uint8_t* data, size_t len)`
| 参数 | 说明 |
|------|------|
| `ctx` | 引擎上下文句柄 |
| `data` | 序列化数据缓冲区 |
| `len` | 数据长度(字节数) |
**返回**: 反序列化后的网格句柄
**参见**: `vde_serialize_mesh 序列化`
**释放由 vde_serialize_mesh 分配的缓冲区**
`void vde_free_buffer(uint8_t* ptr)`
| 参数 | 说明 |
|------|------|
| `ptr` | 由 vde_serialize_mesh 返回的缓冲区指针 |