star-cad

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

commit e28310d88d073315b3a6352c7c31c1df4c05e110
parent 55496e24f8a6e32635c3d177a4e54e0d04605f0f
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 25 Nov 2022 16:29:51 +0100

Another try at geometry partition

Diffstat:
Msrc/scad.h | 28++++++++++++++--------------
Msrc/scad_geometry.c | 208++++++++++++++++++++++++++++++++++++++++---------------------------------------
2 files changed, 119 insertions(+), 117 deletions(-)

diff --git a/src/scad.h b/src/scad.h @@ -182,7 +182,7 @@ SCAD_API res_T scad_add_polygon (const char* name, /* Can be NULL */ void (*get_position)(const size_t ivert, double pos[2], void* data), - void* data, /* Custom data */ + void* data, /* Custom data; can be NULL if get_position don't use it */ const double z, const size_t count, /* size of x and y arrays */ struct scad_geometry** polygon); /* Can be NULL: no handler returned. */ @@ -216,10 +216,6 @@ scad_add_sphere const double radius, struct scad_geometry** sphere); /* Can be NULL: no handler returned. */ -SCAD_API res_T -scad_scene_mesh - (void); - /* Compute the boolean union (the fusion) of the geometries in `geometries' and * `tools'. */ SCAD_API res_T @@ -265,21 +261,25 @@ scad_geometries_common_boundaries struct scad_geometry** out_geometry); /* Compute the boolean fragments (general fuse) resulting from the - * intersection of every single geometry in `geometries' and the - * other geometries in `geometries' used as tools, making all interfaces + * intersection of the geometries in `geometries', making all interfaces * conformal. - * Geometries are considered one at a time against the other ones, producing one - * output by geometry in `geometries'. + * If overlapping is allowed `out_geometries' is constructed and the new + * geometries are created unnamed; if overlapping is not allowed + * `out_geometries' is expected to be NULL. * 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 - (char** names, /* Can be NULL */ - struct scad_geometry** geometries, + (struct scad_geometry** geometries, const size_t geometries_count, const int allow_overlapping, - struct scad_geometry** out_geometries); + struct scad_geometry** out_geometries); /* NULL if overlapping not allowed */ + +/* Same as above for the whole scene */ +SCAD_API res_T +scad_scene_partition + (void); SCAD_API res_T scad_fragment_geometries @@ -378,8 +378,8 @@ SCAD_API res_T /* FIXME remove this */ scad_run_ui (void); -SCAD_API res_T /* FIXME TEMPORARY */ -scad_scene_partition +SCAD_API res_T +scad_scene_mesh (void); SCAD_API res_T diff --git a/src/scad_geometry.c b/src/scad_geometry.c @@ -141,7 +141,6 @@ static res_T gather_tags (struct scad_geometry** geometries, const size_t geometries_count, - const size_t except, /* if not SIZE_MAX, this one is not gathered */ int** out_dimTags, size_t* out_dimTags_n) { @@ -154,7 +153,6 @@ gather_tags struct htable_tags_iterator it, end; ASSERT((geometries || !geometries_count) && (out_dimTags || !out_dimTags_n)); - ASSERT(except == SIZE_MAX || except < geometries_count); allocator = dev->allocator; htable_tags_init(allocator, &t2); @@ -162,7 +160,6 @@ gather_tags /* 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]; @@ -345,7 +342,7 @@ scad_geometry_get_mass ASSERT(geom->gmsh_dimTags_n % 2 == 0); count = geom->gmsh_dimTags_n / 2; - ERR(gather_tags(&geom, 1, SIZE_MAX, &data, &sz)); + ERR(gather_tags(&geom, 1, &data, &sz)); dim = data[0]; *mass = 0; @@ -385,9 +382,9 @@ scad_geometry_get_centerofmass *center_n = geom->gmsh_dimTags_n / 2; *center = (double*)malloc(*center_n * 3 * sizeof(double)); - - ERR(gather_tags(&geom, 1, SIZE_MAX, &data, &sz)); - + + ERR(gather_tags(&geom, 1, &data, &sz)); + for (i=0; i<*center_n; ++i) { double x, y, z; int ierr = 0; @@ -746,8 +743,8 @@ scad_fuse_geometries ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data1, &sz1)); - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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 */ @@ -810,8 +807,8 @@ scad_cut_geometries ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data1, &sz1)); - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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 */ @@ -874,8 +871,8 @@ scad_intersect_geometries ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data1, &sz1)); - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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 */ @@ -941,8 +938,8 @@ scad_geometries_common_boundaries ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data1, &sz1)); - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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 */ @@ -1267,8 +1264,7 @@ error: res_T scad_geometries_partition - (char** names, /* Can be NULL */ - struct scad_geometry** geometries, + (struct scad_geometry** geometries, const size_t geometries_count, const int allow_overlapping, struct scad_geometry** out_geometries) @@ -1284,33 +1280,36 @@ scad_geometries_partition 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) { + if(!geometries || !geometries_count || (allow_overlapping && !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)); + ERR(gather_tags(geometries, geometries_count, &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 */ + /* As a general principle, we don't remove gmsh objects directly; they are + * only removed from scad_geometry_delete when their tags are no longuer used + * by any star-cad geometry. + * Here we can safely use the remove flag in the non-overlapping case, as + * this ends in the same tags being reused for output. */ gmshModelOccFragment(data, sz, NULL, 0, &tagout, &tagoutn, &map, &mapn, - &mapnn, -1, 0, 0, &ierr); + &mapnn, -1, (allow_overlapping == 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 */ + get_device()->need_synchro = 1; + + /* Check first if there was an overlapping problem */ if(!allow_overlapping) { /* No overlapping means that each tag in geometries is translated into a * single tag in map */ @@ -1325,92 +1324,95 @@ scad_geometries_partition str_cget(&geometries[i]->name)); } } + /* Additionally, with the delete flag ON we expect the tags to remain + * unchanged in the non-overlapping case. */ + /*ASSERT(res != RES_OK || map[i][1] == data[2*i+1]);*/ } 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]; + } else { + struct mem_allocator* allocator = dev->allocator; + /* 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; - 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)); - } + ERR(htable_mappings_set(mn, &tag, &mapping)); } - /* Allocate result */ - n = htable_tags_size_get(&t2) + htable_tags_size_get(&t3); - dt = malloc(sizeof(*dt) * 2 * n); - if(!dt) { + + /* Create output geometries from mapping */ + geoms = calloc(geometries_count, sizeof(*geoms)); + if(!geoms) { 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); + htable_tags_init(allocator, &t2); + htable_tags_init(allocator, &t3); + ht_initialized = 1; + for(i = 0; i < geometries_count; i++) { + 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])); + /* Create geometry */ + ERR(scad_geometry_create(NULL, 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)); } - memcpy(out_geometries, geoms, geometries_count * sizeof(*geoms)); exit: for(i = 0; i < mapnn; i++) free(map[i]); @@ -1468,8 +1470,8 @@ scad_fragment_geometries ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data1, &sz1)); - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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 */ @@ -1528,7 +1530,7 @@ scad_geometry_boundary ERR(scad_synchronize()); } - ERR(gather_tags(geometries, geometries_count, SIZE_MAX, &data, &sz)); + ERR(gather_tags(geometries, geometries_count, &data, &sz)); gmshModelGetBoundary(data, sz, &tagout, &tagoutn, 1, 0, 0, &ierr); ERR(gmsh_err_to_res_T(ierr)); @@ -1661,7 +1663,7 @@ scad_geometry_normal goto error; } - ERR(gather_tags(&surface, 1, SIZE_MAX, &data, &sz)); + ERR(gather_tags(&surface, 1, &data, &sz)); for (i=0; sz/2; ++i) { double* coord; @@ -1728,7 +1730,7 @@ scad_geometry_dilate ERR(check_device(FUNC_NAME)); - ERR(gather_tags(&geom, 1, SIZE_MAX, &data, &sz)); + ERR(gather_tags(&geom, 1, &data, &sz)); gmshModelOccDilate(data, sz, SPLIT3(center), SPLIT3(scale), &ierr); ERR(gmsh_err_to_res_T(ierr));