commit 7e62deca07d9cf5b578f3492475751d1c26431a9
parent acebcf026722e9bc475003ec1fcdc08bca5ef962
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Mon, 18 Aug 2025 18:37:13 +0200
Fix common boundary
Complete change: intead of relying on OccIntersect to compute the common
part of the boundaries, use tag filtering.
As the geometries need to have been partitioned before calling common
boundary the 'intersect' part of the job as already been done.
Diffstat:
| M | src/scad_geometry.c | | | 164 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
1 file changed, 140 insertions(+), 24 deletions(-)
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -174,6 +174,123 @@ error:
goto end;
}
+enum tag_operation {
+ COMMON_TAGS,
+ UNIQUE_TAGS
+};
+
+static res_T
+process_tag_list
+ (const int* dt1,
+ const size_t c1,
+ const int* dt2,
+ const size_t c2,
+ const enum tag_operation op,
+ int** out_dimTags,
+ size_t* out_dimTags_n)
+{
+ res_T res = RES_OK;
+ size_t i, d, c = 0, sz = 0;
+ struct scad_device* dev = get_device();
+ struct mem_allocator* allocator = dev->allocator;
+ struct htable_tags t2, t3;
+ struct htable_tags_iterator it, end;
+ int* dimTags = NULL;
+ const char set1 = BIT(0), set2 = BIT(1), both = set1 | set2;
+
+ ASSERT((dt1 || c1 == 0) && (dt2 || c2 == 0) && out_dimTags && out_dimTags_n);
+
+ htable_tags_init(allocator, &t2);
+ htable_tags_init(allocator, &t3);
+
+ /* list tags and flags them whith set(s) they are from */
+ for(i = 0; i < c1; i += 2) {
+ int dim = dt1[i];
+ int tag = dt1[i+1];
+ struct htable_tags* tn = (dim == 2) ? &t2 : &t3;
+ ASSERT(dim == 2 || dim == 3);
+ ERR(htable_tags_set(tn, &tag, &set1));
+ }
+ for(i = 0; i < c2; i += 2) {
+ char *fl, tmp;
+ int dim = dt2[i];
+ int tag = dt2[i+1];
+ struct htable_tags* tn = (dim == 2) ? &t2 : &t3;
+ ASSERT(dim == 2 || dim == 3);
+ fl = htable_tags_find(tn, &tag);
+ if(fl == NULL) {
+ tmp = set2;
+ fl = &tmp;
+ } else {
+ *fl |= set2;
+ }
+ ERR(htable_tags_set(tn, &tag, fl));
+ }
+
+ switch(op) {
+ case COMMON_TAGS:
+ for(d = 2; d <= 3; d++) {
+ struct htable_tags* tn = (d == 2) ? &t2 : &t3;
+ htable_tags_begin(tn, &it);
+ htable_tags_end(tn, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ if(*htable_tags_iterator_data_get(&it) == both) sz++;
+ htable_tags_iterator_next(&it);
+ }
+ }
+ break;
+ case UNIQUE_TAGS:
+ sz = htable_tags_size_get(&t2) + htable_tags_size_get(&t3);
+ break;
+ default: FATAL("Invalid enum value");
+ }
+
+ /* Build result */
+ if(sz > 0) {
+ dimTags = MEM_ALLOC(allocator, sz * 2 * sizeof(*dimTags));
+ if(!dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ for(d = 2; d <= 3; d++) {
+ struct htable_tags* tn = (d == 2) ? &t2 : &t3;
+ htable_tags_begin(tn, &it);
+ htable_tags_end(tn, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ int add;
+ switch(op) {
+ case COMMON_TAGS:
+ add = (*htable_tags_iterator_data_get(&it) == both);
+ break;
+ case UNIQUE_TAGS:
+ add = 1;
+ break;
+ default: FATAL("Invalid enum value");
+ }
+ if(add) {
+ dimTags[c++] = 2;
+ dimTags[c++] = *htable_tags_iterator_key_get(&it);
+ }
+ htable_tags_iterator_next(&it);
+ }
+ }
+ ASSERT(sz*2 == c);
+ }
+
+exit:
+ *out_dimTags_n = c;
+ *out_dimTags = dimTags;
+ htable_tags_release(&t2);
+ htable_tags_release(&t3);
+ return res;
+error:
+ MEM_RM(allocator, dimTags);
+ dimTags = NULL;
+ c = 0;
+ goto exit;
+}
+
static res_T
gather_tags
(struct scad_geometry** geometries,
@@ -1674,11 +1791,10 @@ scad_geometries_common_boundaries
{
res_T res = RES_OK;
int* tagout = NULL;
- int** map = NULL;
- size_t* mapn = NULL;
- size_t tagoutn, mapnn = 0, sz1, sz2;
+ size_t tagoutn, sz1, sz2, u_sz;
int* data1 = NULL;
int* data2 = NULL;
+ int* unique = NULL;
int ierr = 0;
int* bound1 = NULL;
int* bound2 = NULL;
@@ -1705,17 +1821,16 @@ scad_geometries_common_boundaries
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
- /* We don't remove gmsh objects here; they are only removed when their tags are
- * no longer used by any star-cad geometry */
+ /* data1 and data2 can have tags in common: deduplicate them!
+ * (even if the refcounting stuff can manage duplicates) */
+ ERR(process_tag_list(data1, sz1, data2, sz2, UNIQUE_TAGS, &unique, &u_sz));
+
gmshModelGetBoundary(data1, sz1, &bound1, &n1, 1, 0, 0, &ierr);
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));
+
+ ERR(process_tag_list(bound1, n1, bound2, n2, COMMON_TAGS, &tagout, &tagoutn));
ASSERT(tagoutn % 2 == 0);
c = tagoutn / 2;
@@ -1747,19 +1862,20 @@ scad_geometries_common_boundaries
ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
}
ERR(str_append_printf(&msg, "] getting a ref to tags ["));
- for(i = 0; i < sz1; i += 2) {
- const int dim = data1[i];
- const int tag = data1[i+1];
+ for(i = 0; i < u_sz; i += 2) {
+ const int dim = unique[i];
+ const int tag = unique[i+1];
ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
}
- for(i = 0; i < sz2; i += 2) {
- const int dim = data2[i];
- const int tag = data2[i+1];
- ERR(str_append_printf(&msg, ", %d.%d", dim, tag));
- }
logger_print(dev->logger, log_type, "%s].\n", str_cget(&msg));
}
+ out_geom = MEM_CALLOC(allocator, c, sizeof(*out_geom));
+ if(!out_geom) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
for(i = 0, n = 0; i < tagoutn; i += 2, n++) {
int dim = tagout[i];
int tag = tagout[i+1];
@@ -1772,17 +1888,18 @@ scad_geometries_common_boundaries
ERR(geom_set_name(out_geom[n], &name));
}
out_geom[n]->gmsh_dimTags_n = 2;
- out_geom[n]->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*tagout));
+ out_geom[n]->gmsh_dimTags = MEM_ALLOC(allocator,
+ 2 * sizeof(*out_geom[n]->gmsh_dimTags));
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, data1, sz1));
- ERR(device_register_ref_to_tags(dim, tag, data2, sz2));
+ ERR(device_register_ref_to_tags(dim, tag, unique, u_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. */
@@ -1799,12 +1916,11 @@ exit:
if(allocator) {
MEM_RM(allocator, data1);
MEM_RM(allocator, data2);
+ MEM_RM(allocator, unique);
+ MEM_RM(allocator, tagout);
}
gmshFree(bound1);
gmshFree(bound2);
- gmshFree(mapn);
- gmshFree(tagout);
- free_gmsh_map(map, mapnn);
return res;
error:
if(ierr) {