star-cad

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

commit 7782d93139d91e2f48d449dc67ac02908b10c168
parent a6d569e070e7c004b9d0b3ff48fe3e97788d8f1b
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 11 Jun 2025 12:06:39 +0200

Change API of get_common_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 | 31++++++++++++++++++++-----------
Msrc/scad_geometry.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/test_api.c | 11++++++-----
3 files changed, 80 insertions(+), 49 deletions(-)

diff --git a/src/scad.h b/src/scad.h @@ -391,17 +391,6 @@ scad_geometries_intersect const size_t tools_count, struct scad_geometry** out_geometry); -/* compute boundary intersection (the common part) of the geometries in - * `geometries' and `tools'. */ -SCAD_API res_T -scad_geometries_common_boundaries - (const char* name, /* Can be NULL */ - struct scad_geometry** geometries, - const size_t geometries_count, - struct scad_geometry** tools, - const size_t tools_count, - struct scad_geometry** out_geometry); - /* Compute the boolean fragments (general fuse) resulting from the * intersection of the geometries in `geometries', making all interfaces * conformal. @@ -418,6 +407,26 @@ scad_geometries_partition const int flags, struct scad_geometry** out_geometries); +/* compute boundary intersection (the common part) of the geometries in + * `geometries' and `tools'. + * 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. + * If there is no common boundary, `out_boundaries' is set to NULL and + * `out_count' is set to 0. + * Note that there is usually no common boundaries between geometries before + * they have been partitioned. */ +SCAD_API res_T +scad_geometries_common_boundaries + (const char* prefix_name, /* Can be NULL */ + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry*** out_boundaries, + size_t *out_count); + /* 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. diff --git a/src/scad_geometry.c b/src/scad_geometry.c @@ -1570,12 +1570,13 @@ error: res_T scad_geometries_common_boundaries - (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** tools, const size_t tools_count, - struct scad_geometry** out_geometry) + struct scad_geometry*** out_boundaries, + size_t *out_count) { res_T res = RES_OK; int* tagout = NULL; @@ -1588,16 +1589,18 @@ scad_geometries_common_boundaries int* bound1 = NULL; int* bound2 = NULL; size_t n1, n2; - 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 || !geometries_count || !tools || !tools_count || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count + || !out_boundaries || !out_count) + { res = RES_BAD_ARG; goto error; } @@ -1614,33 +1617,31 @@ scad_geometries_common_boundaries ERR(gmsh_err_to_res_T(ierr)); gmshModelGetBoundary(data2, sz2, &bound2, &n2, 1, 0, 0, &ierr); ERR(gmsh_err_to_res_T(ierr)); + /* TODO: + * Can this be computed directly on dim.tag lists? */ gmshModelOccIntersect(bound1, n1, bound2, n2, &tagout, &tagoutn, &map, &mapn, &mapnn, -1, 0/*no delete*/, 0/*no delete*/, &ierr); ERR(gmsh_err_to_res_T(ierr)); + ASSERT(tagoutn % 2 == 0); + c = tagoutn / 2; - ERR(geometry_create(name, &geom)); - geom->gmsh_dimTags_n = tagoutn; if(tagoutn == 0) { - if(name) { - log_message(dev, "Common boundary '%s' is empty.\n", name); + if(prefix_name) { + log_message(dev, "Common boundary list '%s' is empty.\n", prefix_name); } else { - log_message(dev, "Unnamed common boundary %p is empty.\n", (void*)geom); + log_message(dev, "Unnamed common boundary list is empty.\n"); } - geom->gmsh_dimTags = NULL; - } else { - geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout)); - if(!geom->gmsh_dimTags) { - res = RES_MEM_ERR; - goto error; - } - memcpy(geom->gmsh_dimTags, tagout, tagoutn * sizeof(*tagout)); + goto exit; } - 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, "Common boundaries specific tag management:\n"); ERR(str_printf(&msg, " tags [")); @@ -1662,15 +1663,27 @@ scad_geometries_common_boundaries } 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; 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; /* 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, data1, sz1)); @@ -1678,12 +1691,16 @@ scad_geometries_common_boundaries /* 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(out_geometry) *out_geometry = geom; + if(msg_initialized) str_release(&msg); + if(name_initialized) str_release(&name); + if(out_boundaries) *out_boundaries = out_geom; + if(out_count) *out_count = c; if(allocator) { MEM_RM(allocator, data1); MEM_RM(allocator, data2); @@ -1697,12 +1714,16 @@ exit: error: if(ierr) { int dim = INT_MAX; - if(!mixed_dim_err_msg(name, "common boundary", geometries, geometries_count, &dim)) - mixed_dim_err_msg(name, "common boundary", tools, tools_count, &dim); + if(!mixed_dim_err_msg(prefix_name, "common boundary", geometries, geometries_count, &dim)) + mixed_dim_err_msg(prefix_name, "common boundary", tools, tools_count, &dim); } - 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 @@ -186,11 +186,12 @@ main(int argc, char* argv[]) OK(scad_geometry_ref_put(geom)); /* BAD(scad_geometries_common_boundaries(NULL, NULL, 0, geoms, 2, &geom)); */ - BAD(scad_geometries_common_boundaries(NULL, geoms, 2, NULL, 0, &geom)); - BAD(scad_geometries_common_boundaries(NULL, NULL, 1, &geom2, 1, &geom)); - BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, NULL, 1, &geom)); - BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, NULL)); - OK(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, &geom)); + BAD(scad_geometries_common_boundaries(NULL, geoms, 2, NULL, 0, &geom_array, &c)); + BAD(scad_geometries_common_boundaries(NULL, NULL, 1, &geom2, 1, &geom_array, &c)); + BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, NULL, 1, &geom_array, &c)); + BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, &geom_array, NULL)); + BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, NULL, &c)); + OK(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, &geom_array, &c)); OK(scad_geometry_ref_put(geom)); BAD(scad_geometries_partition(NULL, 2, 1, out_geoms));