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:
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;
+}