star-cad

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

commit de3c0f6dd5bf18621cbf6e49cc0d319cca8a0477
parent 1e871accee115e344204bd5da66dfcc8e2ab5114
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu, 12 Dec 2024 17:39:56 +0100

Add an API call to change mesh size by geometry

This works by setting a size factor that is applied to the mesh size
resulting from the various Mesh.XXXX options.

Diffstat:
Msrc/scad.h | 13+++++++++++++
Msrc/scad_device.c | 8++++++++
Msrc/scad_device.h | 6++++++
Msrc/scad_geometry.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/src/scad.h b/src/scad.h @@ -548,6 +548,19 @@ SCAD_API res_T scad_scene_mesh (void); +/* Set a size factor for geometries in `geometries'. + * When meshing these geometries, triangles' size will be size*factor, where + * size would be the size of the triangle in the absence of a size factor. + * The size factor is applied recursively down to dimension 0 (points). + * If multiple size factors are applied, the order in which size factors are + * applied matters, as the last applied size factor remains. + * To reset a size factor, just apply a new factor of 1. */ +SCAD_API res_T +scad_geometries_set_mesh_size_factor + (struct scad_geometry** geometries, + const size_t geometries_count, + double factor); + /* Clear the mesh of the geometries in `geometries'. * Note that the mesh of a geometry can only be cleared if it is not on the * boundary of another geometry with a non-empty mesh. */ diff --git a/src/scad_device.c b/src/scad_device.c @@ -120,6 +120,10 @@ device_release(struct scad_device* dev) htable_geometries_release(&dev->allgeom); device_release_tags_of_dim(dev, 2); device_release_tags_of_dim(dev, 3); + htable_size_factors_release(&dev->size_factors_by_dim[0]); + htable_size_factors_release(&dev->size_factors_by_dim[1]); + htable_size_factors_release(&dev->size_factors_by_dim[2]); + htable_size_factors_release(&dev->size_factors_by_dim[3]); if(log) { logger_print(dev->logger, log_type, "End finalizing scad.\n"); } @@ -597,6 +601,10 @@ scad_initialize htable_geometries_init(allocator, &g_device->allgeom); htable_tags2desc_init(allocator, &g_device->tags2desc[0]); htable_tags2desc_init(allocator, &g_device->tags2desc[1]); + htable_size_factors_init(allocator, &g_device->size_factors_by_dim[0]); + htable_size_factors_init(allocator, &g_device->size_factors_by_dim[1]); + htable_size_factors_init(allocator, &g_device->size_factors_by_dim[2]); + htable_size_factors_init(allocator, &g_device->size_factors_by_dim[3]); /* Init to default */ scad_set_options(NULL); diff --git a/src/scad_device.h b/src/scad_device.h @@ -115,6 +115,11 @@ tag_desc_copy_and_release #define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE tag_desc_copy_and_release #include <rsys/hash_table.h> +#define HTABLE_NAME size_factors +#define HTABLE_KEY int +#define HTABLE_DATA double +#include <rsys/hash_table.h> + struct scad_device { struct logger* logger; struct mem_allocator* allocator; @@ -122,6 +127,7 @@ struct scad_device { struct htable_names geometry_names; struct htable_geometries allgeom; struct htable_tags2desc tags2desc[2]; /* Only geoms for 2D and 3D tags for now */ + struct htable_size_factors size_factors_by_dim[4]; int verbose; int need_synchro; diff --git a/src/scad_geometry.c b/src/scad_geometry.c @@ -251,6 +251,115 @@ error: goto exit; } +static res_T +store_tags + (int* dimTags, + size_t count, + struct htable_tags t[4]) +{ + res_T res = RES_OK; + char one = 1; + size_t i; + ASSERT((dimTags || count == 0) && t); + for(i = 0; i < count; i += 2) { + int dim = dimTags[i]; + int tag = dimTags[i+1]; + ASSERT(dim >= 0 && dim <= 3); + ERR(htable_tags_set(t+dim, &tag, &one)); + } + +exit: + return res; +error: + goto exit; +} + +static res_T +gather_tags_recursive + (struct scad_geometry** geometries, + const size_t geometries_count, + int* out_dimTags[4], + size_t out_dimTags_n[4]) +{ + res_T res = RES_OK; + int* dimTags[4] = { NULL, NULL, NULL, NULL }, *sub = NULL; + size_t i, sz[4]; + struct scad_device* dev = get_device(); + struct mem_allocator* allocator = dev->allocator; + struct htable_tags t[4]; + struct htable_tags_iterator it, end; + int dim; + + ASSERT((geometries || geometries_count == 0) && out_dimTags && out_dimTags_n); + + for(i = 0; i < 4; i++) { + htable_tags_init(allocator, t+i); + } + + /* list tags by dimension and remove duplicates */ + for(i = 0; i < geometries_count; i++) { + if(!geometries[i]) { + res = RES_BAD_ARG; + goto error; + } + ERR(store_tags(geometries[i]->gmsh_dimTags, geometries[i]->gmsh_dimTags_n, t)); + } + + /* Recursively build result by dimension and list constituants, + * begining with dim==3 */ + for(dim = 3; dim >= 0; dim--) { + size_t c = 0; + sz[dim] = 2 * htable_tags_size_get(t+dim); + dimTags[dim] = MEM_ALLOC(allocator, sz[dim] * sizeof(*dimTags)); + if(!dimTags[dim]) { + res = RES_MEM_ERR; + goto error; + } + htable_tags_begin(t+dim, &it); + htable_tags_end(t+dim, &end); + while(!htable_tags_iterator_eq(&it, &end)) { + dimTags[dim][c++] = dim; + dimTags[dim][c++] = *htable_tags_iterator_key_get(&it); + htable_tags_iterator_next(&it); + } + if(dim > 0) { + int ierr; + size_t subn; + gmshModelGetBoundary(dimTags[dim], sz[dim], &sub, &subn, 0, 0, 0, &ierr); + ERR(gmsh_err_to_res_T(ierr)); + ERR(store_tags(sub, subn, t)); + gmshFree(sub); sub = NULL; + } + ASSERT(sz[dim] == c); + } + + for(i = 0; i < 4; i++) { + out_dimTags_n[i] = sz[i]; + out_dimTags[i] = dimTags[i]; + } + +exit: + if(sub) gmshFree(sub); + for(i = 0; i < 4; i++) { + htable_tags_release(t+i); + } + return res; +error: + for(i = 0; i < 4; i++) { + MEM_RM(allocator, dimTags[i]); + } + goto exit; +} + +static double size_callback + (int dim, int tag, double x, double y, double z, double lc, void* data_) +{ + struct scad_device* dev = get_device(); + double *factor = htable_size_factors_find(dev->size_factors_by_dim + dim, &tag); + (void)x;(void)y;(void)z;(void)data_; + return (factor ? *factor * lc : lc); +} + /* gmsh documentation states that memory allocated by gmsh should be freed using * gmshFree. * According to valgrind map results as allocated by gmsh are not fully freed if @@ -2579,3 +2688,56 @@ error: out = NULL; goto exit; } + +res_T +scad_geometries_set_mesh_size_factor + (struct scad_geometry** geometries, + const size_t geometries_count, + double factor) +{ + res_T res = RES_OK; + struct scad_device* dev = get_device(); + int ierr, dim, some = 0; + int* tagout[4] = { NULL, NULL, NULL, NULL }; + size_t tagoutn[4] = { 0, 0, 0, 0}, i; + + if(!geometries || geometries_count == 0 || factor <= 0) { + res = RES_BAD_ARG; + goto error; + } + + ERR(check_device(FUNC_NAME)); + + ERR(gather_tags_recursive(geometries, geometries_count, tagout, tagoutn)); + for(dim = 0; dim < 4; dim++) { + for(i = 0; i < tagoutn[dim]; i += 2) { + int d = tagout[dim][i]; + int tag = tagout[dim][i+1]; + struct htable_size_factors* factors = dev->size_factors_by_dim + dim; + double* f_ptr = htable_size_factors_find(factors, &tag); + ASSERT(d == dim); + if(f_ptr && factor == 1) { + size_t c = htable_size_factors_erase(factors, &tag); + ASSERT(c == 1); + } else if(f_ptr) { + *f_ptr = factor; + } else { + ERR(htable_size_factors_set(factors, &tag, &factor)); + } + } + } + for(dim = 0; dim < 4; dim++) { + if(htable_size_factors_size_get(dev->size_factors_by_dim + dim) > 0) { + some = 1; + break; + } + } + + gmshModelMeshSetSizeCallback( (some ? size_callback : NULL), NULL, &ierr); + ERR(gmsh_err_to_res_T(ierr)); + +exit: + return res; +error: + goto exit; +}