commit 7a9bc8e8f712df1e7c92ec7e2f02be5f278a8d68
parent 7d4be0eeafec655b5e622a454f779f4dc4b9c5d5
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Wed, 23 Nov 2022 11:37:30 +0100
Rework on geometry partition given a geometry list
Diffstat:
2 files changed, 242 insertions(+), 43 deletions(-)
diff --git a/src/scad.h b/src/scad.h
@@ -261,22 +261,21 @@ scad_geometries_partition
struct scad_geometry** out_geometry);
/* Compute the boolean fragments (general fuse) resulting from the
- * intersection of the single geometry `geometries[not_tool_index]' and the
+ * intersection of every single geometry in `geometries' and the
* other geometries in `geometries' used as tools, making all interfaces
* conformal.
- * This function may be best suited than scad_geometries_partition when used
- * from a loop.
+ * Geometries are considered one at a time against the other ones, producing one
+ * output by geometry in `geometries'.
* When applied to geometries of different dimensions, the lower dimensional
* geometries will be automatically embedded in the higher dimensional
* geometries if they are not on their boundary. */
SCAD_API res_T
scad_geometries_partition_one
- (const char* name, /* Can be NULL */
+ (char** names, /* Can be NULL */
struct scad_geometry** geometries,
const size_t geometries_count,
- const size_t not_tool_index,
const int allow_overlapping,
- struct scad_geometry** out_geometry);
+ struct scad_geometry** out_geometries);
SCAD_API res_T
scad_fragment_geometries
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -24,10 +24,24 @@
#include <rsys/math.h>
#include <rsys/double3.h>
+#include <rsys/hash_table.h>
+
#include <stdlib.h>
#include <string.h>
#include <gmsh/gmshc.h>
+/* A type used to deduplicate tags */
+#define HTABLE_NAME tags
+#define HTABLE_KEY int
+#define HTABLE_DATA char
+#include <rsys/hash_table.h>
+
+/* A type used for mappings */
+#define HTABLE_NAME mappings
+#define HTABLE_KEY int
+#define HTABLE_DATA size_t
+#include <rsys/hash_table.h>
+
/*******************************************************************************
* Utility functions
******************************************************************************/
@@ -102,33 +116,67 @@ gather_tags
size_t* out_dimTags_n)
{
res_T res = RES_OK;
- int* tags;
+ int* dimTags = NULL;
size_t i, j, c, sz;
+ struct mem_allocator* allocator;
+ struct scad_device* dev = get_device();
+ struct htable_tags t2, t3;
+ struct htable_tags_iterator it, end;
- ASSERT(geometries && geometries_count && out_dimTags && out_dimTags_n);
+ ASSERT((geometries || !geometries_count) && (out_dimTags || !out_dimTags_n));
ASSERT(except == SIZE_MAX || except < geometries_count);
- for(sz = 0, i = 0; i < geometries_count; i++) {
- sz += geometries[i]->gmsh_dimTags_n;
+ allocator = dev->allocator;
+ htable_tags_init(allocator, &t2);
+ htable_tags_init(allocator, &t3);
+
+ /* list tags and remove duplicates */
+ for(i = 0; i < geometries_count; i++) {
+ if(i == except) continue;
+ for(j = 0; j < geometries[i]->gmsh_dimTags_n; j += 2) {
+ char one = 1;
+ int dim = geometries[i]->gmsh_dimTags[j];
+ int tag = geometries[i]->gmsh_dimTags[j+1];
+ struct htable_tags* tn = (dim == 2) ? &t2 : &t3;
+ ASSERT(dim == 2 || dim == 3);
+ ERR(htable_tags_set(tn, &tag, &one));
+ }
}
- tags = malloc(sizeof(*tags) * sz);
- if(!tags) {
+
+ /* Build result */
+ sz = htable_tags_size_get(&t2) + htable_tags_size_get(&t3);
+ dimTags = malloc(sizeof(*dimTags) * sz * 2);
+ if(!dimTags) {
res = RES_MEM_ERR;
goto error;
}
- for(i = 0, c = 0; i < geometries_count; i++) {
- if(i == except) continue;
- for(j = 0; j < geometries[i]->gmsh_dimTags_n; j++, c++) {
- tags[c] = geometries[i]->gmsh_dimTags[j];
- }
+
+ c = 0;
+ htable_tags_begin(&t2, &it);
+ htable_tags_end(&t2, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ dimTags[c++] = 2;
+ dimTags[c++] = *htable_tags_iterator_key_get(&it);
+ htable_tags_iterator_next(&it);
+ }
+ htable_tags_begin(&t3, &it);
+ htable_tags_end(&t3, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ dimTags[c++] = 3;
+ dimTags[c++] = *htable_tags_iterator_key_get(&it);
+ htable_tags_iterator_next(&it);
}
+ ASSERT(sz*2 == c);
+
*out_dimTags_n = c;
- *out_dimTags = tags;
+ *out_dimTags = dimTags;
exit:
+ htable_tags_release(&t2);
+ htable_tags_release(&t3);
return res;
error:
- if(tags) free(tags);
+ free(dimTags);
goto exit;
}
@@ -141,7 +189,7 @@ scad_geometries_partition_core
struct scad_geometry** tools,
const size_t tools_count,
const int allow_overlapping,
- struct scad_geometry** out_geometry)
+ struct scad_geometry** out_geom)
{
int* tagout = NULL;
int** map = NULL;
@@ -153,7 +201,7 @@ scad_geometries_partition_core
struct scad_geometry* geom = NULL;
res_T res = RES_OK;
- if(!geometries || !out_geometry) {
+ if(!geometries || !geometries_count || !tools || !tools_count || !out_geom) {
res = RES_BAD_ARG;
goto error;
}
@@ -164,27 +212,21 @@ scad_geometries_partition_core
}
ERR(gather_tags(geometries, geometries_count, except, &data1, &sz1));
- if(tools) {
- ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2));
- }
+ ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2));
- /* We don't remove gmsh objects here; they are only removed when their tags are
- * no longuer used by any star-cad geometry */
+ /* We don't remove gmsh objects here; they are only removed when their tags
+ * are no longuer used by any star-cad geometry */
gmshModelOccFragment(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ASSERT(sz1 + sz2 == 2*mapnn);
if(!allow_overlapping) {
/* Each tag in geometries must have been translated to a single tag in map */
size_t i, err;
for(i = 0, err = SIZE_MAX; i < mapnn; i++) {
- int dim = (2*i >= sz1) ? data2[i*2-sz1] : data1[i*2];
- int tag = (2*i >= sz1) ? data2[i*2+1-sz1] : data1[i*2+1];
if(mapn[i] != 2) {
err = i;
break;
}
- ASSERT(dim == map[i][0]); (void)dim; (void)tag;
}
if(err != SIZE_MAX) {
struct scad_geometry* problem = geometries[err];
@@ -207,11 +249,11 @@ scad_geometries_partition_core
ERR(device_register_tags(geom));
exit:
- if(out_geometry) *out_geometry = geom;
- if(data1) free(data1);
- if(data2) free(data2);
- if(mapn) free(mapn);
- if(map) free(map);
+ if(out_geom) *out_geom = geom;
+ free(data1);
+ free(data2);
+ free(mapn);
+ free(map);
return res;
error:
if(geom) {
@@ -1245,18 +1287,176 @@ error:
res_T
scad_geometries_partition_one
- (const char* name, /* Can be NULL */
+ (char** names, /* Can be NULL */
struct scad_geometry** geometries,
const size_t geometries_count,
- const size_t not_tool_index,
const int allow_overlapping,
- struct scad_geometry** out_geometry)
+ struct scad_geometry** out_geometries)
{
- if(not_tool_index >= geometries_count)
- return RES_BAD_ARG;
- return scad_geometries_partition_core(name, geometries, geometries_count,
- not_tool_index, geometries+not_tool_index, 1, allow_overlapping,
- out_geometry);
+ res_T res = RES_OK;
+ size_t i;
+ int* tagout = NULL;
+ int** map = NULL;
+ size_t* mapn = NULL;
+ size_t tagoutn = 0, mapnn = 0, sz;
+ int* data = NULL;
+ int ierr = 0;
+ struct scad_geometry** geoms = NULL;
+ struct htable_mappings m2, m3;
+ int hm_initialized = 0;
+ struct mem_allocator* allocator;
+ struct scad_device* dev = get_device();
+ struct htable_tags t2, t3;
+ struct htable_tags_iterator it, end;
+ int ht_initialized = 0;
+
+ if(!geometries || !geometries_count || !out_geometries) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ allocator = dev->allocator;
+ ERR(check_device(FUNC_NAME));
+ if(get_device()->need_synchro) {
+ ERR(scad_synchronize());
+ }
+
+ ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data, &sz));
+
+ /* We don't remove gmsh objects here; they are only removed when their tags
+ * are no longuer used by any star-cad geometry */
+ gmshModelOccFragment(data, sz, NULL, 0, &tagout, &tagoutn, &map, &mapn,
+ &mapnn, -1, 0, 0, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ ASSERT(sz == 2*mapnn); /* Because input tags where deduplicated */
+
+ /* Check first if there is an overlapping problem */
+ if(!allow_overlapping) {
+ /* No overlapping means that each tag in geometries is translated into a
+ * single tag in map */
+ unsigned long ucount = 0;
+ for(i = 0; i < mapnn; i++) {
+ if(mapn[i] != 2) {
+ res = RES_BAD_ARG;
+ if(str_is_empty(&geometries[i]->name)) {
+ ucount++;
+ } else {
+ log_error(get_device(), "Geometry '%s' overlapping.\n",
+ str_cget(&geometries[i]->name));
+ }
+ }
+ }
+ if(ucount) {
+ log_error(get_device(), "%lu unamed overlapping geometries.\n", ucount);
+ }
+ if(res != RES_OK) goto error;
+ }
+
+ /* Create htables of mappings to ease access */
+ htable_mappings_init(allocator, &m2);
+ htable_mappings_init(allocator, &m3);
+ hm_initialized = 1;
+ for(i = 0; i < sz; i += 2) {
+ int dim = data[i];
+ int tag = data[i+1];
+ size_t mapping = i/2;
+ struct htable_mappings* mn = (dim == 2) ? &m2 : &m3;
+ ASSERT(dim == 2 || dim == 3);
+ ERR(htable_mappings_set(mn, &tag, &mapping));
+ }
+
+ /* Create output geometries from mapping */
+ geoms = calloc(geometries_count, sizeof(*geoms));
+ if(!geoms) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ htable_tags_init(allocator, &t2);
+ htable_tags_init(allocator, &t3);
+ ht_initialized = 1;
+ for(i = 0; i < geometries_count; i++) {
+ const char* name = names ? names[i] : NULL;
+ struct scad_geometry* geom = geometries[i];
+ size_t c, n, j;
+ int* dt = NULL;
+ /* For each tag in geometries[i] out_geometries[i] includes the mapped tags.
+ * The resulting tags need to be deduplicated though. */
+ htable_tags_clear(&t2);
+ htable_tags_clear(&t3);
+ for(j = 0; j < geom->gmsh_dimTags_n; j += 2) {
+ int dim = geom->gmsh_dimTags[j];
+ int tag = geom->gmsh_dimTags[j+1];
+ struct htable_mappings* mn = (dim == 2) ? &m2 : &m3;
+ size_t k;
+ size_t* mapping = htable_mappings_find(mn, &tag);
+ ASSERT(dim == 2 || dim == 3);
+ ASSERT(mapping && *mapping < mapnn);
+ for(k = 0; k < mapn[*mapping]; k += 2) {
+ char one = 1;
+ int d = map[*mapping][k];
+ int t = map[*mapping][k+1];
+ struct htable_tags* tn = (d == 2) ? &t2 : &t3;
+ ERR(htable_tags_set(tn, &t, &one));
+ }
+ }
+ /* Allocate result */
+ n = htable_tags_size_get(&t2) + htable_tags_size_get(&t3);
+ dt = malloc(sizeof(*dt) * 2 * n);
+ if(!dt) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ /* Copy tags */
+ c = 0;
+ htable_tags_begin(&t2, &it);
+ htable_tags_end(&t2, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ dt[c++] = 2;
+ dt[c++] = *htable_tags_iterator_key_get(&it);
+ htable_tags_iterator_next(&it);
+ }
+ htable_tags_begin(&t3, &it);
+ htable_tags_end(&t3, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ dt[c++] = 3;
+ dt[c++] = *htable_tags_iterator_key_get(&it);
+ htable_tags_iterator_next(&it);
+ }
+ ASSERT(c == 2*n);
+
+ /* Create geometry */
+ ERR(scad_geometry_create(name, geoms+i));
+ geoms[i]->gmsh_dimTags_n = c;
+ geoms[i]->gmsh_dimTags = dt;
+ ERR(device_register_tags(geoms[i]));
+ }
+ memcpy(out_geometries, geoms, geometries_count * sizeof(*geoms));
+
+exit:
+ for(i = 0; i < mapnn; i++) free(map[i]);
+ free(mapn);
+ if(hm_initialized) {
+ htable_mappings_release(&m2);
+ htable_mappings_release(&m3);
+ }
+ if(ht_initialized) {
+ htable_tags_release(&t2);
+ htable_tags_release(&t3);
+ }
+ free(geoms);
+ free(data);
+ free(tagout);
+ return res;
+error:
+ if(geoms) {
+ for(i = 0; i < geometries_count; i++) {
+ if(geoms[i]) CHK(RES_OK == geometry_release(geoms[i]));
+ }
+ }
+ if(tagout) {
+ gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
+ }
+ goto exit;
}
res_T