Files
ViewDesignEngine/examples/capi/basic_usage.cpp
T
茂之钳 a73c5e8954
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 32s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
fix(v1.0.1): VDE-002 submodule path + VDE-006 cycle dep + VDE-007/008/009 API fixes
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)
2026-07-27 22:29:06 +08:00

351 lines
12 KiB
C++
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.
/**
* @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;
}