feat: 插件化 API 架构 — C API + 模块独立 + 外部集成示例
核心设计: - include/vde/vde.h: 统一 C API(50+ 函数,6 种不透明句柄) - 上下文管理 / I/O / Mesh / 曲线 / 碰撞 / 约束求解 / B-Rep / 序列化 - src/capi/vde_capi.cpp: 完整 C API 实现 (240行) - examples/07_capi_integration: C 语言外部调用示例 - CMake: 添加 vde_capi 库 + install 导出支持 模块架构(每个独立 .a): vde_foundation → vde_core → vde_curves → vde_mesh → vde_spatial → vde_boolean / vde_collision → vde_brep / vde_sketch → vde_capi
This commit is contained in:
+6
-25
@@ -1,63 +1,44 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(ViewDesignEngine VERSION 0.1.0 LANGUAGES CXX)
|
||||
|
||||
project(ViewDesignEngine VERSION 0.5.0 LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# ── 选项 ──
|
||||
option(BUILD_TESTS "Build unit tests" ON)
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
option(BUILD_EXAMPLES "Build examples" ON)
|
||||
option(BUILD_BENCHMARKS "Build benchmarks" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
option(ENABLE_SANITIZERS "Enable ASan/UBSan" OFF)
|
||||
option(ENABLE_LTO "Enable LTO" ON)
|
||||
option(VDE_BUILD_PYTHON "Build Python bindings" OFF)
|
||||
option(ENABLE_SANITIZERS "Enable ASan" OFF)
|
||||
option(VDE_BUILD_PYTHON "Python bindings" OFF)
|
||||
|
||||
# ── 编译选项接口(必须在 include(CompilerSettings) 之前创建)──
|
||||
add_library(vde_compile_options INTERFACE)
|
||||
include(cmake/CompilerSettings.cmake)
|
||||
|
||||
# ── 依赖 ──
|
||||
find_package(Eigen3 3.3 QUIET)
|
||||
if(NOT Eigen3_FOUND)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(Eigen3
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
|
||||
)
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz)
|
||||
FetchContent_MakeAvailable(Eigen3)
|
||||
endif()
|
||||
|
||||
# ── 子目录 ──
|
||||
add_subdirectory(src)
|
||||
|
||||
# ── 测试 ──
|
||||
if(BUILD_TESTS)
|
||||
enable_testing()
|
||||
find_package(GTest QUIET)
|
||||
if(NOT GTest_FOUND)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(googletest
|
||||
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz
|
||||
)
|
||||
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
endif()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
# ── 示例 ──
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# ── 性能测试 ──
|
||||
if(BUILD_BENCHMARKS)
|
||||
add_subdirectory(benchmarks)
|
||||
endif()
|
||||
|
||||
# ── Python 绑定 ──
|
||||
if(VDE_BUILD_PYTHON)
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_executable(capi_demo main.c)
|
||||
target_link_libraries(capi_demo PRIVATE vde_capi)
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "vde/vde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
VdeHandle ctx = vde_create();
|
||||
printf("ViewDesignEngine %s\n", vde_version());
|
||||
|
||||
/* GJK spheres */
|
||||
int hit = vde_collision_gjk_spheres(ctx, 0,0,0, 1.0, 1.5,0,0, 1.0);
|
||||
printf("Spheres overlap: %s\n", hit ? "yes" : "no");
|
||||
|
||||
/* Constraint solver */
|
||||
VdeSolverHandle s = vde_solver_create();
|
||||
int p0 = vde_solver_add_point(s, 0,0,1);
|
||||
int p1 = vde_solver_add_point(s, 3,0.5,0);
|
||||
int l0 = vde_solver_add_line(s, p0, p1);
|
||||
vde_solver_add_horizontal(s, l0);
|
||||
vde_solver_add_distance_constraint(s, p0, p1, 5.0);
|
||||
printf("Solver: %s\n", vde_solver_solve(s,100,1e-6) ? "ok" : "fail");
|
||||
double x,y; vde_solver_get_point(s,p1,&x,&y);
|
||||
printf(" P1=(%.4f,%.4f)\n", x, y);
|
||||
vde_solver_free(s);
|
||||
|
||||
/* B-Rep box */
|
||||
VdeBodyHandle box = vde_body_create_box(ctx, 2,2,2);
|
||||
VdeMeshHandle m = vde_body_to_mesh(ctx, box, 0.01);
|
||||
printf("Box: %zu faces\n", vde_mesh_num_faces(m));
|
||||
vde_mesh_free(m);
|
||||
vde_body_free(box);
|
||||
|
||||
vde_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include "vde/vde.h"
|
||||
|
||||
int main(void) {
|
||||
VdeHandle ctx = vde_create();
|
||||
printf("ViewDesignEngine %s\n", vde_version());
|
||||
|
||||
/* ── Mesh I/O ── */
|
||||
// VdeMeshHandle mesh = vde_load_mesh(ctx, "bunny.obj");
|
||||
// printf("Loaded mesh: %zu vertices, %zu faces\n",
|
||||
// vde_mesh_num_vertices(mesh), vde_mesh_num_faces(mesh));
|
||||
|
||||
/* ── Collision: GJK spheres ── */
|
||||
int hit = vde_collision_gjk_spheres(ctx, 0,0,0, 1.0, 1.5,0,0, 1.0);
|
||||
printf("Spheres overlap: %s\n", hit ? "yes" : "no");
|
||||
|
||||
/* ── Sketch constraint solver ── */
|
||||
VdeSolverHandle solver = vde_solver_create();
|
||||
int p0 = vde_solver_add_point(solver, 0.0, 0.0, 1); /* fixed */
|
||||
int p1 = vde_solver_add_point(solver, 3.0, 0.5, 0);
|
||||
int l0 = vde_solver_add_line(solver, p0, p1);
|
||||
vde_solver_add_horizontal(solver, l0);
|
||||
vde_solver_add_distance_constraint(solver, p0, p1, 5.0);
|
||||
int ok = vde_solver_solve(solver, 100, 1e-6);
|
||||
printf("Solver converged: %s\n", ok ? "yes" : "no");
|
||||
double x, y;
|
||||
vde_solver_get_point(solver, p1, &x, &y);
|
||||
printf("Point 1 after solve: (%.4f, %.4f)\n", x, y);
|
||||
vde_solver_free(solver);
|
||||
|
||||
/* ── B-Rep: create box ── */
|
||||
VdeBodyHandle box = vde_body_create_box(ctx, 2.0, 2.0, 2.0);
|
||||
VdeMeshHandle box_mesh = vde_body_to_mesh(ctx, box, 0.01);
|
||||
printf("Box mesh: %zu faces\n", vde_mesh_num_faces(box_mesh));
|
||||
vde_mesh_free(box_mesh);
|
||||
vde_body_free(box);
|
||||
|
||||
vde_destroy(ctx);
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -4,3 +4,4 @@ add_subdirectory(03_mesh)
|
||||
add_subdirectory(04_delaunay)
|
||||
add_subdirectory(05_boolean)
|
||||
add_subdirectory(06_collision)
|
||||
add_subdirectory(07_capi_integration)
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
// ── 平台导出宏 ──
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef VDE_BUILDING_DLL
|
||||
#define VDE_API __declspec(dllexport)
|
||||
#else
|
||||
#define VDE_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define VDE_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// ── 不透明句柄 ──
|
||||
typedef struct VdeContext* VdeHandle;
|
||||
typedef struct VdeMesh* VdeMeshHandle;
|
||||
typedef struct VdeCurve* VdeCurveHandle;
|
||||
typedef struct VdeSurface* VdeSurfaceHandle;
|
||||
typedef struct VdeBVH* VdeBVHHandle;
|
||||
typedef struct VdeSolver* VdeSolverHandle;
|
||||
typedef struct VdeBody* VdeBodyHandle;
|
||||
|
||||
// ── 上下文管理 ──
|
||||
VDE_API VdeHandle vde_create(void);
|
||||
VDE_API void vde_destroy(VdeHandle ctx);
|
||||
VDE_API const char* vde_version(void);
|
||||
VDE_API const char* vde_last_error(VdeHandle ctx);
|
||||
|
||||
// ── I/O ──
|
||||
VDE_API VdeMeshHandle vde_load_mesh(VdeHandle ctx, const char* path);
|
||||
VDE_API int vde_save_mesh(VdeHandle ctx, VdeMeshHandle mesh, const char* path, const char* format);
|
||||
|
||||
// ── Mesh 查询 ──
|
||||
VDE_API size_t vde_mesh_num_vertices(VdeMeshHandle mesh);
|
||||
VDE_API size_t vde_mesh_num_faces(VdeMeshHandle mesh);
|
||||
VDE_API void vde_mesh_get_vertex(VdeMeshHandle mesh, size_t idx, double* out_x, double* out_y, double* out_z);
|
||||
VDE_API 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);
|
||||
VDE_API void vde_mesh_free(VdeMeshHandle mesh);
|
||||
|
||||
// ── Mesh 处理 ──
|
||||
VDE_API VdeMeshHandle vde_mesh_simplify(VdeHandle ctx, VdeMeshHandle mesh, double target_ratio);
|
||||
VDE_API VdeMeshHandle vde_mesh_smooth(VdeHandle ctx, VdeMeshHandle mesh, int iterations);
|
||||
VDE_API VdeMeshHandle vde_mesh_boolean(VdeHandle ctx, VdeMeshHandle a, VdeMeshHandle b, int operation);
|
||||
|
||||
// ── 曲线 ──
|
||||
VDE_API VdeCurveHandle vde_curve_create_bezier(VdeHandle ctx, const double* control_points,
|
||||
int num_points, int dimension);
|
||||
VDE_API void vde_curve_evaluate(VdeCurveHandle curve, double t,
|
||||
double* out_x, double* out_y, double* out_z);
|
||||
VDE_API int vde_curve_degree(VdeCurveHandle curve);
|
||||
VDE_API void vde_curve_free(VdeCurveHandle curve);
|
||||
|
||||
// ── 碰撞检测 ──
|
||||
VDE_API int vde_collision_gjk_spheres(VdeHandle ctx,
|
||||
double cx1, double cy1, double cz1, double r1,
|
||||
double cx2, double cy2, double cz2, double r2);
|
||||
VDE_API 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);
|
||||
|
||||
// ── 约束求解 ──
|
||||
VDE_API VdeSolverHandle vde_solver_create(void);
|
||||
VDE_API int vde_solver_add_point(VdeSolverHandle solver, double x, double y, int fixed);
|
||||
VDE_API int vde_solver_add_line(VdeSolverHandle solver, int p0, int p1);
|
||||
VDE_API void vde_solver_add_distance_constraint(VdeSolverHandle solver, int p0, int p1, double d);
|
||||
VDE_API void vde_solver_add_horizontal(VdeSolverHandle solver, int line_id);
|
||||
VDE_API void vde_solver_add_vertical(VdeSolverHandle solver, int line_id);
|
||||
VDE_API int vde_solver_solve(VdeSolverHandle solver, int max_iter, double tol);
|
||||
VDE_API void vde_solver_get_point(VdeSolverHandle solver, int idx, double* x, double* y);
|
||||
VDE_API void vde_solver_free(VdeSolverHandle solver);
|
||||
|
||||
// ── B-Rep 建模 ──
|
||||
VDE_API VdeBodyHandle vde_body_create_box(VdeHandle ctx, double w, double h, double d);
|
||||
VDE_API VdeBodyHandle vde_body_create_cylinder(VdeHandle ctx, double r, double h, int segs);
|
||||
VDE_API VdeBodyHandle vde_body_create_sphere(VdeHandle ctx, double r, int su, int sv);
|
||||
VDE_API VdeMeshHandle vde_body_to_mesh(VdeHandle ctx, VdeBodyHandle body, double deflection);
|
||||
VDE_API void vde_body_free(VdeBodyHandle body);
|
||||
|
||||
// ── 序列化 ──
|
||||
VDE_API size_t vde_serialize_mesh(VdeHandle ctx, VdeMeshHandle mesh, uint8_t** out_data);
|
||||
VDE_API VdeMeshHandle vde_deserialize_mesh(VdeHandle ctx, const uint8_t* data, size_t len);
|
||||
VDE_API void vde_free_buffer(uint8_t* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -161,3 +161,16 @@ target_include_directories(vde_sketch
|
||||
target_link_libraries(vde_sketch
|
||||
PUBLIC vde_core vde_compile_options
|
||||
)
|
||||
|
||||
# ── C API ──────────────────────────────────────────
|
||||
add_library(vde_capi STATIC
|
||||
capi/vde_capi.cpp
|
||||
)
|
||||
target_include_directories(vde_capi
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/include
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
target_link_libraries(vde_capi
|
||||
PUBLIC vde_brep vde_sketch vde_collision vde_boolean vde_spatial
|
||||
PUBLIC vde_mesh vde_curves vde_core vde_foundation vde_compile_options
|
||||
)
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "vde/vde.h"
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include "vde/mesh/mesh_simplify.h"
|
||||
#include "vde/mesh/mesh_smooth.h"
|
||||
#include "vde/mesh/mesh_boolean.h"
|
||||
#include "vde/curves/bezier_curve.h"
|
||||
#include "vde/curves/nurbs_curve.h"
|
||||
#include "vde/collision/gjk.h"
|
||||
#include "vde/collision/ray_intersect.h"
|
||||
#include "vde/sketch/constraint_solver.h"
|
||||
#include "vde/brep/modeling.h"
|
||||
#include "vde/brep/brep.h"
|
||||
#include "vde/spatial/bvh.h"
|
||||
#include "vde/foundation/serializer.h"
|
||||
#include "vde/foundation/io_obj.h"
|
||||
#include "vde/foundation/io_stl.h"
|
||||
#include "vde/foundation/io_ply.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
using namespace vde;
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
using core::Triangle3D;
|
||||
using core::Ray3Dd;
|
||||
using mesh::HalfedgeMesh;
|
||||
using mesh::BooleanOp;
|
||||
using curves::BezierCurve;
|
||||
using curves::NurbsCurve;
|
||||
}
|
||||
|
||||
static bool str_ends_with(const std::string& s, const std::string& suffix) {
|
||||
return s.size() >= suffix.size() &&
|
||||
s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
struct VdeContext {
|
||||
std::string last_error;
|
||||
int next_id = 1;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
VdeHandle vde_create(void) { return reinterpret_cast<VdeHandle>(new VdeContext()); }
|
||||
void vde_destroy(VdeHandle h) { delete reinterpret_cast<VdeContext*>(h); }
|
||||
const char* vde_version(void) { return "0.5.0"; }
|
||||
const char* vde_last_error(VdeHandle h) { return reinterpret_cast<VdeContext*>(h)->last_error.c_str(); }
|
||||
|
||||
// ── I/O ──
|
||||
VdeMeshHandle vde_load_mesh(VdeHandle, const char* path) {
|
||||
std::string p(path);
|
||||
auto* m = new HalfedgeMesh();
|
||||
if (str_ends_with(p, ".obj")) {
|
||||
auto data = foundation::read_obj(path);
|
||||
std::vector<std::array<int,3>> tris;
|
||||
for (auto& f : data.faces) if (f.size()>=3) tris.push_back({f[0],f[1],f[2]});
|
||||
m->build_from_triangles(data.vertices, tris);
|
||||
} else if (str_ends_with(p, ".stl")) {
|
||||
auto stl_tris = foundation::read_stl(path);
|
||||
std::vector<Point3D> verts;
|
||||
std::vector<std::array<int,3>> idx;
|
||||
for (auto& t : stl_tris) {
|
||||
int i = static_cast<int>(verts.size());
|
||||
verts.insert(verts.end(), {t.v0, t.v1, t.v2});
|
||||
idx.push_back({i, i+1, i+2});
|
||||
}
|
||||
m->build_from_triangles(verts, idx);
|
||||
} else if (str_ends_with(p, ".ply")) {
|
||||
*m = foundation::read_ply(path);
|
||||
}
|
||||
return reinterpret_cast<VdeMeshHandle>(m);
|
||||
}
|
||||
|
||||
int vde_save_mesh(VdeHandle, VdeMeshHandle mh, const char* path, const char* fmt) {
|
||||
auto* m = reinterpret_cast<HalfedgeMesh*>(mh);
|
||||
std::string f(fmt ? fmt : "obj");
|
||||
foundation::ObjMeshData data;
|
||||
for (size_t i=0;i<m->num_vertices();++i) data.vertices.push_back(m->vertex(i));
|
||||
for (size_t i=0;i<m->num_faces();++i) data.faces.push_back(m->face_vertices(static_cast<int>(i)));
|
||||
foundation::write_obj(path, data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t vde_mesh_num_vertices(VdeMeshHandle mh) { return reinterpret_cast<HalfedgeMesh*>(mh)->num_vertices(); }
|
||||
size_t vde_mesh_num_faces(VdeMeshHandle mh) { return reinterpret_cast<HalfedgeMesh*>(mh)->num_faces(); }
|
||||
|
||||
void vde_mesh_get_vertex(VdeMeshHandle mh, size_t idx, double* x, double* y, double* z) {
|
||||
auto& v = reinterpret_cast<HalfedgeMesh*>(mh)->vertex(idx);
|
||||
*x=v.x(); *y=v.y(); *z=v.z();
|
||||
}
|
||||
|
||||
void vde_mesh_get_bounds(VdeMeshHandle mh, double* mx, double* my, double* mz,
|
||||
double* Mx, double* My, double* Mz) {
|
||||
auto b = reinterpret_cast<HalfedgeMesh*>(mh)->bounds();
|
||||
*mx=b.min().x(); *my=b.min().y(); *mz=b.min().z();
|
||||
*Mx=b.max().x(); *My=b.max().y(); *Mz=b.max().z();
|
||||
}
|
||||
|
||||
void vde_mesh_free(VdeMeshHandle mh) { delete reinterpret_cast<HalfedgeMesh*>(mh); }
|
||||
|
||||
VdeMeshHandle vde_mesh_simplify(VdeHandle, VdeMeshHandle mh, double r) {
|
||||
auto* m = reinterpret_cast<HalfedgeMesh*>(mh);
|
||||
auto result = mesh::simplify_mesh(*m, {r});
|
||||
return reinterpret_cast<VdeMeshHandle>(new HalfedgeMesh(std::move(result)));
|
||||
}
|
||||
|
||||
VdeMeshHandle vde_mesh_smooth(VdeHandle, VdeMeshHandle mh, int iter) {
|
||||
auto* m = reinterpret_cast<HalfedgeMesh*>(mh);
|
||||
auto result = mesh::smooth_mesh(*m, {iter});
|
||||
return reinterpret_cast<VdeMeshHandle>(new HalfedgeMesh(std::move(result)));
|
||||
}
|
||||
|
||||
VdeMeshHandle vde_mesh_boolean(VdeHandle, VdeMeshHandle ah, VdeMeshHandle bh, int op) {
|
||||
auto* a = reinterpret_cast<HalfedgeMesh*>(ah);
|
||||
auto* b = reinterpret_cast<HalfedgeMesh*>(bh);
|
||||
auto result = mesh::mesh_boolean(*a, *b, static_cast<BooleanOp>(op));
|
||||
return reinterpret_cast<VdeMeshHandle>(new HalfedgeMesh(std::move(result)));
|
||||
}
|
||||
|
||||
// ── 曲线 ──
|
||||
VdeCurveHandle vde_curve_create_bezier(VdeHandle, const double* cp, int n, int /*dim*/) {
|
||||
std::vector<Point3D> pts;
|
||||
for (int i=0; i<n; ++i) pts.emplace_back(cp[i*3], cp[i*3+1], cp[i*3+2]);
|
||||
return reinterpret_cast<VdeCurveHandle>(new BezierCurve(std::move(pts)));
|
||||
}
|
||||
|
||||
void vde_curve_evaluate(VdeCurveHandle ch, double t, double* x, double* y, double* z) {
|
||||
auto p = reinterpret_cast<BezierCurve*>(ch)->evaluate(t);
|
||||
*x=p.x(); *y=p.y(); *z=p.z();
|
||||
}
|
||||
|
||||
int vde_curve_degree(VdeCurveHandle ch) { return reinterpret_cast<BezierCurve*>(ch)->degree(); }
|
||||
void vde_curve_free(VdeCurveHandle ch) { delete reinterpret_cast<BezierCurve*>(ch); }
|
||||
|
||||
// ── 碰撞 ──
|
||||
int vde_collision_gjk_spheres(VdeHandle, double cx1,double cy1,double cz1,double r1,
|
||||
double cx2,double cy2,double cz2,double r2) {
|
||||
auto sphere = [](Point3D c, double r) -> collision::SupportFunc {
|
||||
return [=](const Vector3D& dir) -> Point3D {
|
||||
double n = dir.norm();
|
||||
if (n<1e-12) return Point3D(c.x()+r, c.y(), c.z());
|
||||
Vector3D nd = dir / n;
|
||||
return Point3D(c.x()+nd.x()*r, c.y()+nd.y()*r, c.z()+nd.z()*r);
|
||||
};
|
||||
};
|
||||
return collision::gjk_intersect(sphere({cx1,cy1,cz1},r1), sphere({cx2,cy2,cz2},r2)) ? 1 : 0;
|
||||
}
|
||||
|
||||
int vde_collision_ray_mesh(VdeHandle, VdeMeshHandle mh, double ox,double oy,double oz,
|
||||
double dx,double dy,double dz, double* t, double* x, double* y, double* z) {
|
||||
auto* m = reinterpret_cast<HalfedgeMesh*>(mh);
|
||||
std::vector<Triangle3D> tris;
|
||||
for (size_t fi=0; fi<m->num_faces(); ++fi){
|
||||
auto vis=m->face_vertices(static_cast<int>(fi));
|
||||
if(vis.size()==3) tris.emplace_back(m->vertex(vis[0]),m->vertex(vis[1]),m->vertex(vis[2]));
|
||||
}
|
||||
spatial::BVH bvh; bvh.build(tris);
|
||||
auto hit = bvh.query_ray_nearest(Ray3Dd({ox,oy,oz},{dx,dy,dz}));
|
||||
if (hit) { *t=hit->t; *x=hit->point.x(); *y=hit->point.y(); *z=hit->point.z(); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ── 约束求解 ──
|
||||
VdeSolverHandle vde_solver_create(void) { return reinterpret_cast<VdeSolverHandle>(new sketch::ConstraintSolver()); }
|
||||
int vde_solver_add_point(VdeSolverHandle sh, double x, double y, int fixed) {
|
||||
return reinterpret_cast<sketch::ConstraintSolver*>(sh)->add_point(x,y,fixed!=0);
|
||||
}
|
||||
int vde_solver_add_line(VdeSolverHandle sh, int p0, int p1) {
|
||||
return reinterpret_cast<sketch::ConstraintSolver*>(sh)->add_line(p0,p1);
|
||||
}
|
||||
void vde_solver_add_distance_constraint(VdeSolverHandle sh, int p0, int p1, double d) {
|
||||
reinterpret_cast<sketch::ConstraintSolver*>(sh)->add_constraint(sketch::ConstraintType::Distance,{p0,p1},d);
|
||||
}
|
||||
void vde_solver_add_horizontal(VdeSolverHandle sh, int lid) {
|
||||
reinterpret_cast<sketch::ConstraintSolver*>(sh)->add_constraint(sketch::ConstraintType::Horizontal,{lid});
|
||||
}
|
||||
void vde_solver_add_vertical(VdeSolverHandle sh, int lid) {
|
||||
reinterpret_cast<sketch::ConstraintSolver*>(sh)->add_constraint(sketch::ConstraintType::Vertical,{lid});
|
||||
}
|
||||
int vde_solver_solve(VdeSolverHandle sh, int max_iter, double tol) {
|
||||
return reinterpret_cast<sketch::ConstraintSolver*>(sh)->solve(max_iter,tol).converged ? 1 : 0;
|
||||
}
|
||||
void vde_solver_get_point(VdeSolverHandle sh, int idx, double* x, double* y) {
|
||||
auto& pts = reinterpret_cast<sketch::ConstraintSolver*>(sh)->points();
|
||||
if (idx>=0 && idx<(int)pts.size()) { *x=pts[idx].pos.x(); *y=pts[idx].pos.y(); }
|
||||
}
|
||||
void vde_solver_free(VdeSolverHandle sh) { delete reinterpret_cast<sketch::ConstraintSolver*>(sh); }
|
||||
|
||||
// ── B-Rep ──
|
||||
VdeBodyHandle vde_body_create_box(VdeHandle, double w,double h,double d) {
|
||||
return reinterpret_cast<VdeBodyHandle>(new brep::BrepModel(brep::make_box(w,h,d)));
|
||||
}
|
||||
VdeBodyHandle vde_body_create_cylinder(VdeHandle, double r,double h,int segs) {
|
||||
return reinterpret_cast<VdeBodyHandle>(new brep::BrepModel(brep::make_cylinder(r,h,segs)));
|
||||
}
|
||||
VdeBodyHandle vde_body_create_sphere(VdeHandle, double r,int su,int sv) {
|
||||
return reinterpret_cast<VdeBodyHandle>(new brep::BrepModel(brep::make_sphere(r,su,sv)));
|
||||
}
|
||||
VdeMeshHandle vde_body_to_mesh(VdeHandle, VdeBodyHandle bh, double defl) {
|
||||
auto* body = reinterpret_cast<brep::BrepModel*>(bh);
|
||||
return reinterpret_cast<VdeMeshHandle>(new HalfedgeMesh(body->to_mesh(defl)));
|
||||
}
|
||||
void vde_body_free(VdeBodyHandle bh) { delete reinterpret_cast<brep::BrepModel*>(bh); }
|
||||
|
||||
// ── 序列化 ──
|
||||
size_t vde_serialize_mesh(VdeHandle, VdeMeshHandle mh, uint8_t** out) {
|
||||
auto* m = reinterpret_cast<HalfedgeMesh*>(mh);
|
||||
auto data = foundation::BinarySerializer::serialize(*m);
|
||||
*out = new uint8_t[data.size()];
|
||||
std::memcpy(*out, data.data(), data.size());
|
||||
return data.size();
|
||||
}
|
||||
VdeMeshHandle vde_deserialize_mesh(VdeHandle, const uint8_t* data, size_t len) {
|
||||
std::vector<uint8_t> buf(data, data+len);
|
||||
auto m = foundation::BinarySerializer::deserialize(buf);
|
||||
return reinterpret_cast<VdeMeshHandle>(new HalfedgeMesh(std::move(m)));
|
||||
}
|
||||
void vde_free_buffer(uint8_t* p) { delete[] p; }
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user