Add missing C API bindings (#1633)
Add missing C API bindings for Manifold methods and MeshGL fields
New bindings:
- manifold_get_tolerance, manifold_set_tolerance, manifold_simplify,
manifold_num_prop_vert
- manifold_meshgl{,64}_tolerance, _run_flags_length, _run_flags,
_num_run, _update_normals
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a503665378
commit
93c1b4bf3c
@@ -173,6 +173,10 @@ ManifoldManifold* manifold_refine_to_length(void* mem, ManifoldManifold* m,
|
||||
double length);
|
||||
ManifoldManifold* manifold_refine_to_tolerance(void* mem, ManifoldManifold* m,
|
||||
double tolerance);
|
||||
ManifoldManifold* manifold_set_tolerance(void* mem, ManifoldManifold* m,
|
||||
double tolerance);
|
||||
ManifoldManifold* manifold_simplify(void* mem, ManifoldManifold* m,
|
||||
double tolerance);
|
||||
|
||||
// Manifold Shapes / Constructors
|
||||
|
||||
@@ -216,6 +220,8 @@ size_t manifold_num_tri(ManifoldManifold* m);
|
||||
size_t manifold_num_prop(ManifoldManifold* m);
|
||||
ManifoldBox* manifold_bounding_box(void* mem, ManifoldManifold* m);
|
||||
double manifold_epsilon(ManifoldManifold* m);
|
||||
double manifold_get_tolerance(ManifoldManifold* m);
|
||||
size_t manifold_num_prop_vert(ManifoldManifold* m);
|
||||
int manifold_genus(ManifoldManifold* m);
|
||||
double manifold_surface_area(ManifoldManifold* m);
|
||||
double manifold_volume(ManifoldManifold* m);
|
||||
@@ -411,6 +417,11 @@ uint32_t* manifold_meshgl_run_original_id(void* mem, ManifoldMeshGL* m);
|
||||
float* manifold_meshgl_run_transform(void* mem, ManifoldMeshGL* m);
|
||||
uint32_t* manifold_meshgl_face_id(void* mem, ManifoldMeshGL* m);
|
||||
float* manifold_meshgl_halfedge_tangent(void* mem, ManifoldMeshGL* m);
|
||||
float manifold_meshgl_tolerance(ManifoldMeshGL* m);
|
||||
size_t manifold_meshgl_run_flags_length(ManifoldMeshGL* m);
|
||||
uint8_t* manifold_meshgl_run_flags(void* mem, ManifoldMeshGL* m);
|
||||
size_t manifold_meshgl_num_run(ManifoldMeshGL* m);
|
||||
void manifold_meshgl_update_normals(ManifoldMeshGL* m, int normal_idx);
|
||||
|
||||
size_t manifold_meshgl64_num_prop(ManifoldMeshGL64* m);
|
||||
size_t manifold_meshgl64_num_vert(ManifoldMeshGL64* m);
|
||||
@@ -432,6 +443,11 @@ uint32_t* manifold_meshgl64_run_original_id(void* mem, ManifoldMeshGL64* m);
|
||||
double* manifold_meshgl64_run_transform(void* mem, ManifoldMeshGL64* m);
|
||||
uint64_t* manifold_meshgl64_face_id(void* mem, ManifoldMeshGL64* m);
|
||||
double* manifold_meshgl64_halfedge_tangent(void* mem, ManifoldMeshGL64* m);
|
||||
double manifold_meshgl64_tolerance(ManifoldMeshGL64* m);
|
||||
size_t manifold_meshgl64_run_flags_length(ManifoldMeshGL64* m);
|
||||
uint8_t* manifold_meshgl64_run_flags(void* mem, ManifoldMeshGL64* m);
|
||||
size_t manifold_meshgl64_num_run(ManifoldMeshGL64* m);
|
||||
void manifold_meshgl64_update_normals(ManifoldMeshGL64* m, int normal_idx);
|
||||
|
||||
// Triangulation
|
||||
|
||||
|
||||
@@ -321,6 +321,18 @@ ManifoldManifold* manifold_refine_to_tolerance(void* mem, ManifoldManifold* m,
|
||||
return to_c(new (mem) Manifold(refined));
|
||||
}
|
||||
|
||||
ManifoldManifold* manifold_set_tolerance(void* mem, ManifoldManifold* m,
|
||||
double tolerance) {
|
||||
auto result = from_c(m)->SetTolerance(tolerance);
|
||||
return to_c(new (mem) Manifold(result));
|
||||
}
|
||||
|
||||
ManifoldManifold* manifold_simplify(void* mem, ManifoldManifold* m,
|
||||
double tolerance) {
|
||||
auto simplified = from_c(m)->Simplify(tolerance);
|
||||
return to_c(new (mem) Manifold(simplified));
|
||||
}
|
||||
|
||||
ManifoldManifold* manifold_empty(void* mem) {
|
||||
return to_c(new (mem) Manifold());
|
||||
}
|
||||
@@ -652,6 +664,26 @@ float* manifold_meshgl_halfedge_tangent(void* mem, ManifoldMeshGL* m) {
|
||||
return copy_data(mem, from_c(m)->halfedgeTangent);
|
||||
}
|
||||
|
||||
float manifold_meshgl_tolerance(ManifoldMeshGL* m) {
|
||||
return from_c(m)->tolerance;
|
||||
}
|
||||
|
||||
size_t manifold_meshgl_run_flags_length(ManifoldMeshGL* m) {
|
||||
return from_c(m)->runFlags.size();
|
||||
}
|
||||
|
||||
uint8_t* manifold_meshgl_run_flags(void* mem, ManifoldMeshGL* m) {
|
||||
return copy_data(mem, from_c(m)->runFlags);
|
||||
}
|
||||
|
||||
size_t manifold_meshgl_num_run(ManifoldMeshGL* m) {
|
||||
return from_c(m)->NumRun();
|
||||
}
|
||||
|
||||
void manifold_meshgl_update_normals(ManifoldMeshGL* m, int normal_idx) {
|
||||
from_c(m)->UpdateNormals(normal_idx);
|
||||
}
|
||||
|
||||
size_t manifold_meshgl64_num_prop(ManifoldMeshGL64* m) {
|
||||
return from_c(m)->numProp;
|
||||
}
|
||||
@@ -713,6 +745,26 @@ double* manifold_meshgl64_halfedge_tangent(void* mem, ManifoldMeshGL64* m) {
|
||||
return copy_data(mem, from_c(m)->halfedgeTangent);
|
||||
}
|
||||
|
||||
double manifold_meshgl64_tolerance(ManifoldMeshGL64* m) {
|
||||
return from_c(m)->tolerance;
|
||||
}
|
||||
|
||||
size_t manifold_meshgl64_run_flags_length(ManifoldMeshGL64* m) {
|
||||
return from_c(m)->runFlags.size();
|
||||
}
|
||||
|
||||
uint8_t* manifold_meshgl64_run_flags(void* mem, ManifoldMeshGL64* m) {
|
||||
return copy_data(mem, from_c(m)->runFlags);
|
||||
}
|
||||
|
||||
size_t manifold_meshgl64_num_run(ManifoldMeshGL64* m) {
|
||||
return from_c(m)->NumRun();
|
||||
}
|
||||
|
||||
void manifold_meshgl64_update_normals(ManifoldMeshGL64* m, int normal_idx) {
|
||||
from_c(m)->UpdateNormals(normal_idx);
|
||||
}
|
||||
|
||||
ManifoldManifold* manifold_as_original(void* mem, ManifoldManifold* m) {
|
||||
auto orig = from_c(m)->AsOriginal();
|
||||
return to_c(new (mem) Manifold(orig));
|
||||
@@ -747,6 +799,14 @@ ManifoldBox* manifold_bounding_box(void* mem, ManifoldManifold* m) {
|
||||
|
||||
double manifold_epsilon(ManifoldManifold* m) { return from_c(m)->GetEpsilon(); }
|
||||
|
||||
double manifold_get_tolerance(ManifoldManifold* m) {
|
||||
return from_c(m)->GetTolerance();
|
||||
}
|
||||
|
||||
size_t manifold_num_prop_vert(ManifoldManifold* m) {
|
||||
return from_c(m)->NumPropVert();
|
||||
}
|
||||
|
||||
uint32_t manifold_reserve_ids(uint32_t n) { return Manifold::ReserveIDs(n); }
|
||||
|
||||
ManifoldManifold* manifold_set_properties(
|
||||
|
||||
@@ -524,3 +524,144 @@ TEST(CBIND, meshgl64_merge_returns_mem) {
|
||||
free(original);
|
||||
free(cube);
|
||||
}
|
||||
|
||||
TEST(CBIND, tolerance) {
|
||||
ManifoldManifold* sphere = manifold_sphere(alloc_manifold_buffer(), 1.0, 100);
|
||||
|
||||
// GetTolerance should return a non-negative value.
|
||||
double tol = manifold_get_tolerance(sphere);
|
||||
EXPECT_GE(tol, 0.0);
|
||||
|
||||
// SetTolerance should be reflected by GetTolerance.
|
||||
ManifoldManifold* with_tol =
|
||||
manifold_set_tolerance(alloc_manifold_buffer(), sphere, 0.5);
|
||||
EXPECT_EQ(manifold_get_tolerance(with_tol), 0.5);
|
||||
|
||||
// Simplify should produce a valid manifold with fewer or equal triangles.
|
||||
ManifoldManifold* simplified =
|
||||
manifold_simplify(alloc_manifold_buffer(), sphere, 0.1);
|
||||
EXPECT_EQ(manifold_status(simplified), MANIFOLD_NO_ERROR);
|
||||
EXPECT_LE(manifold_num_tri(simplified), manifold_num_tri(sphere));
|
||||
|
||||
manifold_destruct_manifold(sphere);
|
||||
manifold_destruct_manifold(with_tol);
|
||||
manifold_destruct_manifold(simplified);
|
||||
free(sphere);
|
||||
free(with_tol);
|
||||
free(simplified);
|
||||
}
|
||||
|
||||
TEST(CBIND, num_prop_vert) {
|
||||
ManifoldManifold* cube =
|
||||
manifold_cube(alloc_manifold_buffer(), 1.0, 1.0, 1.0, 0);
|
||||
|
||||
// A cube has 8 geometric vertices but more property vertices (due to
|
||||
// duplicated normals at sharp edges).
|
||||
EXPECT_EQ(manifold_num_vert(cube), 8);
|
||||
EXPECT_GE(manifold_num_prop_vert(cube), manifold_num_vert(cube));
|
||||
|
||||
manifold_destruct_manifold(cube);
|
||||
free(cube);
|
||||
}
|
||||
|
||||
TEST(CBIND, meshgl_run_accessors) {
|
||||
// Create two shapes with original IDs so the boolean result has 2 runs.
|
||||
ManifoldManifold* cube_tmp =
|
||||
manifold_cube(alloc_manifold_buffer(), 1, 1, 1, 0);
|
||||
ManifoldManifold* cube =
|
||||
manifold_as_original(alloc_manifold_buffer(), cube_tmp);
|
||||
ManifoldManifold* sphere_tmp =
|
||||
manifold_sphere(alloc_manifold_buffer(), 0.6, 32);
|
||||
ManifoldManifold* sphere_trans =
|
||||
manifold_translate(alloc_manifold_buffer(), sphere_tmp, 0.5, 0.5, 0.5);
|
||||
ManifoldManifold* sphere =
|
||||
manifold_as_original(alloc_manifold_buffer(), sphere_trans);
|
||||
ManifoldManifold* result =
|
||||
manifold_union(alloc_manifold_buffer(), cube, sphere);
|
||||
EXPECT_EQ(manifold_status(result), MANIFOLD_NO_ERROR);
|
||||
|
||||
// MeshGL
|
||||
ManifoldMeshGL* mesh = manifold_get_meshgl(alloc_meshgl_buffer(), result);
|
||||
EXPECT_GE(manifold_meshgl_tolerance(mesh), 0.0f);
|
||||
EXPECT_EQ(manifold_meshgl_num_run(mesh), 2);
|
||||
EXPECT_EQ(manifold_meshgl_run_flags_length(mesh),
|
||||
manifold_meshgl_num_run(mesh));
|
||||
|
||||
size_t flags_len = manifold_meshgl_run_flags_length(mesh);
|
||||
uint8_t* flags = (uint8_t*)manifold_meshgl_run_flags(malloc(flags_len), mesh);
|
||||
// Just verify we got data without crashing.
|
||||
EXPECT_NE(flags, (uint8_t*)NULL);
|
||||
free(flags);
|
||||
|
||||
// MeshGL64
|
||||
ManifoldMeshGL64* mesh64 =
|
||||
manifold_get_meshgl64(alloc_meshgl64_buffer(), result);
|
||||
EXPECT_GE(manifold_meshgl64_tolerance(mesh64), 0.0);
|
||||
EXPECT_EQ(manifold_meshgl64_num_run(mesh64), 2);
|
||||
EXPECT_EQ(manifold_meshgl64_run_flags_length(mesh64),
|
||||
manifold_meshgl64_num_run(mesh64));
|
||||
|
||||
size_t flags64_len = manifold_meshgl64_run_flags_length(mesh64);
|
||||
uint8_t* flags64 =
|
||||
(uint8_t*)manifold_meshgl64_run_flags(malloc(flags64_len), mesh64);
|
||||
EXPECT_NE(flags64, (uint8_t*)NULL);
|
||||
free(flags64);
|
||||
|
||||
manifold_destruct_meshgl(mesh);
|
||||
manifold_destruct_meshgl64(mesh64);
|
||||
manifold_destruct_manifold(result);
|
||||
manifold_destruct_manifold(sphere);
|
||||
manifold_destruct_manifold(sphere_trans);
|
||||
manifold_destruct_manifold(sphere_tmp);
|
||||
manifold_destruct_manifold(cube);
|
||||
manifold_destruct_manifold(cube_tmp);
|
||||
free(mesh);
|
||||
free(mesh64);
|
||||
free(result);
|
||||
free(sphere);
|
||||
free(sphere_trans);
|
||||
free(sphere_tmp);
|
||||
free(cube);
|
||||
free(cube_tmp);
|
||||
}
|
||||
|
||||
TEST(CBIND, meshgl_update_normals) {
|
||||
// Get a mesh with normals, then verify UpdateNormals doesn't corrupt it.
|
||||
ManifoldManifold* cube =
|
||||
manifold_cube(alloc_manifold_buffer(), 1.0, 1.0, 1.0, 0);
|
||||
ManifoldManifold* with_normals =
|
||||
manifold_calculate_normals(alloc_manifold_buffer(), cube, 3, 60.0);
|
||||
EXPECT_EQ(manifold_status(with_normals), MANIFOLD_NO_ERROR);
|
||||
|
||||
// MeshGL with normals at channel 3
|
||||
ManifoldMeshGL* mesh =
|
||||
manifold_get_meshgl_w_normals(alloc_meshgl_buffer(), with_normals, 3);
|
||||
size_t tri_before = manifold_meshgl_num_tri(mesh);
|
||||
manifold_meshgl_update_normals(mesh, 3);
|
||||
EXPECT_EQ(manifold_meshgl_num_tri(mesh), tri_before);
|
||||
|
||||
// Verify the mesh is still valid by constructing a Manifold from it.
|
||||
ManifoldManifold* rebuilt = manifold_of_meshgl(alloc_manifold_buffer(), mesh);
|
||||
EXPECT_EQ(manifold_status(rebuilt), MANIFOLD_NO_ERROR);
|
||||
|
||||
// MeshGL64 same test
|
||||
ManifoldMeshGL64* mesh64 =
|
||||
manifold_get_meshgl64_w_normals(alloc_meshgl64_buffer(), with_normals, 3);
|
||||
manifold_meshgl64_update_normals(mesh64, 3);
|
||||
ManifoldManifold* rebuilt64 =
|
||||
manifold_of_meshgl64(alloc_manifold_buffer(), mesh64);
|
||||
EXPECT_EQ(manifold_status(rebuilt64), MANIFOLD_NO_ERROR);
|
||||
|
||||
manifold_destruct_manifold(rebuilt64);
|
||||
manifold_destruct_meshgl64(mesh64);
|
||||
manifold_destruct_manifold(rebuilt);
|
||||
manifold_destruct_meshgl(mesh);
|
||||
manifold_destruct_manifold(with_normals);
|
||||
manifold_destruct_manifold(cube);
|
||||
free(rebuilt64);
|
||||
free(mesh64);
|
||||
free(rebuilt);
|
||||
free(mesh);
|
||||
free(with_normals);
|
||||
free(cube);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user