a73c5e8954
VDE-002 (High): Fix submodule include path - All target_include_directories: CMAKE_SOURCE_DIR → BUILD_INTERFACE - Works as both standalone project and add_subdirectory() VDE-006 (High): Break vde_mesh ↔ vde_brep circular dependency - Move mesh-dependent code from brep to mesh module - vde_brep no longer links vde_mesh VDE-007 (Low): Add mirror() and mirror_about_plane() to transform.h VDE-008 (Low): Add convenience accessors to StlTriangle (.x()/.y()/.z()) VDE-009 (Medium): Full Doxygen docs for C API + examples/capi/basic_usage.cpp Pending: VDE-001/003/004/005/010 GCC compatibility (agent still running)
351 lines
12 KiB
C++
351 lines
12 KiB
C++
/**
|
||
* @file basic_usage.cpp
|
||
* @brief ViewDesignEngine C API 基础使用示例
|
||
*
|
||
* 演示通过纯 C 接口使用 VDE 引擎的主要功能:
|
||
* - 引擎生命周期管理
|
||
* - Mesh 加载体素 → 查询 → 保存
|
||
* - 网格简化与平滑
|
||
* - 碰撞检测(GJK + 射线-网格)
|
||
* - Bézier 曲线创建与求值
|
||
* - B-Rep 实体创建 → 布尔运算 → 转网格
|
||
* - SDF 隐式曲面 → 转网格
|
||
* - 序列化与反序列化
|
||
*
|
||
* 编译: g++ -std=c++17 -I../include basic_usage.cpp -L../build -lvde -o basic_usage
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <math.h>
|
||
|
||
/* C API 头文件(在 C++ 中以 extern "C" 方式暴露) */
|
||
#include "vde/capi/vde_capi.h"
|
||
|
||
/* ── 辅助宏 ─────────────────────────────────────────────── */
|
||
#define CHECK(cond, msg) do { \
|
||
if (!(cond)) { \
|
||
fprintf(stderr, "[FAIL] %s\n", msg); \
|
||
return 1; \
|
||
} \
|
||
} while(0)
|
||
|
||
/* ── 示例 1: 引擎生命周期 ──────────────────────────────── */
|
||
static void demo01_lifecycle(void) {
|
||
printf("=== 示例 1: 引擎生命周期 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
printf(" 引擎创建成功\n");
|
||
|
||
const char* ver = vde_version();
|
||
printf(" VDE 版本: %s\n", ver);
|
||
|
||
vde_destroy(ctx);
|
||
printf(" 引擎销毁成功\n\n");
|
||
}
|
||
|
||
/* ── 示例 2: Mesh 创建/查询/保存 ───────────────────────── */
|
||
static int demo02_mesh_io(void) {
|
||
printf("=== 示例 2: Mesh I/O ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 2.1 创建 B-Rep box → 转 mesh(模拟加载) */
|
||
VdeBodyHandle body = vde_body_create_box(ctx, 2.0, 2.0, 2.0);
|
||
CHECK(body != NULL, "vde_body_create_box 失败");
|
||
|
||
VdeMeshHandle mesh = vde_body_to_mesh(ctx, body, 0.01);
|
||
CHECK(mesh != NULL, "vde_body_to_mesh 失败");
|
||
|
||
/* 2.2 查询网格属性 */
|
||
size_t nv = vde_mesh_num_vertices(mesh);
|
||
size_t nf = vde_mesh_num_faces(mesh);
|
||
printf(" 顶点数: %zu, 三角面数: %zu\n", nv, nf);
|
||
|
||
/* 2.3 获取包围盒 */
|
||
double min_x, min_y, min_z, max_x, max_y, max_z;
|
||
vde_mesh_get_bounds(mesh, &min_x, &min_y, &min_z, &max_x, &max_y, &max_z);
|
||
printf(" 包围盒: (%.1f, %.1f, %.1f) - (%.1f, %.1f, %.1f)\n",
|
||
min_x, min_y, min_z, max_x, max_y, max_z);
|
||
|
||
/* 2.4 获取第一个顶点 */
|
||
if (nv > 0) {
|
||
double vx, vy, vz;
|
||
vde_mesh_get_vertex(mesh, 0, &vx, &vy, &vz);
|
||
printf(" 顶点 [0]: (%.3f, %.3f, %.3f)\n", vx, vy, vz);
|
||
}
|
||
|
||
/* 2.5 获取第一个面的索引 — 演示 vde_mesh_get_face + vde_free_buffer */
|
||
if (nf > 0) {
|
||
int* indices = NULL;
|
||
int n = vde_mesh_get_face(mesh, 0, &indices);
|
||
if (n > 0) {
|
||
printf(" 面 [0]: v%d v%d v%d\n", indices[0], indices[1], indices[2]);
|
||
}
|
||
vde_free_buffer((uint8_t*)indices); /* 释放库分配的索引数组 */
|
||
}
|
||
|
||
/* 2.6 保存为 OBJ */
|
||
int saved = vde_save_mesh(ctx, mesh, "/tmp/vde_capi_demo_box.obj", "obj");
|
||
printf(" 保存 OBJ: %s\n", saved ? "成功" : "失败");
|
||
|
||
vde_mesh_free(mesh);
|
||
vde_body_free(body);
|
||
vde_destroy(ctx);
|
||
printf(" Mesh I/O 演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 3: 网格简化与平滑 ────────────────────────────── */
|
||
static int demo03_mesh_process(void) {
|
||
printf("=== 示例 3: 网格处理 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 创建球体 → 网格(较多三角形,便于观察简化效果) */
|
||
VdeBodyHandle sphere = vde_body_create_sphere(ctx, 2.0, 32, 32);
|
||
VdeMeshHandle mesh = vde_body_to_mesh(ctx, sphere, 0.01);
|
||
printf(" 原始球体: %zu 顶点, %zu 面\n",
|
||
vde_mesh_num_vertices(mesh), vde_mesh_num_faces(mesh));
|
||
|
||
/* 网格简化到 50% */
|
||
VdeMeshHandle simplified = vde_mesh_simplify(ctx, mesh, 0.5);
|
||
if (simplified) {
|
||
printf(" 简化后: %zu 顶点, %zu 面 (目标 50%%)\n",
|
||
vde_mesh_num_vertices(simplified),
|
||
vde_mesh_num_faces(simplified));
|
||
vde_mesh_free(simplified);
|
||
}
|
||
|
||
/* 网格平滑 */
|
||
VdeMeshHandle smoothed = vde_mesh_smooth(ctx, mesh, 3);
|
||
if (smoothed) {
|
||
printf(" 平滑后: %zu 顶点, %zu 面 (3 次迭代)\n",
|
||
vde_mesh_num_vertices(smoothed),
|
||
vde_mesh_num_faces(smoothed));
|
||
vde_mesh_free(smoothed);
|
||
}
|
||
|
||
vde_mesh_free(mesh);
|
||
vde_body_free(sphere);
|
||
vde_destroy(ctx);
|
||
printf(" 网格处理演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 4: 碰撞检测 ──────────────────────────────────── */
|
||
static int demo04_collision(void) {
|
||
printf("=== 示例 4: 碰撞检测 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 4.1 GJK 球体碰撞 — 两球相交 */
|
||
int hit = vde_collision_gjk_spheres(ctx,
|
||
0.0, 0.0, 0.0, 1.0, /* 球 1: 原点, 半径 1 */
|
||
1.5, 0.0, 0.0, 1.0); /* 球 2: (1.5,0,0), 半径 1 → 圆心距 1.5 < 1+1=2 */
|
||
printf(" GJK 两球相交: %s (期望: 1)\n", hit ? "是" : "否");
|
||
|
||
/* 相距远的球 — 不应碰撞 */
|
||
hit = vde_collision_gjk_spheres(ctx,
|
||
0.0, 0.0, 0.0, 1.0,
|
||
5.0, 0.0, 0.0, 1.0); /* 圆心距 5 > 2 */
|
||
printf(" GJK 两球分离: %s (期望: 0)\n", hit ? "是" : "否");
|
||
|
||
/* 4.2 射线-网格碰撞 — 从 Z+ 方向射向一个立方体 */
|
||
VdeBodyHandle box = vde_body_create_box(ctx, 2.0, 2.0, 2.0);
|
||
VdeMeshHandle mesh = vde_body_to_mesh(ctx, box, 0.01);
|
||
double t, hx, hy, hz;
|
||
int ray_hit = vde_collision_ray_mesh(ctx, mesh,
|
||
0.0, 0.0, 5.0, /* 射线起点: (0,0,5) */
|
||
0.0, 0.0, -1.0, /* 方向: 沿 Z 负方向 */
|
||
&t, &hx, &hy, &hz);
|
||
if (ray_hit) {
|
||
printf(" 射线命中: t=%.3f, 交点=(%.3f, %.3f, %.3f)\n",
|
||
t, hx, hy, hz);
|
||
} else {
|
||
printf(" 射线未命中 (不应该)\n");
|
||
}
|
||
|
||
vde_mesh_free(mesh);
|
||
vde_body_free(box);
|
||
vde_destroy(ctx);
|
||
printf(" 碰撞检测演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 5: Bézier 曲线 ───────────────────────────────── */
|
||
static int demo05_curve(void) {
|
||
printf("=== 示例 5: Bézier 曲线 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 创建 3 阶 (4 控制点) Bézier 曲线 */
|
||
double cp[] = {
|
||
0.0, 0.0, 0.0, /* P0 */
|
||
1.0, 2.0, 0.0, /* P1 */
|
||
2.0, 2.0, 0.0, /* P2 */
|
||
3.0, 0.0, 0.0 /* P3 */
|
||
};
|
||
VdeCurveHandle curve = vde_curve_create_bezier(ctx, cp, 4, 3);
|
||
CHECK(curve != NULL, "vde_curve_create_bezier 失败");
|
||
|
||
printf(" 曲线次数: %d\n", vde_curve_degree(curve));
|
||
|
||
/* 在参数 t = 0.0, 0.5, 1.0 处求值 */
|
||
for (int i = 0; i <= 2; i++) {
|
||
double t = i * 0.5;
|
||
double px, py, pz;
|
||
vde_curve_evaluate(curve, t, &px, &py, &pz);
|
||
printf(" t=%.1f → (%.3f, %.3f, %.3f)\n", t, px, py, pz);
|
||
}
|
||
|
||
vde_curve_free(curve);
|
||
vde_destroy(ctx);
|
||
printf(" 曲线演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 6: B-Rep 实体与布尔运算 ─────────────────────── */
|
||
static int demo06_brep_boolean(void) {
|
||
printf("=== 示例 6: B-Rep 布尔运算 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 创建立方体和球体 */
|
||
VdeBodyHandle box = vde_body_create_box(ctx, 2.0, 2.0, 2.0);
|
||
VdeBodyHandle sphere = vde_body_create_sphere(ctx, 1.2, 32, 32);
|
||
|
||
/* 并集: box ∪ sphere */
|
||
VdeBodyHandle union_body = vde_body_boolean(ctx, box, sphere, 0);
|
||
CHECK(union_body != NULL, "B-Rep 并集失败");
|
||
VdeMeshHandle union_mesh = vde_body_to_mesh(ctx, union_body, 0.01);
|
||
printf(" 并集: %zu 顶点, %zu 面\n",
|
||
vde_mesh_num_vertices(union_mesh),
|
||
vde_mesh_num_faces(union_mesh));
|
||
|
||
/* 深拷贝演示 */
|
||
VdeBodyHandle clone = vde_body_clone(ctx, union_body);
|
||
CHECK(clone != NULL, "vde_body_clone 失败");
|
||
printf(" 深拷贝成功\n");
|
||
|
||
vde_mesh_free(union_mesh);
|
||
vde_body_free(clone);
|
||
vde_body_free(union_body);
|
||
vde_body_free(sphere);
|
||
vde_body_free(box);
|
||
vde_destroy(ctx);
|
||
printf(" B-Rep 布尔演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 7: SDF 隐式曲面 ──────────────────────────────── */
|
||
static int demo07_sdf(void) {
|
||
printf("=== 示例 7: SDF 隐式曲面 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 创建球体和盒子 SDF 节点 */
|
||
VdeSdfHandle s1 = vde_sdf_sphere(ctx, 1.5);
|
||
VdeSdfHandle s2 = vde_sdf_box(ctx, 1.0, 1.0, 1.0);
|
||
|
||
/* SDF 差集:球体减去盒子(得到一个带方形空腔的球) */
|
||
VdeSdfHandle diff = vde_sdf_difference(ctx, s1, s2);
|
||
CHECK(diff != NULL, "SDF 差集失败");
|
||
|
||
/* 转为网格(注意:s1, s2 所有权已移交给 diff) */
|
||
VdeMeshHandle mesh = vde_sdf_to_mesh(ctx, diff, 64);
|
||
if (mesh) {
|
||
printf(" SDF → Mesh: %zu 顶点, %zu 面 (resolution=64)\n",
|
||
vde_mesh_num_vertices(mesh),
|
||
vde_mesh_num_faces(mesh));
|
||
vde_save_mesh(ctx, mesh, "/tmp/vde_capi_demo_sdf.obj", "obj");
|
||
vde_mesh_free(mesh);
|
||
}
|
||
|
||
/* 注意: s1, s2 已由 diff 拥有,只释放 diff */
|
||
vde_sdf_free(diff);
|
||
vde_destroy(ctx);
|
||
printf(" SDF 演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 8: 序列化 ────────────────────────────────────── */
|
||
static int demo08_serialize(void) {
|
||
printf("=== 示例 8: 序列化/反序列化 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 创建网格 */
|
||
VdeBodyHandle cyl = vde_body_create_cylinder(ctx, 1.0, 3.0, 24);
|
||
VdeMeshHandle mesh = vde_body_to_mesh(ctx, cyl, 0.01);
|
||
|
||
printf(" 原始网格: %zu 顶点, %zu 面\n",
|
||
vde_mesh_num_vertices(mesh),
|
||
vde_mesh_num_faces(mesh));
|
||
|
||
/* 序列化 */
|
||
uint8_t* data = NULL;
|
||
size_t len = vde_serialize_mesh(ctx, mesh, &data);
|
||
printf(" 序列化数据: %zu 字节\n", len);
|
||
|
||
/* 反序列化 */
|
||
VdeMeshHandle mesh2 = vde_deserialize_mesh(ctx, data, len);
|
||
if (mesh2) {
|
||
printf(" 反序列化网格: %zu 顶点, %zu 面\n",
|
||
vde_mesh_num_vertices(mesh2),
|
||
vde_mesh_num_faces(mesh2));
|
||
vde_mesh_free(mesh2);
|
||
}
|
||
|
||
/* 释放序列化缓冲区 */
|
||
vde_free_buffer(data);
|
||
|
||
vde_mesh_free(mesh);
|
||
vde_body_free(cyl);
|
||
vde_destroy(ctx);
|
||
printf(" 序列化演示完成\n\n");
|
||
return 0;
|
||
}
|
||
|
||
/* ── 示例 9: 错误处理 ──────────────────────────────────── */
|
||
static void demo09_error_handling(void) {
|
||
printf("=== 示例 9: 错误处理 ===\n");
|
||
|
||
VdeHandle ctx = vde_create();
|
||
|
||
/* 尝试加载不存在的文件 */
|
||
VdeMeshHandle bad = vde_load_mesh(ctx, "/nonexistent_file.obj");
|
||
if (!bad) {
|
||
printf(" 加载失败 (预期): %s\n", vde_last_error(ctx));
|
||
}
|
||
|
||
vde_destroy(ctx);
|
||
printf(" 错误处理演示完成\n\n");
|
||
}
|
||
|
||
/* ── main ───────────────────────────────────────────────── */
|
||
int main(void) {
|
||
printf("╔══════════════════════════════════════════╗\n");
|
||
printf("║ ViewDesignEngine C API 基础使用示例 ║\n");
|
||
printf("╚══════════════════════════════════════════╝\n\n");
|
||
|
||
demo01_lifecycle();
|
||
|
||
int ret = 0;
|
||
ret |= demo02_mesh_io();
|
||
ret |= demo03_mesh_process();
|
||
ret |= demo04_collision();
|
||
ret |= demo05_curve();
|
||
ret |= demo06_brep_boolean();
|
||
ret |= demo07_sdf();
|
||
ret |= demo08_serialize();
|
||
demo09_error_handling();
|
||
|
||
if (ret == 0) {
|
||
printf("所有演示通过 ✓\n");
|
||
} else {
|
||
printf("部分演示失败 ✗\n");
|
||
}
|
||
return ret;
|
||
}
|