star-cad

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

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:
Msrc/scad.h | 11+++++------
Msrc/scad_geometry.c | 274++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
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