star-cad

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

commit 1a61e7a4d636fa754c5683c3024e572c4df05977
parent 83738eb1326404be7933accb4c3508cd9aa7a6c2
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri,  2 Sep 2022 17:19:46 +0200

Change API reflect groups removal

Internals change too, as the lifetime of gmsh entities is now implicitly managed by reference (from star-cad geometries)

Diffstat:
Msrc/scad.c | 18++++++++++++++++--
Msrc/scad.h | 60+++++++++++++++++++++++++++++++++++++-----------------------
Msrc/scad_device.c | 138++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/scad_device.h | 33++++++++++++++++++++++++++++++++-
Msrc/scad_geometry.c | 473+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/scad_geometry.h | 4++--
6 files changed, 514 insertions(+), 212 deletions(-)

diff --git a/src/scad.c b/src/scad.c @@ -186,9 +186,14 @@ scad_synchronize (void) { res_T res = RES_OK; + struct scad_device* dev = get_device(); int ierr; - ERR(check_device()); + /* Cannot use check_device to avoid an infinite loop! */ + if(!dev) { + res = RES_BAD_ARG; + goto error; + } gmshModelOccSynchronize(&ierr); get_device()->need_synchro = 0; @@ -204,9 +209,18 @@ res_T scad_run_ui(void) { res_T res = RES_OK; + struct scad_device* dev = get_device(); int ierr; - ERR(check_device()); + /* Cannot use check_device to avoid an infinite loop! */ + if(!dev) { + res = RES_BAD_ARG; + goto error; + } + + if(dev->options.Misc.SynchronizeOnRunUI && get_device()->need_synchro) { + ERR(scad_synchronize()); + } gmshFltkRun(&ierr); ERR(gmsh_err_to_res_T(ierr)); diff --git a/src/scad.h b/src/scad.h @@ -52,10 +52,14 @@ struct scad_options { double MinimumElementsPerTwoPi; double MeshSizeExtendFromBoundary; } Mesh; + struct { + int Step; + int SynchronizeOnRunUI; + } Misc; }; #define SCAD_DEFAULT_OPTIONS__ \ - { { 2, 0, 1, 36, 0 } } + { { 2, 0, 1, 36, 0 }, { 0, 0 }} static const struct scad_options SCAD_DEFAULT_OPTIONS = SCAD_DEFAULT_OPTIONS__; @@ -93,6 +97,10 @@ scad_synchronize ******************************************************************************/ SCAD_API res_T +scad_geometry_delete + (struct scad_geometry* geom); + +SCAD_API res_T scad_scene_clear (void); @@ -169,20 +177,22 @@ scad_scene_mesh SCAD_API res_T scad_fuse_geometries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove); + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry); /* Compute the boolean difference between the geometries `geom1' and `geom2'. * Remove geom1 and geom2 from scene if `remove' is set. */ SCAD_API res_T scad_cut_geometries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove); + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry); /* Compute the boolean intersection (the common parts) of the geometries * `geom1' and `geom2'. @@ -190,34 +200,38 @@ scad_cut_geometries SCAD_API res_T scad_intersect_geometries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove); + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry); /* compute boundary intersection (the common part) of geom1 and geom2 * Remove geom1 and geom2 from scene if `remove' is set. */ SCAD_API res_T scad_geometries_common_boundaries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove); + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry); /* Compute the boolean fragments (general fuse) resulting from the - * intersection of the geometries `geom1' and `geom2', making all iterfaces + * intersection of the geometries `geom1' and `geom2', making all interfaces * conformal. 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. * Remove geom1 and geom2 from scene if `remove' is set. */ SCAD_API res_T -scad_geometries_fragment +scad_geometries_partition (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove); + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + const int allow_overlapping, + struct scad_geometry** out_geometry); /* Get the boundary of the geometry `geom'. */ SCAD_API res_T diff --git a/src/scad_device.c b/src/scad_device.c @@ -16,6 +16,7 @@ #include "scad.h" #include "scad_c.h" #include "scad_device.h" +#include "scad_geometry.h" #include <rsys/logger.h> #include <rsys/mem_allocator.h> @@ -23,6 +24,7 @@ #include <rsys/cstr.h> #include <gmshc.h> +#include <rsys/rsys.h> /******************************************************************************* * Local functions @@ -30,19 +32,26 @@ static void device_release(struct scad_device* dev) { - struct htable_names_iterator it, end; + struct htable_geometries tmp; + struct htable_geometries_iterator it, end; ASSERT(dev); - htable_names_begin(&dev->geometry_names, &it); - htable_names_end(&dev->geometry_names, &end); - while(!htable_names_iterator_eq(&it, &end)) { - struct scad_geometry* geom = *htable_names_iterator_data_get(&it); - SCAD(geometry_release(geom)); - htable_names_iterator_next(&it); + htable_geometries_init(dev->allocator, &tmp); + CHK(RES_OK == htable_geometries_copy(&tmp, &dev->allgeom)); + htable_geometries_begin(&tmp, &it); + htable_geometries_end(&tmp, &end); + while(!htable_geometries_iterator_eq(&it, &end)) { + struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it); + CHK(RES_OK == geometry_release(geom)); + htable_geometries_iterator_next(&it); } htable_names_release(&dev->geometry_names); + htable_tags2geom_release(&dev->tags2geom[0]); + htable_tags2geom_release(&dev->tags2geom[1]); + htable_geometries_release(&dev->allgeom); MEM_RM(dev->allocator, dev); + htable_geometries_release(&tmp); } void @@ -79,7 +88,21 @@ res_T check_device (void) { - return g_device ? RES_OK : RES_BAD_ARG; + res_T res = RES_OK; + + if(!g_device) { + res = RES_BAD_ARG; + goto error; + } + + if(g_device->options.Misc.Step) { + ERR(scad_run_ui()); + } + +exit: + return res; +error: + goto exit; } struct scad_device* @@ -90,6 +113,96 @@ get_device } res_T +device_register_tags + (struct scad_geometry* geom) +{ + res_T res = RES_OK; + int* dimTags; + size_t count; + + size_t i; + + ASSERT(geom); + + dimTags = geom->gmsh_dimTags; + count = geom->gmsh_dimTags_n; + for(i = 0; i < count; i += 2) { + int dim = dimTags[i]; + int tag = dimTags[i+1]; + struct htable_tags2geom* t2g; + struct htable_geometries* geoms; + char one = 1; + if(dim != 2 && dim != 3) { + res = RES_BAD_ARG; + goto error; + } + /* Add geom to the geometries that use tag@dim */ + t2g = g_device->tags2geom + (dim-2); + geoms = htable_tags2geom_find(t2g, &tag); + if(!geoms) { + /* First geom using this tag: create the table */ + struct htable_geometries g; + htable_geometries_init(g_device->allocator, &g); + ERR(htable_tags2geom_set(t2g, &tag, &g)); + geoms = htable_tags2geom_find(t2g, &tag); + ASSERT(geoms); + } + ASSERT(!htable_geometries_find(geoms, &geom)); + ERR(htable_geometries_set(geoms, &geom, &one)); + } + +end: + return res; +error: + goto end; +} + +res_T +device_unregister_tags + (struct scad_geometry* geom) +{ + res_T res = RES_OK; + int* dimTags; + size_t count; + size_t i; + + ASSERT(geom); + + dimTags = geom->gmsh_dimTags; + count = geom->gmsh_dimTags_n; + + for(i = 0; i < count; i += 2) { + int dim = dimTags[i]; + int tag = dimTags[i+1]; + int ierr; + struct htable_tags2geom* t2g; + struct htable_geometries* geoms; + size_t n; + if(dim != 2 && dim != 3) { + /* other dims not managed yet */ + res = RES_BAD_ARG; + goto error; + } + t2g = g_device->tags2geom + (dim-2); + geoms = htable_tags2geom_find(t2g, &tag); + n = htable_geometries_erase(geoms, &geom); + ASSERT(geoms && n == 1); (void)n; + if(htable_geometries_size_get(geoms) > 0) continue; + /* The gmsh geometry with tag 'tag' is not in use anymore: release it */ + gmshModelOccRemove(dimTags+i, 2, 1, &ierr); + ERR(gmsh_err_to_res_T(ierr)); + } + +end: + return res; +error: + goto end; +} + +/******************************************************************************* + * API scad_device functions + ******************************************************************************/ +res_T scad_initialize (struct logger* logger, struct mem_allocator* mem_allocator, @@ -118,6 +231,9 @@ scad_initialize g_device->logger = logger ? logger : LOGGER_DEFAULT; g_device->allocator = allocator; htable_names_init(allocator, &g_device->geometry_names); + htable_geometries_init(allocator, &g_device->allgeom); + htable_tags2geom_init(allocator, &g_device->tags2geom[0]); + htable_tags2geom_init(allocator, &g_device->tags2geom[1]); g_device->verbose = verbose; /* Init to default */ scad_set_options(NULL); @@ -160,9 +276,12 @@ scad_set_options const struct scad_options* actual_options = options ? options : &SCAD_DEFAULT_OPTIONS; int ierr = 0; + struct scad_options keep; ERR(check_device()); + keep = get_device()->options; + gmshOptionSetNumber("Mesh.StlOneSolidPerSurface", actual_options->Mesh.StlOneSolidPerSurface, &ierr); ERR(gmsh_err_to_res_T(ierr)); @@ -179,10 +298,13 @@ scad_set_options actual_options->Mesh.MeshSizeExtendFromBoundary, &ierr); ERR(gmsh_err_to_res_T(ierr)); + get_device()->options = *actual_options; + exit: return res; error: fprintf(stderr, "%s: can't initialize gmsh -- %s\n", FUNC_NAME, res_to_cstr(res)); + if(get_device()) get_device()->options = keep; goto exit; } diff --git a/src/scad_device.h b/src/scad_device.h @@ -23,6 +23,7 @@ #include <rsys/ref_count.h> #include <rsys/logger.h> #include <rsys/hash_table.h> +#include <rsys/dynamic_array.h> #include <rsys/str.h> static INLINE char @@ -46,15 +47,30 @@ hash_str(const struct str* a) #define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release #define HTABLE_KEY_FUNCTOR_EQ eq_str #define HTABLE_KEY_FUNCTOR_HASH hash_str +#include <rsys/hash_table.h> + +#define HTABLE_NAME geometries +#define HTABLE_DATA char +#define HTABLE_KEY struct scad_geometry* +#include <rsys/hash_table.h> +#define HTABLE_NAME tags2geom +#define HTABLE_DATA struct htable_geometries +#define HTABLE_KEY int +#define HTABLE_DATA_FUNCTOR_INIT htable_geometries_init +#define HTABLE_DATA_FUNCTOR_RELEASE htable_geometries_release +#define HTABLE_DATA_FUNCTOR_COPY htable_geometries_copy +#define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE htable_geometries_copy_and_release #include <rsys/hash_table.h> struct scad_device { struct logger* logger; struct mem_allocator* allocator; + struct scad_options options; struct htable_names geometry_names; + struct htable_geometries allgeom; + struct htable_tags2geom tags2geom[2]; int verbose; - int is_meshed; int need_synchro; ref_T ref; @@ -113,4 +129,19 @@ LOCAL_SYM struct scad_device* get_device (void); +LOCAL_SYM res_T +device_register_tags + (struct scad_geometry* geom); + +LOCAL_SYM res_T +device_unregister_tags + (struct scad_geometry* geom); + +LOCAL_SYM res_T +device_apply_mappings + (const int* original_dimTags, + int** mappings, + size_t* mappings_counts, /* Number of items in each mapping */ + const size_t mappings_count); /* Number of mappings; count(original_dimTags)/2 */ + #endif diff --git a/src/scad_geometry.c b/src/scad_geometry.c @@ -35,90 +35,119 @@ scad_geometry_create struct scad_geometry** out_geometry) { res_T res = RES_OK; + struct str str_name; struct scad_geometry* geom = NULL; + struct scad_device* dev = get_device(); + char one = 1; ASSERT(out_geometry); - if (name) { - struct str str_name; - - str_init(get_device()->allocator, &str_name); + str_init(dev->allocator, &str_name); + if(name) { + if(strlen(name) == 0) { + res = RES_BAD_ARG; + log_error(get_device(), "Geometry name '' is invalid.\n"); + goto error; + } ERR(str_set(&str_name, name)); - if(name && htable_names_find(&get_device()->geometry_names, &str_name)) { + if(name && htable_names_find(&dev->geometry_names, &str_name)) { /* if defined, names must be unique */ res = RES_BAD_ARG; + log_error(get_device(), "Geometry name '%s' is allready in use.\n", + name); goto error; } - str_release(&str_name); } - geom = (struct scad_geometry*)MEM_CALLOC(get_device()->allocator, 1, + geom = (struct scad_geometry*)MEM_CALLOC(dev->allocator, 1, sizeof(*geom)); if(!geom) { res = RES_MEM_ERR; goto error; } - str_init(get_device()->allocator, &geom->name); - get_device()->need_synchro = 1; - if(name) { - struct str str_name; + ERR(htable_geometries_set(&dev->allgeom, &geom, &one)); - str_init(get_device()->allocator, &str_name); - ERR(str_set(&str_name, name)); - ERR(str_copy(&geom->name, &str_name)); - ERR(htable_names_set(&get_device()->geometry_names, &str_name, &geom)); - str_release(&str_name); + str_init(dev->allocator, &geom->name); + dev->need_synchro = 1; + if(name) { + ERR(str_set(&geom->name, name)); + ERR(htable_names_set(&dev->geometry_names, &geom->name, &geom)); } end: - if(out_geometry) *out_geometry = geom; + str_release(&str_name); + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto end; } -static void -remove_dimTags - (struct scad_geometry* geom) +static res_T +gather_tags + (struct scad_geometry** geometries, + const size_t geometries_count, + int** out_dimTags, + size_t* out_dimTags_n) { - ASSERT(geom); - geom->gmsh_dimTags_n = 0; - if(geom->gmsh_dimTags) free(geom->gmsh_dimTags); - geom->gmsh_dimTags = NULL; + res_T res = RES_OK; + int* tags; + size_t i, j, c, sz; + + ASSERT(geometries && geometries_count && out_dimTags && out_dimTags_n); + + for(sz = 0, i = 0; i < geometries_count; i++) { + sz += geometries[i]->gmsh_dimTags_n; + } + tags = malloc(sizeof(*tags) * sz); + if(!tags) { + res = RES_MEM_ERR; + goto error; + } + for(i = 0, c = 0; i < geometries_count; i++) { + for(j = 0; j < geometries[i]->gmsh_dimTags_n; j++, c++) { + tags[c] = geometries[i]->gmsh_dimTags[j]; + } + } + *out_dimTags_n = sz; + *out_dimTags = tags; + +exit: + return res; +error: + if(tags) free(tags); + goto exit; } /******************************************************************************* * Local functions ******************************************************************************/ res_T -scad_geometry_release +geometry_release (struct scad_geometry* geom) { struct mem_allocator* allocator; - size_t sz; - int* data; - int ierr; + struct scad_device* dev = get_device(); res_T res = RES_OK; - ASSERT(geom); + size_t n; + ASSERT(geom); (void)n; - ERR(check_device()); - allocator = get_device()->allocator; - get_device()->need_synchro = 1; + allocator = dev->allocator; + dev->need_synchro = 1; - sz = geom->gmsh_dimTags_n; - data = geom->gmsh_dimTags; - if(sz != 0) { - gmshModelOccRemove(data, sz, 1, &ierr); - ERR(gmsh_err_to_res_T(ierr)); - ASSERT(data); - free(data); + ERR(device_unregister_tags(geom)); + free(geom->gmsh_dimTags); + if(str_len(&geom->name) != 0) { + n = htable_names_erase(&dev->geometry_names, &geom->name); + ASSERT(n == 1); } str_release(&geom->name); + n = htable_geometries_erase(&dev->allgeom, &geom); + ASSERT(n == 1); MEM_RM(allocator, geom); end: @@ -131,6 +160,27 @@ error: * Exported functions *****************************************************************************/ res_T +scad_geometry_delete + (struct scad_geometry* geom) +{ + res_T res = RES_OK; + + if(!geom) { + res = RES_BAD_ARG; + goto error; + } + + ERR(check_device()); + + ERR(geometry_release(geom)); + +end: + return res; +error: + goto end; +} + +res_T scad_scene_clear (void) { @@ -184,7 +234,7 @@ scad_add_rectangle struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!xyz || !dxdy) { + if(!xyz || !dxdy || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -203,13 +253,14 @@ scad_add_rectangle } geom->gmsh_dimTags[0] = 2; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -226,7 +277,7 @@ scad_add_disk struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!xyz || radius <= 0) { + if(!xyz || radius <= 0 || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -245,13 +296,14 @@ scad_add_disk } geom->gmsh_dimTags[0] = 2; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -274,7 +326,7 @@ scad_add_polygon int loop; res_T res = RES_OK; - if(!x || !y || count < 3) { + if(!x || !y || count < 3 || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -289,11 +341,11 @@ scad_add_polygon lines = malloc(count * sizeof(int)); for (i=0; i<count-1; ++i) { - lines[i] = gmshModelOccAddLine(points[i], points[i+1], -1, &ierr); + lines[i] = gmshModelOccAddLine(points[i], points[i+1], -1, &ierr); ERR(gmsh_err_to_res_T(ierr)); } /*and the last line*/ - lines[count-1] = gmshModelOccAddLine(points[count-1], points[0], -1, &ierr); + lines[count-1] = gmshModelOccAddLine(points[count-1], points[0], -1, &ierr); ERR(gmsh_err_to_res_T(ierr)); loop = gmshModelOccAddCurveLoop(lines, count, -1, &ierr); @@ -311,15 +363,16 @@ scad_add_polygon } geom->gmsh_dimTags[0] = 2; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; if(points) free(points); if(lines) free(lines); return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -336,7 +389,7 @@ scad_add_box struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!xyz || !dxdydz) { + if(!xyz || !dxdydz || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -355,13 +408,14 @@ scad_add_box } geom->gmsh_dimTags[0] = 3; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -380,7 +434,7 @@ scad_add_cylinder struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!xyz || !axis || rad <= 0 || angle < 0 || angle > 2*PI) { + if(!xyz || !axis || rad <= 0 || angle < 0 || angle > 2*PI || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -400,13 +454,14 @@ scad_add_cylinder } geom->gmsh_dimTags[0] = 3; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -423,7 +478,7 @@ scad_add_sphere struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!xyz || rad <= 0) { + if(!xyz || rad <= 0 || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -442,13 +497,14 @@ scad_add_sphere } geom->gmsh_dimTags[0] = 3; geom->gmsh_dimTags[1] = gmsh_ID; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } goto exit; @@ -457,191 +513,204 @@ error: res_T scad_fuse_geometries (const char* name, - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove) + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry) { int* tagout = NULL; int** map = NULL; size_t* mapn = NULL; size_t tagoutn, mapnn, sz1, sz2; - int* data1; - int* data2; + int* data1 = NULL; + int* data2 = NULL; int ierr = 0; struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geom1 || !geom2 || !out_geometry) { + if(!geometries || !tools || !out_geometry) { res = RES_BAD_ARG; goto error; } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - sz1 = geom1->gmsh_dimTags_n; - sz2 = geom2->gmsh_dimTags_n; - data1 = geom1->gmsh_dimTags; - data2 = geom2->gmsh_dimTags; + 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 longuer used by any star-cad geometry */ gmshModelOccFuse(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn, - &mapnn, -1, remove, remove, &ierr); + &mapnn, -1, 0, 0, &ierr); ERR(gmsh_err_to_res_T(ierr)); ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; - if(remove) { /* FIXME: not sure of this! */ - remove_dimTags(geom1); - remove_dimTags(geom2); - } + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; + if(data1) free(data1); + if(data2) free(data2); if(mapn) free(mapn); if(map) free(map); return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } res_T scad_cut_geometries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove) + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry) { int* tagout = NULL; int** map = NULL; size_t* mapn = NULL; size_t tagoutn, mapnn, sz1, sz2; - int* data1; - int* data2; + int* data1 = NULL; + int* data2 = NULL; int ierr = 0; struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geom1 || !geom2 || !out_geometry) { + if(!geometries || !tools || !out_geometry) { res = RES_BAD_ARG; goto error; } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - sz1 = geom1->gmsh_dimTags_n; - sz2 = geom2->gmsh_dimTags_n; - data1 = geom1->gmsh_dimTags; - data2 = geom2->gmsh_dimTags; + 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 longuer used by any star-cad geometry */ gmshModelOccCut(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn, - &mapnn, -1, remove, remove, &ierr); + &mapnn, -1, 0, 0, &ierr); ERR(gmsh_err_to_res_T(ierr)); ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; - if(remove) { /* FIXME: not sure of this! */ - remove_dimTags(geom1); - remove_dimTags(geom2); - } + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; + if(data1) free(data1); + if(data2) free(data2); if(mapn) free(mapn); if(map) free(map); return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } res_T scad_intersect_geometries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove) + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry) { int* tagout = NULL; int** map = NULL; size_t* mapn = NULL; size_t tagoutn, mapnn, sz1, sz2; - int* data1; - int* data2; + int* data1 = NULL; + int* data2 = NULL; int ierr = 0; struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geom1 || !geom2 || !out_geometry) { + if(!geometries || !tools || !out_geometry) { res = RES_BAD_ARG; goto error; } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - sz1 = geom1->gmsh_dimTags_n; - sz2 = geom2->gmsh_dimTags_n; - data1 = geom1->gmsh_dimTags; - data2 = geom2->gmsh_dimTags; + 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 longuer used by any star-cad geometry */ gmshModelOccIntersect(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn, - &mapnn, -1, remove, remove, &ierr); + &mapnn, -1, 0, 0, &ierr); ERR(gmsh_err_to_res_T(ierr)); ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; - if(remove) { /* FIXME: not sure of this! */ - remove_dimTags(geom1); - remove_dimTags(geom2); - } + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; + if(data1) free(data1); + if(data2) free(data2); if(mapn) free(mapn); if(map) free(map); return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } res_T -scad_geometries_common_boundaries +scad_geometries_common_boundaries (const char* name, /* Can be NULL */ - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove) + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + struct scad_geometry** out_geometry) { int* tagout = NULL; int** map = NULL; size_t* mapn = NULL; size_t tagoutn, mapnn, sz1, sz2; - int* data1; - int* data2; + int* data1 = NULL; + int* data2 = NULL; int ierr = 0; int* bound1; int* bound2; @@ -649,21 +718,21 @@ scad_geometries_common_boundaries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geom1 || !geom2 || !out_geometry) { + if(!geometries || !tools || !out_geometry) { res = RES_BAD_ARG; goto error; } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - sz1 = geom1->gmsh_dimTags_n; - sz2 = geom2->gmsh_dimTags_n; - data1 = geom1->gmsh_dimTags; - data2 = geom2->gmsh_dimTags; + 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 longuer used by any star-cad geometry */ 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); @@ -675,13 +744,12 @@ scad_geometries_common_boundaries ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; - if(remove) { /* FIXME: not sure of this! */ - remove_dimTags(geom1); - remove_dimTags(geom2); - } + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; + if(data1) free(data1); + if(data2) free(data2); if(bound1) free(bound1); if(bound2) free(bound2); if(mapn) free(mapn); @@ -689,9 +757,13 @@ exit: return res; error: if(geom) { - SCAD(geometry_release(geom)); + CHK(RES_OK == geometry_release(geom)); geom = NULL; } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } @@ -713,7 +785,6 @@ scad_geometry_rotate } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } @@ -753,7 +824,6 @@ scad_geometry_extrude } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } @@ -769,7 +839,7 @@ scad_geometry_extrude /* keep only 3D entities */ /* TODO : NOT SURE OF THE CONCEPT */ for (i=0; i<tagoutn/2; ++i) { - if (tagout[2*i] == 3) extrude_sz += 2; + if (tagout[2*i] == 3) extrude_sz += 2; } extrude_data = malloc(extrude_sz * sizeof(int)); j = 0; @@ -782,14 +852,15 @@ scad_geometry_extrude } extrude_geom->gmsh_dimTags_n = extrude_sz; extrude_geom->gmsh_dimTags = extrude_data; + ERR(device_register_tags(extrude_geom)); exit: - if(out_geometry) *out_geometry = extrude_geom; - if (tagout) free(tagout); + *out_geometry = extrude_geom; + if(tagout) free(tagout); return res; error: if(extrude_geom) { - SCAD(geometry_release(extrude_geom)); + CHK(RES_OK == geometry_release(extrude_geom)); extrude_geom = NULL; } goto exit; @@ -813,7 +884,6 @@ scad_geometry_copy } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } @@ -827,6 +897,7 @@ scad_geometry_copy ERR(scad_geometry_create(name, copy)); (*copy)->gmsh_dimTags_n = sz2; (*copy)->gmsh_dimTags = data2; + ERR(device_register_tags(*copy)); exit: return res; @@ -850,7 +921,6 @@ scad_geometry_translate } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } @@ -868,56 +938,93 @@ error: } res_T -scad_geometries_fragment +scad_geometries_partition (const char* name, - struct scad_geometry* geom1, - struct scad_geometry* geom2, - struct scad_geometry** out_geometry, - const int remove) + struct scad_geometry** geometries, + const size_t geometries_count, + struct scad_geometry** tools, + const size_t tools_count, + const int allow_overlapping, + struct scad_geometry** out_geometry) { int* tagout = NULL; int** map = NULL; size_t* mapn = NULL; - size_t tagoutn, mapnn, sz1, sz2; - int* data1; - int* data2; + size_t tagoutn = 0, mapnn, sz1, sz2 = 0; + int* data1 = NULL; + int* data2 = NULL; int ierr = 0; struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geom1 || !geom2 || !out_geometry) { + if(!geometries || !out_geometry) { res = RES_BAD_ARG; goto error; } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - sz1 = geom1->gmsh_dimTags_n; - sz2 = geom2->gmsh_dimTags_n; - data1 = geom1->gmsh_dimTags; - data2 = geom2->gmsh_dimTags; + ERR(gather_tags(geometries, geometries_count, &data1, &sz1)); + if(tools) { + ERR(gather_tags(tools, tools_count, &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 */ gmshModelOccFragment(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn, - &mapnn, -1, remove, remove, &ierr); + &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]; + res = RES_BAD_ARG; + if(str_is_empty(&problem->name)) { + log_error(get_device(), "Unnamed geometry overlapping tools.\n"); + } else { + log_error(get_device(), "Geometry '%s' overlapping tools.\n", + str_cget(&problem->name)); + } + goto error; + } + } ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; - if(remove) { /* FIXME: not sure of this! */ - remove_dimTags(geom1); - remove_dimTags(geom2); - } + + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; + if(data1) free(data1); + if(data2) free(data2); if(mapn) free(mapn); if(map) free(map); return res; error: + if(geom) { + CHK(RES_OK == geometry_release(geom)); + geom = NULL; + } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } @@ -950,11 +1057,20 @@ scad_geometry_boundary ERR(scad_geometry_create(name, &geom)); geom->gmsh_dimTags_n = tagoutn; geom->gmsh_dimTags = tagout; + ERR(device_register_tags(geom)); exit: - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: + if(geom) { + CHK(RES_OK == geometry_release(geom)); + geom = NULL; + } + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } goto exit; } @@ -968,6 +1084,8 @@ scad_step_import int ierr; int* tagout = NULL; size_t tagoutn, i; + struct str strname; + int name_initialized = 0; res_T res = RES_OK; if(!filename) { @@ -976,38 +1094,41 @@ scad_step_import } ERR(check_device()); - if(get_device()->need_synchro) { ERR(scad_synchronize()); } - gmshModelOccImportShapes(filename, - &tagout, &tagoutn, - 1, - "step", - &ierr); + gmshModelOccImportShapes(filename, &tagout, &tagoutn, 1, "step", &ierr); ERR(gmsh_err_to_res_T(ierr)); *out_geometry = malloc(tagoutn/2 * sizeof(struct scad_geometry*)); + str_init(get_device()->allocator, &strname); + name_initialized = 1; for (i=0; i<tagoutn/2; ++i) { - struct str strname; - - str_init(get_device()->allocator, &strname); ERR(str_set(&strname, name)); - ERR(str_append_printf(&strname,"_%lu", (unsigned long)i)); + ERR(str_append_printf(&strname,"_%lu", (unsigned long)i)); ERR(scad_geometry_create(str_cget(&strname), &(*out_geometry)[i])); (*out_geometry)[i]->gmsh_dimTags_n = 2; (*out_geometry)[i]->gmsh_dimTags = malloc(2 * sizeof(int)); (*out_geometry)[i]->gmsh_dimTags[0] = tagout[2*i]; (*out_geometry)[i]->gmsh_dimTags[1] = tagout[2*i+1]; - str_release(&strname); + ERR(device_register_tags((*out_geometry)[i])); } *out_geometry_n = tagoutn/2; exit: + if(name_initialized) str_release(&strname); return res; error: + if(tagout) { + gmshModelOccRemove(tagout, tagoutn, 1, &ierr); + free(tagout); + } + if(out_geometry) { + free(out_geometry); + out_geometry = NULL; + } goto exit; } diff --git a/src/scad_geometry.h b/src/scad_geometry.h @@ -27,8 +27,8 @@ struct scad_geometry { struct str name; }; -extern LOCAL_SYM res_T -scad_geometry_release +LOCAL_SYM res_T +geometry_release (struct scad_geometry* geom); #endif