star-cad

Geometric operators for computer-aided design
git clone git://git.meso-star.fr/star-cad.git
Log | Files | Refs | README | LICENSE

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:
Msrc/scad.h | 11++++++++---
Msrc/scad_geometry.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/test_api.c | 7++++---
Msrc/test_lifetime.c | 48++++++++++++++++++++++++++++++------------------
Msrc/test_periodic.c | 10++++------
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], &center_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], &center_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);