#pragma once /** * @file vde_capi.h * @brief ViewDesignEngine C API — 跨语言边界接口 * * 提供稳定的 C ABI 接口,使 Python、Rust、C# 等语言可以通过 FFI 调用 * ViewDesignEngine 的核心功能,无需依赖 C++ ABI。 * * ## 设计原则 * * 1. **不透明句柄**: 所有内部对象(网格、曲线、求解器等)通过 `typedef` 前向声明 * 隐藏为不透明指针类型,外部代码只能通过 API 函数操作 * 2. **C 兼容类型**: 仅使用 C 原生类型(int, double, const char*)作为参数和返回值 * 3. **输出通过指针**: 复数返回值(如顶点坐标、包围盒)通过输出参数传递,避免结构体 ABI 问题 * 4. **显式生命周期管理**: 每个 create/load 函数都有对应的 free/destroy 函数 * * ## 句柄类型 * * | C 类型 | 内部类型 | 创建方式 | 释放方式 | * |------------------|--------------------|-----------------------------|-------------------| * | VdeHandle | VdeContext | vde_create() | vde_destroy() | * | VdeMeshHandle | HalfedgeMesh | vde_load_mesh(), 工厂函数 | vde_mesh_free() | * | VdeCurveHandle | NurbsCurve | vde_curve_create_bezier() | vde_curve_free() | * | VdeSolverHandle | ConstraintSolver | vde_solver_create() | vde_solver_free() | * | VdeBodyHandle | BrepModel | vde_body_create_*() | vde_body_free() | * * ## 布尔操作编码 * * | 操作 | 整数值 | * |------|--------| * | 并集 | 0 | * | 交集 | 1 | * | 差集 | 2 | * * ## 线程安全性 * * - 每个 VdeHandle 是独立的上下文,不同句柄之间线程安全 * - 同一句柄上的操作不是线程安全的(调用方负责同步) * * @ingroup capi * @see vde.h C++ 等价接口 */ #include #include #ifdef __cplusplus extern "C" { #endif // ═══════════════════════════════════════════════════════════ // 不透明句柄类型(在 vde.h 中已有前向声明) // ═══════════════════════════════════════════════════════════ /** @brief 引擎上下文句柄 — 管理错误状态和内部资源 */ #ifndef VDE_HANDLE_DEFINED typedef struct VdeContext* VdeHandle; #endif /** @brief 三角网格句柄 — 顶点+面集合 */ #ifndef VDE_MESH_HANDLE_DEFINED typedef struct VdeMesh* VdeMeshHandle; #endif /** @brief 参数曲线句柄 — NURBS 曲线 */ #ifndef VDE_CURVE_HANDLE_DEFINED typedef struct VdeCurve* VdeCurveHandle; #endif /** @brief 约束求解器句柄 — 二维草图约束 */ #ifndef VDE_SOLVER_HANDLE_DEFINED typedef struct VdeSolver* VdeSolverHandle; #endif /** @brief B-Rep 实体句柄 — 边界表示模型 */ #ifndef VDE_BODY_HANDLE_DEFINED typedef struct VdeBody* VdeBodyHandle; #endif // ═══════════════════════════════════════════════════════════ // 引擎生命周期 // ═══════════════════════════════════════════════════════════ /** * @brief 创建 ViewDesignEngine 上下文 * * 初始化一个独立的引擎实例。几乎所有后续操作都需要传入此句柄。 * * @return 新的引擎句柄,不需要时通过 vde_destroy() 释放 * * @code{.py} * // Python ctypes 示例 * ctx = lib.vde_create() * @endcode * * @see vde_destroy 释放上下文 */ VdeHandle vde_create(void); /** * @brief 销毁引擎上下文 * * 释放上下文及其内部资源。销毁后不能再使用该句柄。 * * @param ctx 引擎上下文句柄 * * @see vde_create */ void vde_destroy(VdeHandle ctx); /** * @brief 获取引擎版本字符串 * * @return 语义版本号字符串(如 "0.5.0"),静态生命周期,无需释放 * * @code{.c} * printf("VDE version: %s\n", vde_version()); * @endcode */ const char* vde_version(void); /** * @brief 获取最后一次操作的错误描述 * * 当某操作失败(如加载不存在的文件)时,可通过此函数获取详情。 * * @param ctx 引擎上下文句柄 * @return 错误描述字符串(上下文的内部缓冲区,静态生命周期) * * @note 每次新的失败操作会覆盖此描述。成功操作不会清除它。 */ const char* vde_last_error(VdeHandle ctx); // ═══════════════════════════════════════════════════════════ // 网格 I/O // ═══════════════════════════════════════════════════════════ /** * @brief 从文件加载三角网格 * * 支持 OBJ (.obj), STL (.stl), PLY (.ply) 三种格式。 * 格式通过文件扩展名自动检测。 * * @param ctx 引擎上下文句柄 * @param path 文件路径(UTF-8 编码) * @return 网格句柄,失败时返回 NULL(通过 vde_last_error() 获取原因) * * @code{.c} * VdeMeshHandle mesh = vde_load_mesh(ctx, "model.obj"); * if (!mesh) { * fprintf(stderr, "Load failed: %s\n", vde_last_error(ctx)); * return; * } * @endcode * * @see vde_mesh_free 释放网格 * @see vde_save_mesh 保存网格 */ VdeMeshHandle vde_load_mesh(VdeHandle ctx, const char* path); /** * @brief 将三角网格保存为文件 * * 当前支持 OBJ 格式输出。 * * @param ctx 引擎上下文句柄 * @param mesh 网格句柄 * @param path 输出文件路径 * @param format 输出格式(当前仅 "obj" 有效) * @return 成功返回 1,失败返回 0 * * @see vde_load_mesh 加载网格 */ int vde_save_mesh(VdeHandle ctx, VdeMeshHandle mesh, const char* path, const char* format); // ═══════════════════════════════════════════════════════════ // 网格查询 // ═══════════════════════════════════════════════════════════ /** * @brief 获取网格的顶点数量 * * @param mesh 网格句柄(必须有效且非 NULL) * @return 顶点数 * * @see vde_mesh_num_faces 面数 */ size_t vde_mesh_num_vertices(VdeMeshHandle mesh); /** * @brief 获取网格的三角面数量 * * @param mesh 网格句柄 * @return 面数 * * @see vde_mesh_num_vertices 顶点数 */ size_t vde_mesh_num_faces(VdeMeshHandle mesh); /** * @brief 获取指定索引的顶点坐标 * * 顶点索引从 0 开始,到 num_vertices - 1。 * * @param mesh 网格句柄 * @param idx 顶点索引 [0, num_vertices) * @param out_x [out] 顶点 X 坐标 * @param out_y [out] 顶点 Y 坐标 * @param out_z [out] 顶点 Z 坐标 * * @pre idx < vde_mesh_num_vertices(mesh) */ void vde_mesh_get_vertex(VdeMeshHandle mesh, size_t idx, double* out_x, double* out_y, double* out_z); /** * @brief 获取网格的轴对齐包围盒 * * @param mesh 网格句柄 * @param out_min_x [out] 最小 X 坐标 * @param out_min_y [out] 最小 Y 坐标 * @param out_min_z [out] 最小 Z 坐标 * @param out_max_x [out] 最大 X 坐标 * @param out_max_y [out] 最大 Y 坐标 * @param out_max_z [out] 最大 Z 坐标 */ void vde_mesh_get_bounds(VdeMeshHandle mesh, double* out_min_x, double* out_min_y, double* out_min_z, double* out_max_x, double* out_max_y, double* out_max_z); /** * @brief 释放网格句柄及其资源 * * 释放后将不能再使用该句柄。 * * @param mesh 网格句柄 */ void vde_mesh_free(VdeMeshHandle mesh); // ═══════════════════════════════════════════════════════════ // 网格处理 // ═══════════════════════════════════════════════════════════ /** * @brief 网格简化 * * 通过 edge-collapse 或类似算法减少三角形数量, * 同时尽可能保留几何特征。 * * @param ctx 引擎上下文句柄 * @param mesh 输入网格句柄(不修改输入) * @param target_ratio 目标简化比率 [0, 1](0 = 不变,1 = 最大简化) * @return 简化后的新网格句柄 * * @code{.c} * VdeMeshHandle simple = vde_mesh_simplify(ctx, mesh, 0.5); // 减少 50% * @endcode * * @see vde_mesh_smooth 网格平滑 */ VdeMeshHandle vde_mesh_simplify(VdeHandle ctx, VdeMeshHandle mesh, double target_ratio); /** * @brief 网格平滑(Laplacian 或 Taubin 平滑) * * 通过迭代平滑顶点位置改善网格质量,减少噪声。 * * @param ctx 引擎上下文句柄 * @param mesh 输入网格句柄 * @param iterations 平滑迭代次数 * @return 平滑后的新网格句柄 * * @see vde_mesh_simplify 网格简化 */ VdeMeshHandle vde_mesh_smooth(VdeHandle ctx, VdeMeshHandle mesh, int iterations); /** * @brief 网格布尔运算 * * 对两个三角网格执行布尔操作。 * * @param ctx 引擎上下文句柄 * @param a 网格 A * @param b 网格 B * @param operation 布尔操作类型: 0 = 并集, 1 = 交集, 2 = 差集 (A \ B) * @return 布尔结果的新网格句柄 * * @warning 两个输入网格必须是水密的(closed manifold),否则结果不可预测。 * * @code{.c} * VdeMeshHandle result = vde_mesh_boolean(ctx, box, sphere, 0); // 并集 * @endcode */ VdeMeshHandle vde_mesh_boolean(VdeHandle ctx, VdeMeshHandle a, VdeMeshHandle b, int operation); // ═══════════════════════════════════════════════════════════ // 曲线 // ═══════════════════════════════════════════════════════════ /** * @brief 创建 Bézier 曲线 * * @param ctx 引擎上下文句柄 * @param control_points 控制点数组,每 3 个 double 表示一个三维点 (x,y,z) * @param num_points 控制点数量(次数 = num_points - 1) * @param dim 维度(固定为 3) * @return 曲线句柄 * * @code{.c} * double cp[] = {0,0,0, 1,2,0, 3,0,0}; // 3 控制点,2 次 Bézier * VdeCurveHandle curve = vde_curve_create_bezier(ctx, cp, 3, 3); * @endcode * * @see vde_curve_evaluate 求值 * @see vde_curve_free 释放 */ VdeCurveHandle vde_curve_create_bezier(VdeHandle ctx, const double* control_points, int num_points, int dim); /** * @brief 在参数 t 处求值曲线 * * @param curve 曲线句柄 * @param t 参数值 [0, 1] * @param out_x [out] 曲线上点的 X 坐标 * @param out_y [out] 曲线上点的 Y 坐标 * @param out_z [out] 曲线上点的 Z 坐标 * * @pre 0 ≤ t ≤ 1 */ void vde_curve_evaluate(VdeCurveHandle curve, double t, double* out_x, double* out_y, double* out_z); /** * @brief 获取曲线的次数 * * 对于 Bézier 曲线,次数 = 控制点数 - 1。 * * @param curve 曲线句柄 * @return 曲线次数 */ int vde_curve_degree(VdeCurveHandle curve); /** * @brief 释放曲线句柄 * * @param curve 曲线句柄 */ void vde_curve_free(VdeCurveHandle curve); // ═══════════════════════════════════════════════════════════ // 碰撞检测 // ═══════════════════════════════════════════════════════════ /** * @brief 两球体碰撞检测(GJK 算法) * * 用于验证和测试 GJK 碰撞检测算法的轻量级接口。 * * @param ctx 引擎上下文句柄 * @param cx1, cy1, cz1 第一个球体的球心坐标 * @param r1 第一个球体的半径 * @param cx2, cy2, cz2 第二个球体的球心坐标 * @param r2 第二个球体的半径 * @return 碰撞返回 1,不碰撞返回 0 * * @code{.c} * int hit = vde_collision_gjk_spheres(ctx, 0,0,0, 1.0, 1.5,0,0, 0.5); * @endcode * * @see vde_collision_ray_mesh 射线-网格相交 */ int vde_collision_gjk_spheres(VdeHandle ctx, double cx1, double cy1, double cz1, double r1, double cx2, double cy2, double cz2, double r2); /** * @brief 射线与网格的最近交点查询 * * 使用 BVH 加速结构加速查询。 * * @param ctx 引擎上下文句柄 * @param mesh 目标网格句柄 * @param ox, oy, oz 射线起点 * @param dx, dy, dz 射线方向(无需归一化) * @param out_t [out] 交点参数 t(沿射线的距离) * @param out_x, out_y, out_z [out] 交点坐标 * @return 命中返回 1,未命中返回 0 * * @code{.c} * double t, hx, hy, hz; * int hit = vde_collision_ray_mesh(ctx, mesh, * 0,0,-10, // 射线起点 * 0,0,1, // 射线方向 (沿 Z 轴正方向) * &t, &hx, &hy, &hz); * if (hit) printf("Hit at (%f,%f,%f), t=%f\n", hx, hy, hz, t); * @endcode * * @see vde_collision_gjk_spheres GJK 球体碰撞 */ int vde_collision_ray_mesh(VdeHandle ctx, VdeMeshHandle mesh, double ox, double oy, double oz, double dx, double dy, double dz, double* out_t, double* out_x, double* out_y, double* out_z); // ═══════════════════════════════════════════════════════════ // 约束求解器(二维草图) // ═══════════════════════════════════════════════════════════ /** * @brief 创建二维约束求解器 * * 用于求解草图几何约束(距离、水平、垂直等)。 * * @return 求解器句柄 * * @see vde_solver_free 释放 */ VdeSolverHandle vde_solver_create(void); /** * @brief 向求解器添加点 * * @param solver 求解器句柄 * @param x 初始 X 坐标 * @param y 初始 Y 坐标 * @param fixed 固定点标记(1 = 固定不移动) * @return 点的 ID(用于后续约束引用) * * @see vde_solver_add_line 添加线段 */ int vde_solver_add_point(VdeSolverHandle solver, double x, double y, int fixed); /** * @brief 向求解器添加线段(由两个点定义) * * @param solver 求解器句柄 * @param p0 起点 ID * @param p1 终点 ID * @return 线段的 ID * * @see vde_solver_add_point 添加点 * @see vde_solver_add_horizontal 添加水平约束 * @see vde_solver_add_vertical 添加垂直约束 */ int vde_solver_add_line(VdeSolverHandle solver, int p0, int p1); /** * @brief 添加距离约束(两点之间) * * @param solver 求解器句柄 * @param p0 第一个点的 ID * @param p1 第二个点的 ID * @param d 目标距离(必须 > 0) * * @see vde_solver_add_horizontal 水平约束 */ void vde_solver_add_distance_constraint(VdeSolverHandle solver, int p0, int p1, double d); /** * @brief 添加水平约束(线段水平) * * @param solver 求解器句柄 * @param line_id 线段 ID * * @see vde_solver_add_vertical 垂直约束 * @see vde_solver_add_line 添加线段 */ void vde_solver_add_horizontal(VdeSolverHandle solver, int line_id); /** * @brief 添加垂直约束(线段垂直) * * @param solver 求解器句柄 * @param line_id 线段 ID * * @see vde_solver_add_horizontal 水平约束 */ void vde_solver_add_vertical(VdeSolverHandle solver, int line_id); /** * @brief 求解约束系统 * * 通过迭代优化使所有点的位置满足所有约束。 * * @param solver 求解器句柄 * @param max_iter 最大迭代次数 * @param tol 收敛容差 * @return 收敛返回 1,未收敛返回 0 * * @code{.c} * int converged = vde_solver_solve(solver, 100, 1e-6); * @endcode * * @see vde_solver_get_point 获取求解后的点坐标 */ int vde_solver_solve(VdeSolverHandle solver, int max_iter, double tol); /** * @brief 获取求解后的点坐标 * * @param solver 求解器句柄 * @param idx 点 ID * @param out_x [out] 求解后 X 坐标 * @param out_y [out] 求解后 Y 坐标 * * @pre 必须先调用 vde_solver_solve() */ void vde_solver_get_point(VdeSolverHandle solver, int idx, double* out_x, double* out_y); /** * @brief 释放求解器句柄 * * @param solver 求解器句柄 */ void vde_solver_free(VdeSolverHandle solver); // ═══════════════════════════════════════════════════════════ // B-Rep 建模 // ═══════════════════════════════════════════════════════════ /** * @brief 创建实心立方体 B-Rep * * 以原点为中心的轴对齐立方体。 * * @param ctx 引擎上下文句柄 * @param w 宽度(X 方向),> 0 * @param h 高度(Y 方向),> 0 * @param d 深度(Z 方向),> 0 * @return B-Rep 实体句柄 * * @see vde_body_create_cylinder 圆柱体 * @see vde_body_create_sphere 球体 */ VdeBodyHandle vde_body_create_box(VdeHandle ctx, double w, double h, double d); /** * @brief 创建实心圆柱体 B-Rep * * 沿 Y 轴、以原点为中心的圆柱体。 * * @param ctx 引擎上下文句柄 * @param r 截面半径,> 0 * @param h 总高度(从 -h/2 到 +h/2) * @param segs 截面分段数(边数) * @return B-Rep 实体句柄 * * @see vde_body_create_box 立方体 */ VdeBodyHandle vde_body_create_cylinder(VdeHandle ctx, double r, double h, int segs); /** * @brief 创建球体 B-Rep * * @param ctx 引擎上下文句柄 * @param r 球半径,> 0 * @param su 经度方向分段数 * @param sv 纬度方向分段数 * @return B-Rep 实体句柄 */ VdeBodyHandle vde_body_create_sphere(VdeHandle ctx, double r, int su, int sv); /** * @brief 将 B-Rep 实体转换为三角网格 * * 以指定的弦高误差对曲面进行 tessellation。 * * @param ctx 引擎上下文句柄 * @param body B-Rep 实体句柄 * @param deflection 弦高误差(越小 = 越精细,推荐 0.01) * @return 三角网格句柄 * * @code{.c} * VdeBodyHandle body = vde_body_create_box(ctx, 10, 5, 3); * VdeMeshHandle mesh = vde_body_to_mesh(ctx, body, 0.01); * vde_save_mesh(ctx, mesh, "box.obj", "obj"); * @endcode * * @see vde_body_free 释放 B-Rep 实体 */ VdeMeshHandle vde_body_to_mesh(VdeHandle ctx, VdeBodyHandle body, double deflection); /** * @brief 释放 B-Rep 实体句柄 * * @param body B-Rep 实体句柄 */ void vde_body_free(VdeBodyHandle body); /** * @brief 深拷贝 B-Rep 实体 * * 创建 B-Rep 实体的完整独立副本,修改副本不影响原实体。 * * @param ctx 引擎上下文句柄 * @param body 源 B-Rep 实体句柄(不会被修改) * @return 新的 B-Rep 实体句柄,调用方通过 vde_body_free() 释放 * * @note 深拷贝会复制所有几何数据(曲面、边、顶点),开销随复杂度增长。 * * @see vde_body_free * @ingroup capi */ VdeBodyHandle vde_body_clone(VdeHandle ctx, VdeBodyHandle body); // ── B-Rep STEP/IGES I/O ── /** * @brief 从 STEP 文件导入 B-Rep 实体列表 * * STEP(ISO 10303)是工业标准的 CAD 数据交换格式。 * 一个 STEP 文件可能包含多个实体,所有实体同时加载。 * * @param ctx 引擎上下文句柄 * @param path STEP 文件路径(UTF-8 编码) * @param out_bodies [out] 指向实体句柄数组的指针,由库分配,调用方通过 vde_body_free_array() 释放 * @return 导入的实体数量,失败返回 0(通过 vde_last_error() 获取原因) * * @warning 若返回 0,out_bodies 的值未定义,不应使用或释放 * * @note 内存管理:成功时库分配 VdeBodyHandle 数组,调用方必须调用 * vde_body_free_array(out_bodies, count) 释放。 * 数组中每个 body 由 free_array 统一释放,调用方不应单独 vde_body_free。 * * @code{.c} * VdeBodyHandle* bodies = NULL; * int count = vde_body_load_step(ctx, \"assembly.stp\", &bodies); * for (int i = 0; i < count; i++) { * VdeMeshHandle mesh = vde_body_to_mesh(ctx, bodies[i], 0.01); * // ... use mesh ... * vde_mesh_free(mesh); * } * vde_body_free_array(bodies, count); * @endcode * * @see vde_body_save_step, vde_body_load_iges, vde_body_free_array * @ingroup capi */ int vde_body_load_step(VdeHandle ctx, const char* path, VdeBodyHandle** out_bodies); /** * @brief 从 IGES 文件导入 B-Rep 实体列表 * * IGES(Initial Graphics Exchange Specification)是较早期的 CAD 交换格式。 * * @param ctx 引擎上下文句柄 * @param path IGES 文件路径(UTF-8 编码) * @param out_bodies [out] 指向实体句柄数组的指针,由库分配,调用方通过 vde_body_free_array() 释放 * @return 导入的实体数量,失败返回 0 * * @note 内存管理约定与 vde_body_load_step 相同:成功时库分配数组,调用方负责 vde_body_free_array。 * * @see vde_body_save_iges, vde_body_load_step * @ingroup capi */ int vde_body_load_iges(VdeHandle ctx, const char* path, VdeBodyHandle** out_bodies); /** * @brief 将 B-Rep 实体列表导出为 STEP 文件 * * @param ctx 引擎上下文句柄 * @param bodies B-Rep 实体句柄数组(调用方管理生命周期) * @param count 实体数量 * @param path 输出文件路径 * @return 成功返回 1,失败返回 0 * * @note bodies 数组的所有权不转移给此函数,调用方继续管理。 * * @see vde_body_load_step * @ingroup capi */ int vde_body_save_step(VdeHandle ctx, VdeBodyHandle* bodies, int count, const char* path); /** * @brief 将 B-Rep 实体列表导出为 IGES 文件 * * @param ctx 引擎上下文句柄 * @param bodies B-Rep 实体句柄数组(调用方管理生命周期) * @param count 实体数量 * @param path 输出文件路径 * @return 成功返回 1,失败返回 0 * * @see vde_body_load_iges * @ingroup capi */ int vde_body_save_iges(VdeHandle ctx, VdeBodyHandle* bodies, int count, const char* path); // ── B-Rep Boolean ── /** * @brief B-Rep 实体布尔运算 * * 对两个边界表示实体执行精确布尔运算(基于 Parasolid 风格的边界求交)。 * 与网格布尔运算相比,B-Rep 布尔运算结果更精确,适合工程应用。 * * @param ctx 引擎上下文句柄 * @param a 第一个 B-Rep 实体句柄 * @param b 第二个 B-Rep 实体句柄 * @param op 布尔操作类型: 0 = 并集(Union),1 = 交集(Intersection),2 = 差集(Difference,A \\ B) * @return 布尔结果的新 B-Rep 实体句柄,调用方通过 vde_body_free() 释放 * * @warning 输入实体必须是水密的(closed manifold),否则结果未定义 * * @code{.c} * VdeBodyHandle box = vde_body_create_box(ctx, 2, 2, 2); * VdeBodyHandle sphere = vde_body_create_sphere(ctx, 1.5, 32, 32); * VdeBodyHandle result = vde_body_boolean(ctx, box, sphere, 0); // 并集 * vde_body_free(box); * vde_body_free(sphere); * // ... use result ... * vde_body_free(result); * @endcode * * @see vde_mesh_boolean 网格级别布尔运算 * @ingroup capi */ VdeBodyHandle vde_body_boolean(VdeHandle ctx, VdeBodyHandle a, VdeBodyHandle b, int op); // ── Mesh face data access ── /** * @brief 获取网格面的顶点索引 * * 返回指定三角面的顶点索引列表。对于三角网格,通常返回 3 个索引。 * * @param mesh 网格句柄 * @param face_idx 面索引 [0, vde_mesh_num_faces(mesh)) * @param out_indices [out] 指向顶点索引数组的指针,由库分配,调用方必须通过 vde_free_buffer() 释放 * @return 顶点数量(三角网格通常为 3),失败返回 -1 * * @note 内存管理:成功时库在内部分配 int 数组,out_indices 指向该数组。 * 调用方使用完毕后必须调用 vde_free_buffer(out_indices) 释放。 * * @code{.c} * int* indices = NULL; * int n = vde_mesh_get_face(mesh, 0, &indices); * if (n > 0) { * printf(\"Face 0: v%d, v%d, v%d\\n\", indices[0], indices[1], indices[2]); * vde_free_buffer(indices); * } * @endcode * * @see vde_mesh_get_vertex, vde_free_buffer * @ingroup capi */ int vde_mesh_get_face(VdeMeshHandle mesh, size_t face_idx, int** out_indices); // ═══════════════════════════════════════════════════════════ // SDF 建模 // ═══════════════════════════════════════════════════════════ /** @brief SDF 节点句柄(不透明) */ #ifndef VDE_SDF_HANDLE_DEFINED typedef struct VdeSdfNode* VdeSdfHandle; #endif /** * @brief 创建 SDF 球体节点 * * 以原点为中心、指定半径的球体隐式曲面。 * * @param ctx 引擎上下文句柄 * @param radius 球体半径,> 0 * @return SDF 节点句柄,调用方通过 vde_sdf_free() 释放 * * @note 球体公式:f(x,y,z) = |(x,y,z)| - radius * * @see vde_sdf_box, vde_sdf_cylinder, vde_sdf_to_mesh * @ingroup capi */ VdeSdfHandle vde_sdf_sphere(VdeHandle ctx, double radius); /** * @brief 创建 SDF 盒子节点 * * 以原点为中心的轴对齐立方体隐式曲面。 * * @param ctx 引擎上下文句柄 * @param hx X 轴半边长,> 0 * @param hy Y 轴半边长,> 0 * @param hz Z 轴半边长,> 0 * @return SDF 节点句柄 * * @note 盒子范围为 [-hx, hx] × [-hy, hy] × [-hz, hz] * * @see vde_sdf_sphere * @ingroup capi */ VdeSdfHandle vde_sdf_box(VdeHandle ctx, double hx, double hy, double hz); /** * @brief 创建 SDF 圆柱节点 * * 沿 Y 轴、以原点为中心的圆柱体隐式曲面。 * * @param ctx 引擎上下文句柄 * @param radius 截面半径,> 0 * @param height 总高度(从 -height/2 到 +height/2) * @return SDF 节点句柄 * * @see vde_sdf_sphere, vde_sdf_box * @ingroup capi */ VdeSdfHandle vde_sdf_cylinder(VdeHandle ctx, double radius, double height); /** * @brief SDF 布尔并集 * * 返回两个 SDF 节点的并集,新节点拥有 a 和 b。 * 并集操作使两个形状合并。 * * @param ctx 引擎上下文句柄 * @param a 第一个 SDF 节点(所有权转移给结果,调用方不应单独释放) * @param b 第二个 SDF 节点(所有权转移给结果,调用方不应单独释放) * @return 并集 SDF 节点句柄 * * @warning 传入 a 和 b 后,调用方不得再单独释放它们;释放结果节点时会一并释放。 * * @see vde_sdf_intersection, vde_sdf_difference * @ingroup capi */ VdeSdfHandle vde_sdf_union(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b); /** * @brief SDF 布尔交集 * * 返回两个 SDF 节点的交集,得到共同区域。 * * @param ctx 引擎上下文句柄 * @param a 第一个 SDF 节点(所有权转移给结果) * @param b 第二个 SDF 节点(所有权转移给结果) * @return 交集 SDF 节点句柄 * * @note 所有权语义同 vde_sdf_union * * @see vde_sdf_union, vde_sdf_difference * @ingroup capi */ VdeSdfHandle vde_sdf_intersection(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b); /** * @brief SDF 布尔差集 * * 返回 A 减去 B 的差集。 * * @param ctx 引擎上下文句柄 * @param a 被减 SDF 节点(所有权转移给结果) * @param b 减去 SDF 节点(所有权转移给结果) * @return 差集 SDF 节点句柄(A \\ B) * * @note 所有权语义同 vde_sdf_union * * @see vde_sdf_union, vde_sdf_intersection * @ingroup capi */ VdeSdfHandle vde_sdf_difference(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b); /** * @brief 将 SDF 转换为三角网格 * * 通过 Marching Cubes 算法在给定分辨率下将隐式曲面离散化为三角网格。 * * @param ctx 引擎上下文句柄 * @param sdf SDF 节点句柄 * @param resolution 体素网格分辨率(如 128),越高越精细,内存开销为 O(res³) * @return 三角网格句柄,调用方通过 vde_mesh_free() 释放 * * @warning resolution 过大会导致极高内存消耗(128³ = 2M 体素,256³ = 16M 体素) * * @code{.c} * VdeSdfHandle s = vde_sdf_sphere(ctx, 1.0); * VdeMeshHandle mesh = vde_sdf_to_mesh(ctx, s, 64); // 64³ 体素 * vde_save_mesh(ctx, mesh, \"sphere.obj\", \"obj\"); * vde_mesh_free(mesh); * vde_sdf_free(s); * @endcode * * @see vde_sdf_sphere, vde_sdf_box * @ingroup capi */ VdeMeshHandle vde_sdf_to_mesh(VdeHandle ctx, VdeSdfHandle sdf, int resolution); /** * @brief 释放 SDF 节点 * * 释放一个 SDF 节点及其所有子节点。 * 如果是通过布尔操作创建的复合节点,其所有子节点同时释放。 * * @param sdf SDF 节点句柄 * * @note 将 sdf 传给布尔操作(union/intersection/difference)后, * 所有权已转移,不得再调用 vde_sdf_free 释放。 * * @see vde_sdf_union * @ingroup capi */ void vde_sdf_free(VdeSdfHandle sdf); // ═══════════════════════════════════════════════════════════ // 装配体 // ═══════════════════════════════════════════════════════════ /** @brief 装配体句柄 */ #ifndef VDE_ASSEMBLY_HANDLE_DEFINED typedef struct VdeAssembly* VdeAssemblyHandle; #endif /** * @brief 创建装配体 * * 创建一个空的装配体容器,用于组织多个零件。 * * @param ctx 引擎上下文句柄 * @param name 装配体名称(内部复制,调用方可随后释放) * @return 装配体句柄,调用方通过 vde_assembly_free() 释放 * * @note 装配体本身不拥有其包含的 body,释放装配体不会释放其中的 body。 * * @see vde_assembly_add_part, vde_assembly_free * @ingroup capi */ VdeAssemblyHandle vde_assembly_create(VdeHandle ctx, const char* name); /** * @brief 向装配体根节点添加零件 * * 将一个 B-Rep 实体以指定名称添加到装配体的根层级。 * * @param assembly 装配体句柄 * @param name 零件名称(内部复制) * @param body B-Rep 实体句柄(所有权不转移,调用方继续管理) * @return 成功返回 1,失败返回 0 * * @note body 的生命周期由调用方管理;vde_assembly_free 不会释放 body。 * * @warning 添加后调用方仍拥有 body,必须先 vde_assembly_free 再 vde_body_free * * @see vde_assembly_create, vde_assembly_part_count * @ingroup capi */ int vde_assembly_add_part(VdeAssemblyHandle assembly, const char* name, VdeBodyHandle body); /** * @brief 获取装配体零件数量 * * @param assembly 装配体句柄 * @return 零件总数 * * @see vde_assembly_add_part * @ingroup capi */ int vde_assembly_part_count(VdeAssemblyHandle assembly); /** * @brief 释放装配体 * * 释放装配体结构,但不释放其中包含的 body 句柄。 * 调用方需在释放装配体后自行释放各个 body。 * * @param assembly 装配体句柄 * * @note 不释放 body:装配体只是引用 body,不拥有其所有权。 * 释放顺序:先 vde_assembly_free(assembly),再 vde_body_free(body)。 * * @see vde_assembly_create * @ingroup capi */ void vde_assembly_free(VdeAssemblyHandle assembly); /** * @brief 释放 body 句柄数组 * * 释放 vde_body_load_step / vde_body_load_iges 返回的 VdeBodyHandle 数组 * 及其中的所有 B-Rep 实体。 * * @param bodies body 句柄数组(由 load_step/load_iges 返回) * @param count 数组中的实体数量 * * @note 此函数同时释放数组中所有 body 和数组本身。 * 调用方不需要(也不应该)对数组中每个元素单独调用 vde_body_free。 * * @code{.c} * VdeBodyHandle* bodies = NULL; * int count = vde_body_load_step(ctx, \"file.stp\", &bodies); * // ... use bodies[0..count-1] ... * vde_body_free_array(bodies, count); // 一次性释放所有 * @endcode * * @see vde_body_load_step, vde_body_load_iges * @ingroup capi */ void vde_body_free_array(VdeBodyHandle* bodies, int count); // ═══════════════════════════════════════════════════════════ // 序列化 // ═══════════════════════════════════════════════════════════ /** * @brief 将网格序列化为二进制字节流 * * 返回的缓冲区需要在消费后通过 vde_free_buffer() 释放。 * * @param ctx 引擎上下文句柄 * @param mesh 网格句柄 * @param out_data [out] 指向序列化字节数组的指针 * @return 字节数 * * @note 输出的缓冲区由库管理,调用方不得直接 free/delete。 * * @code{.c} * uint8_t* data = NULL; * size_t len = vde_serialize_mesh(ctx, mesh, &data); * // ... 使用/存储 data ... * vde_free_buffer(data); * @endcode * * @see vde_deserialize_mesh 反序列化 * @see vde_free_buffer 释放序列化缓冲区 */ size_t vde_serialize_mesh(VdeHandle ctx, VdeMeshHandle mesh, uint8_t** out_data); /** * @brief 从二进制字节流反序列化为网格 * * @param ctx 引擎上下文句柄 * @param data 序列化数据缓冲区 * @param len 数据长度(字节数) * @return 反序列化后的网格句柄 * * @see vde_serialize_mesh 序列化 */ VdeMeshHandle vde_deserialize_mesh(VdeHandle ctx, const uint8_t* data, size_t len); /** * @brief 释放由 vde_serialize_mesh 分配的缓冲区 * * @param ptr 由 vde_serialize_mesh 返回的缓冲区指针 */ void vde_free_buffer(uint8_t* ptr); #ifdef __cplusplus } #endif