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:
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));