commit a6d569e070e7c004b9d0b3ff48fe3e97788d8f1b
parent 9ca9cad1b7848ba0dccdc4157a3fe31a430a3ed9
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 10 Jun 2025 17:03:58 +0200
Change API of get_boundary
Used to return all the boundary entities, collected into a single
geometry. This was usually followed by a call to scad_geometry_explode
to get access to the individual entities.
Now return as many geometries as there are boundary entities. If the
collected geometry is needed, one can use scad_geometries_collect.
Diffstat:
5 files changed, 95 insertions(+), 53 deletions(-)
diff --git a/src/scad.h b/src/scad.h
@@ -418,13 +418,18 @@ scad_geometries_partition
const int flags,
struct scad_geometry** out_geometries);
-/* Get the boundary of the geometries in `geometries'. */
+/* Get the boundary of the geometries in `geometries', considered as a whole.
+ * If `prefix_name' is not NULL, the output geometries are named
+ * <prefix_name>_<rank>, <rank> counting from 0. Otherwise they remain unnamed.
+ * The result `out_boundaries' being allocated using the allocator provided when
+ * initializing star-cad, it should be freed accordingly. */
SCAD_API res_T
scad_geometries_boundary
- (const char* name, /* Can be NULL */
+ (const char* prefix_name, /* Can be NULL */
struct scad_geometry** geometries,
const size_t geometries_count,
- struct scad_geometry** out_boundary);
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count);
/* copy the geometry `geom'. */
SCAD_API res_T
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -2466,26 +2466,27 @@ error:
res_T
scad_geometries_boundary
- (const char* name,
+ (const char* prefix_name,
struct scad_geometry** geometries,
const size_t geometries_count,
- struct scad_geometry** out_geometry)
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count)
{
res_T res = RES_OK;
int* tagout = NULL;
size_t tagoutn, sz;
int* data = NULL;
int ierr = 0;
- struct scad_geometry* geom = NULL;
+ struct scad_geometry** out_geom = NULL;
struct mem_allocator* allocator = NULL;
struct scad_device* dev = get_device();
int log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
enum log_type log_type = dev->log_type;
- size_t i;
- struct str msg;
- int init = 0;
+ size_t i, c = 0, n;
+ struct str msg, name;
+ int msg_initialized = 0, name_initialized = 0;
- if(!geometries || !out_geometry) {
+ if(!geometries || !out_boundaries || !out_count) {
res = RES_BAD_ARG;
goto error;
}
@@ -2497,20 +2498,22 @@ scad_geometries_boundary
gmshModelGetBoundary(data, sz, &tagout, &tagoutn, 1, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
- geom->gmsh_dimTags_n = tagoutn;
- geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * 2 * sizeof(*tagout));
- if(!geom->gmsh_dimTags) {
+ ASSERT(tagoutn % 2 == 0);
+ c = tagoutn / 2;
+ out_geom = MEM_CALLOC(allocator, c, sizeof(*out_geom));
+ if(!out_geom) {
res = RES_MEM_ERR;
goto error;
}
- memcpy(geom->gmsh_dimTags, tagout, tagoutn * sizeof(*tagout));
- ERR(device_register_tags(geom));
+ if(prefix_name) {
+ str_init(allocator, &name);
+ name_initialized = 1;
+ }
if(log) {
str_init(allocator, &msg);
- init = 1;
+ msg_initialized = 1;
logger_print(dev->logger, log_type, "Boundary specific tag management:\n");
ERR(str_printf(&msg, " tags ["));
for(i = 0; i < tagoutn; i += 2) {
@@ -2526,34 +2529,57 @@ scad_geometries_boundary
}
logger_print(dev->logger, log_type, "%s].\n", str_cget(&msg));
}
- for(i = 0; i < tagoutn; i += 2) {
+
+ for(i = 0, n = 0; i < tagoutn; i += 2, n++) {
int dim = tagout[i];
int tag = tagout[i+1];
- struct tag_desc* desc = device_get_description(dim, tag);
+ struct tag_desc* desc = NULL;
ASSERT(dim == 2);
- if(!desc) {
- res = RES_BAD_OP;
+ if(prefix_name) {
+ ERR(str_set(&name, prefix_name));
+ ERR(str_append_printf(&name,"_%lu", (unsigned long)i));
+ ERR(geometry_create(str_cget(&name), out_geom+n));
+ } else {
+ ERR(geometry_create(NULL, out_geom+n));
+ }
+ out_geom[n]->gmsh_dimTags_n = 2;
+ out_geom[n]->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*tagout));
+ if(!out_geom[n]->gmsh_dimTags) {
+ res = RES_MEM_ERR;
goto error;
}
+ out_geom[n]->gmsh_dimTags[0] = dim;
+ out_geom[n]->gmsh_dimTags[1] = tag;
+
+ ERR(device_register_tags(out_geom[n]));
+
/* Need to protect out_geometry's tags by getting a ref on input tags or
* deleting input geometry will possibly delete them */
ERR(device_register_ref_to_tags(dim, tag, data, sz));
/* As the 2D tags will be deleted when the 3D tag they are part of are
* deleted, they shouldn't be deleted when the geometry they belongs to are
* released. */
+ desc = device_get_description(dim, tag);
+ ASSERT(desc);
desc->delete_policy = Scad_do_not_delete;
}
exit:
- if(init) str_release(&msg);
+ if(msg_initialized) str_release(&msg);
+ if(name_initialized) str_release(&name);
if(allocator) MEM_RM(allocator, data);
- if(out_geometry) *out_geometry = geom;
+ if(out_boundaries) *out_boundaries = out_geom;
+ if(out_count) *out_count = c;
gmshFree(tagout);
return res;
error:
- if(geom) {
- SCAD(geometry_ref_put(geom));
- geom = NULL;
+ if(out_geom) {
+ for(i = 0; i < c; i++) {
+ if(out_geom[i]) SCAD(geometry_ref_put(out_geom[i]));
+ }
+ MEM_RM(allocator, out_geom);
+ out_geom = NULL;
+ c = 0;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
goto exit;
diff --git a/src/test_api.c b/src/test_api.c
@@ -200,9 +200,10 @@ main(int argc, char* argv[])
OK(scad_geometry_ref_put(out_geoms[0]));
OK(scad_geometry_ref_put(out_geoms[1]));
- BAD(scad_geometries_boundary(NULL, NULL, 0, &geom));
- BAD(scad_geometries_boundary(NULL, &geom1, 1, NULL));
- OK(scad_geometries_boundary(NULL, &geom1, 1, &geom));
+ BAD(scad_geometries_boundary(NULL, NULL, 0, &geom_array, &c));
+ BAD(scad_geometries_boundary(NULL, &geom1, 1, NULL, &c));
+ BAD(scad_geometries_boundary(NULL, NULL, 0, &geom_array, NULL));
+ OK(scad_geometries_boundary(NULL, &geom1, 1, &geom_array, &c));
OK(scad_geometry_ref_put(geom));
BAD(scad_geometry_copy(NULL, NULL, &geom));
diff --git a/src/test_lifetime.c b/src/test_lifetime.c
@@ -57,13 +57,13 @@ main(int argc, char* argv[])
double diago[] = {1, 1, 1}, diago_[] = {.5, .5, -1}, base[] = {1, 1, 0};
double dir1[3] = {0, 0, 1};
struct scad_geometry* geom1 = NULL;
- struct scad_geometry* geom2 = NULL;
struct scad_geometry* geom = NULL;
struct scad_geometry* geoms[2];
struct scad_geometry* out_geoms[2];
struct mem_allocator allocator;
struct scad_geometry** list = NULL;
- size_t list_n, center_n, i;
+ struct scad_geometry** list2 = NULL;
+ size_t list_n, list_n2, center_n, i;
double center[3], N[3];
struct scad_options options = SCAD_DEFAULT_OPTIONS;
@@ -77,17 +77,23 @@ main(int argc, char* argv[])
/* Check that 2D constituants of a deleted 3D object are alive and well */
OK(scad_add_box("box", p1, diago, &geom));
- OK(scad_geometries_boundary("boundary", &geom, 1, &geom1));
+ OK(scad_geometries_boundary("boundary", &geom, 1, &list, &list_n));
OK(scad_geometry_ref_put(geom));
- alive_and_well(geom1, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ MEM_RM(&allocator, list); list = NULL;
/* Check that a 3D derivative of a deleted 2D object is alive and well */
OK(scad_add_rectangle("rect", p1, base, &geom));
OK(scad_geometry_extrude(geom, "cube", dir1, &geom1));
OK(scad_geometry_ref_put(geom));
- OK(scad_geometries_boundary("boundary", &geom1, 1, &geom2));
+ OK(scad_geometries_boundary("boundary", &geom1, 1, &list, &list_n));
OK(scad_geometry_ref_put(geom1));
- alive_and_well(geom2, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ MEM_RM(&allocator, list); list = NULL;
/* Check that a 2D part of a deleted 3D object is alive and well */
OK(scad_add_rectangle("rect2", p1, base, &geom));
@@ -96,33 +102,39 @@ main(int argc, char* argv[])
alive_and_well(geom, &allocator);
OK(scad_add_box("cavity", p1, diago, &geom1));
- OK(scad_geometries_boundary("bcavity", &geom1, 1, &geom2));
- OK(scad_geometry_explode(geom2, "explode", &list, &list_n));
- OK(scad_geometry_ref_put(geom2));
- OK(scad_geometry_get_count(list[0], ¢er_n));
- ASSERT(center_n == 1);
- OK(scad_geometry_get_centerofmass(list[0], center));
- OK(scad_geometry_normal(list[0], center, N, "surface", &geom));
+ OK(scad_geometries_boundary("bcavity", &geom1, 1, &list, &list_n));
+ for(i = 0; i < list_n; i++) {
+ OK(scad_geometry_get_count(list[i], ¢er_n));
+ ASSERT(center_n == 1);
+ OK(scad_geometry_get_centerofmass(list[i], center));
+ OK(scad_geometry_normal(list[i], center, N, NULL, &geom));
+ }
OK(scad_geometry_ref_put(geom));
for(i = 0; i < list_n; i++) {
OK(scad_geometry_ref_put(list[i]));
}
- MEM_RM(&allocator, list);
+ MEM_RM(&allocator, list); list = NULL;
OK(scad_geometry_ref_put(geom1));
/* Check that 2D constituants of a deleted 3D object are alive and well after
* a partition */
OK(scad_add_box("box1", p1, diago, geoms+0));
OK(scad_add_box("box2", p1, diago_, geoms+1));
- OK(scad_geometries_boundary(NULL, geoms+0, 1, &geom1));
- OK(scad_geometries_boundary(NULL, geoms+1, 1, &geom2));
+ OK(scad_geometries_boundary(NULL, geoms+0, 1, &list, &list_n));
+ OK(scad_geometries_boundary(NULL, geoms+1, 1, &list2, &list_n2));
OK(scad_geometries_partition(geoms, 2, 0, out_geoms));
OK(scad_geometry_ref_put(geoms[0]));
OK(scad_geometry_ref_put(geoms[1]));
- alive_and_well(geom1, &allocator);
- alive_and_well(geom2, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ for(i = 0; i < list_n2; i++) {
+ alive_and_well(list2[i], &allocator);
+ }
OK(scad_geometry_ref_put(out_geoms[0]));
OK(scad_geometry_ref_put(out_geoms[1]));
+ MEM_RM(&allocator, list); list = NULL;
+ MEM_RM(&allocator, list2); list = NULL;
OK(scad_finalize());
diff --git a/src/test_periodic.c b/src/test_periodic.c
@@ -29,9 +29,9 @@ int
main(int argc, char* argv[])
{
struct mem_allocator allocator;
- struct scad_geometry *cyl1 = NULL, *cyl2 = NULL, *cyl = NULL;
- struct scad_geometry *bound = NULL, **faces = NULL;
- struct scad_geometry * internal = NULL, *external = NULL, *lat[2] = { NULL, NULL};
+ struct scad_geometry *cyl1 = NULL, *cyl2 = NULL, *cyl = NULL;
+ struct scad_geometry** faces = NULL;
+ struct scad_geometry *internal = NULL, *external = NULL, *lat[2] = { NULL, NULL};
double p1[3] = { 0,0,0 }, p2[3], d2[3] = { L,0,0};
double r1 = 1, r2 = r1 * XR, len;
double cyl_affine[16] = { 1, 0, 0, 0, 0, XR, 0, 0, 0, 0, XR, 0, 0, 0, 0, 1 };
@@ -48,9 +48,7 @@ main(int argc, char* argv[])
OK(scad_geometries_cut("cylinder", &cyl2, 1, &cyl1, 1, &cyl));
OK(scad_geometry_ref_put(cyl1));
OK(scad_geometry_ref_put(cyl2));
- OK(scad_geometries_boundary(NULL, &cyl, 1, &bound));
- OK(scad_geometry_explode(bound, NULL, &faces, &facesn));
- OK(scad_geometry_ref_put(bound));
+ OK(scad_geometries_boundary(NULL, &cyl, 1, &faces, &facesn));
ASSERT(facesn == 4);
d3_add(p2, p1, d2);
len = d3_len(d2);