star-cad

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

commit b1c61cf2548067d7ecb91381853e7a10e93eac35
parent d48339d151098d99249fd9499784c71a4f94c1af
Author: Benjamin Piaud <benjamin.piaud@meso-star.com>
Date:   Thu, 24 Nov 2022 13:35:57 +0100

Merge remote-tracking branch 'refs/remotes/origin/develop' into develop

Diffstat:
Mcmake/CMakeLists.txt | 5++++-
Msrc/scad.c | 44+++++++++++++++++++++++++++++++++-----------
Msrc/scad.h | 32++++++++++----------------------
Msrc/scad_geometry.c | 513+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/test1.c | 22++++------------------
Asrc/test_api.c | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_common.h | 1+
Asrc/test_export.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_partition.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 801 insertions(+), 246 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -23,7 +23,7 @@ option(NO_TEST "Disable the test" OFF) ################################################################################ # Check dependencies ################################################################################ -find_package(gmsh 4.9.5 EXACT REQUIRED) +find_package(gmsh 4.9.5 REQUIRED) find_package(RCMake 0.4.1 REQUIRED) find_package(RSys 0.12.1 REQUIRED) @@ -92,6 +92,9 @@ if(NOT NO_TEST) endfunction() new_test(test1) + new_test(test_api) + new_test(test_export) + new_test(test_partition) rcmake_copy_runtime_libraries(test) diff --git a/src/scad.c b/src/scad.c @@ -25,7 +25,6 @@ #include <rsys/str.h> #include <rsys/double3.h> #include <rsys/float3.h> -#include <rsys/stretchy_array.h> #include <stdio.h> @@ -241,6 +240,27 @@ error: } res_T +scad_scene_write + (const char* name) +{ + int ierr; + res_T res = RES_OK; + + if(!name) { + res = RES_BAD_ARG; + goto error; + } + + gmshWrite(name, &ierr); + ERR(gmsh_err_to_res_T(ierr)); + +exit: + return res; +error: + goto exit; +} + +res_T scad_stl_export (struct scad_geometry* geometry, const char* prefix, @@ -250,7 +270,6 @@ scad_stl_export int* allocated_dimTags = NULL; int* faces_dimTags = NULL; size_t faces_dimTags_n; - int* tags = NULL; size_t** nodeTags = NULL; size_t* nodeTags_n = NULL; double** coord = NULL; @@ -357,24 +376,23 @@ scad_stl_export exit: if(str_initialized) str_release(&filename); - if(allocated_dimTags) free(allocated_dimTags); - if(tags) sa_release(tags); + free(allocated_dimTags); if(nodeTags) { for(i = 0; i < faces_dimTags_n/2; i++) free(nodeTags[i]); free(nodeTags); } - if(nodeTags_n) free(nodeTags_n); + free(nodeTags_n); if(coord) { for(i = 0; i < faces_dimTags_n/2; i++) free(coord[i]); free(coord); } - if(coord_n) free(coord_n); + free(coord_n); if(pCoord) { for(i = 0; i < faces_dimTags_n/2; i++) free(pCoord[i]); free(pCoord); } - if(pCoord_n) free(pCoord_n); - if(dimTags) free(dimTags); + free(pCoord_n); + free(dimTags); return res; error: log_error(get_device(), "%s: could not export to STL -- %s\n", @@ -434,6 +452,8 @@ scad_stl_export_split if(data[0] == 2) { FOR_EACH(i, 0, sz/2) { ASSERT(data[2*i] == 2); + /* When upgrading to gmsh 4.11 the additional arg. name cannot be NULL; + * use "" instead */ group = gmshModelAddPhysicalGroup(2, &data[2*i+1], 1, -1, &ierr); ERR(gmsh_err_to_res_T(ierr)); ERR(str_copy(&filename, &filename_root)); @@ -457,6 +477,8 @@ scad_stl_export_split ERR(gmsh_err_to_res_T(ierr)); FOR_EACH(i, 0, tagoutn/2){ + /* When upgrading to gmsh 4.11 the additional arg. name cannot be NULL; + * use "" instead */ group = gmshModelAddPhysicalGroup(2, tagout + 2*i+1, 1, -1, &ierr); ERR(gmsh_err_to_res_T(ierr)); ERR(str_copy(&filename, &filename_root)); @@ -476,7 +498,7 @@ exit: str_release(&filename_root); str_release(&filename); } - if(tagout) free(tagout); + free(tagout); return res; error: goto exit; @@ -529,9 +551,9 @@ scad_scene_partition } gmshModelOccSynchronize(&ierr); ERR(gmsh_err_to_res_T(ierr)); - + exit: - if(dimTags) free(dimTags); + free(dimTags); return res; error: goto exit; diff --git a/src/scad.h b/src/scad.h @@ -252,37 +252,21 @@ scad_geometries_common_boundaries struct scad_geometry** out_geometry); /* Compute the boolean fragments (general fuse) resulting from the - * intersection of the geometries in `geometries' and `tools', 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. */ -SCAD_API res_T -scad_geometries_partition - (const char* name, /* Can be NULL */ - 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); - -/* 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 */ +scad_geometries_partition + (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 @@ -373,6 +357,10 @@ scad_stl_export_split const int binary); /* File format */ +SCAD_API res_T +scad_scene_write + (const char* name); + SCAD_API res_T /* FIXME remove this */ scad_run_ui (void); 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 ******************************************************************************/ @@ -37,27 +51,28 @@ struct coord_pair { }; static res_T -scad_geometry_create - (const char* name, - struct scad_geometry** out_geometry) +geom_set_name + (struct scad_geometry* geom, + const char* name) { - res_T res = RES_OK; - struct str str_name; - struct scad_geometry* geom = NULL; struct scad_device* dev = get_device(); - char one = 1; + struct str str_name; + int name_initialized = 0; + int same_name; + res_T res = RES_OK; - ASSERT(out_geometry); + ASSERT(geom); - 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"); + log_error(get_device(), "Geometry name \"\" is invalid.\n"); goto error; } + str_init(dev->allocator, &str_name); + name_initialized = 1; ERR(str_set(&str_name, name)); - if(name && htable_names_find(&dev->geometry_names, &str_name)) { + if(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", @@ -66,24 +81,53 @@ scad_geometry_create } } + same_name = (!name && str_is_empty(&geom->name)) + || (name && 0 == strcmp(name, str_cget(&geom->name))); + + if(!same_name) { + size_t n = htable_names_erase(&dev->geometry_names, &geom->name); + ASSERT((n == 1) == !str_is_empty(&geom->name)); (void)n; + } + + if(name) { + str_set(&geom->name, name); + ERR(htable_names_set(&dev->geometry_names, &geom->name, &geom)); + } else { + str_clear(&geom->name); + } + +exit: + if(name_initialized) str_release(&str_name); + return res; +error: + goto exit; +} + +static res_T +scad_geometry_create + (const char* name, + struct scad_geometry** out_geometry) +{ + res_T res = RES_OK; + struct scad_geometry* geom = NULL; + struct scad_device* dev = get_device(); + char one = 1; + + ASSERT(out_geometry); + geom = (struct scad_geometry*)MEM_CALLOC(dev->allocator, 1, sizeof(*geom)); if(!geom) { res = RES_MEM_ERR; goto error; } - ERR(htable_geometries_set(&dev->allgeom, &geom, &one)); - str_init(dev->allocator, &geom->name); + ERR(htable_geometries_set(&dev->allgeom, &geom, &one)); + ERR(geom_set_name(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: - str_release(&str_name); - if(out_geometry) *out_geometry = geom; + *out_geometry = geom; return res; error: if(geom) { @@ -102,128 +146,70 @@ 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; - } - tags = malloc(sizeof(*tags) * sz); - if(!tags) { - res = RES_MEM_ERR; - goto error; - } - for(i = 0, c = 0; i < geometries_count; i++) { + 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++, c++) { - tags[c] = geometries[i]->gmsh_dimTags[j]; + 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)); } } - *out_dimTags_n = c; - *out_dimTags = tags; - -exit: - return res; -error: - if(tags) free(tags); - goto exit; -} - -static res_T -scad_geometries_partition_core - (const char* name, - struct scad_geometry** geometries, - const size_t geometries_count, - const size_t except, - 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 = 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(!geometries || !out_geometry) { - res = RES_BAD_ARG; + /* 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; } - ERR(check_device(FUNC_NAME)); - if(get_device()->need_synchro) { - ERR(scad_synchronize()); - } - - ERR(gather_tags(geometries, geometries_count, except, &data1, &sz1)); - if(tools) { - ERR(gather_tags(tools, tools_count, SIZE_MAX, &data2, &sz2)); + 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); } - - /* 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]; - 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; - } + 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); - ERR(scad_geometry_create(name, &geom)); - geom->gmsh_dimTags_n = tagoutn; - geom->gmsh_dimTags = tagout; - tagout = NULL; /* Prevent possible double free */ - - ERR(device_register_tags(geom)); + *out_dimTags_n = c; + *out_dimTags = dimTags; exit: - if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(mapn) free(mapn); - if(map) free(map); + htable_tags_release(&t2); + htable_tags_release(&t3); return res; error: - if(geom) { - CHK(RES_OK == geometry_release(geom)); - geom = NULL; - } - if(tagout) { - gmshModelOccRemove(tagout, tagoutn, 1, &ierr); - free(tagout); - } + free(dimTags); goto exit; } + /******************************************************************************* * Local functions ******************************************************************************/ @@ -290,9 +276,6 @@ scad_scene_clear ERR(check_device(FUNC_NAME)); - /* FIXME: not sure remove is needed. */ - gmshModelRemove(&ierr); - ERR(gmsh_err_to_res_T(ierr)); gmshClear(&ierr); ERR(gmsh_err_to_res_T(ierr)); @@ -333,8 +316,8 @@ scad_geometry_get_name if(!geom || !name) goto error; ERR(check_device(FUNC_NAME)); - - *name = malloc((strlen(str_cget(&geom->name)) + 1)*sizeof(char)); + + *name = malloc((strlen(str_cget(&geom->name)) + 1)*sizeof(char)); strcpy(*name, str_cget(&geom->name)); exit: @@ -363,7 +346,7 @@ scad_geometry_get_mass count = geom->gmsh_dimTags_n / 2; ERR(gather_tags(&geom, 1, SIZE_MAX, &data, &sz)); - + dim = data[0]; *mass = 0; for (i=0; i<count; ++i) { @@ -584,8 +567,8 @@ scad_add_polygon exit: if(out_geometry) *out_geometry = geom; - if(points) free(points); - if(lines) free(lines); + free(points); + free(lines); return res; error: if(geom) { @@ -753,7 +736,7 @@ scad_fuse_geometries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geometries || !tools || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -781,10 +764,10 @@ scad_fuse_geometries exit: if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(mapn) free(mapn); - if(map) free(map); + free(data1); + free(data2); + free(mapn); + free(map); return res; error: if(geom) { @@ -817,7 +800,7 @@ scad_cut_geometries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geometries || !tools || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -845,10 +828,10 @@ scad_cut_geometries exit: if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(mapn) free(mapn); - if(map) free(map); + free(data1); + free(data2); + free(mapn); + free(map); return res; error: if(geom) { @@ -881,7 +864,7 @@ scad_intersect_geometries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geometries || !tools || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -909,10 +892,10 @@ scad_intersect_geometries exit: if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(mapn) free(mapn); - if(map) free(map); + free(data1); + free(data2); + free(mapn); + free(map); return res; error: if(geom) { @@ -948,7 +931,7 @@ scad_geometries_common_boundaries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geometries || !tools || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -980,12 +963,12 @@ scad_geometries_common_boundaries exit: if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(bound1) free(bound1); - if(bound2) free(bound2); - if(mapn) free(mapn); - if(map) free(map); + free(data1); + free(data2); + free(bound1); + free(bound2); + free(mapn); + free(map); return res; error: if(geom) { @@ -1050,7 +1033,7 @@ scad_geometry_extrude struct scad_geometry* extrude_geom = NULL; res_T res = RES_OK; - if(!geom || !dxdydz){ + if(!geom || !dxdydz || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -1063,7 +1046,7 @@ scad_geometry_extrude sz = geom->gmsh_dimTags_n; data = geom->gmsh_dimTags; gmshModelOccExtrude(data, sz, SPLIT3(dxdydz), &tagout, &tagoutn, - NULL, 0, NULL, 0, 0 , &ierr); + NULL, 0, NULL, 0, 0, &ierr); get_device()->need_synchro = 1; ERR(gmsh_err_to_res_T(ierr)); @@ -1094,7 +1077,7 @@ scad_geometry_extrude exit: if(out_geometry) *out_geometry = extrude_geom; - if(tagout) free(tagout); + free(tagout); return res; error: if(extrude_geom) { @@ -1108,7 +1091,7 @@ res_T scad_geometry_explode (const struct scad_geometry* geom, const char* prefix_name, /* Can be NULL */ - struct scad_geometry*** out_geometry, + struct scad_geometry*** out_geometry, size_t* out_geometry_n) { res_T res = RES_OK; @@ -1162,7 +1145,7 @@ scad_geometry_explode ERR(device_register_tags(geom_array[i])); } - + exit: if(out_geometry_n) *out_geometry_n = sz/2 ; if(out_geometry) *out_geometry = geom_array; @@ -1235,16 +1218,14 @@ scad_geometry_rename { res_T res = RES_OK; - if(!geom){ + if(!geom) { res = RES_BAD_ARG; goto error; } ERR(check_device(FUNC_NAME)); - if(!name) - str_clear(&geom->name); - else ERR(str_set(&geom->name, name)); + ERR(geom_set_name(geom, name)); exit: return res; @@ -1285,33 +1266,177 @@ error: } res_T -scad_geometries_partition_one - (const char* name, /* 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) -{ - 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 scad_geometries_partition - (const char* name, + (char** names, /* Can be NULL */ 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) + struct scad_geometry** out_geometries) { - return scad_geometries_partition_core(name, geometries, geometries_count, - SIZE_MAX, tools, tools_count, 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 @@ -1333,7 +1458,7 @@ scad_fragment_geometries struct scad_geometry* geom = NULL; res_T res = RES_OK; - if(!geometries || !tools || !out_geometry) { + if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) { res = RES_BAD_ARG; goto error; } @@ -1361,10 +1486,10 @@ scad_fragment_geometries exit: if(out_geometry) *out_geometry = geom; - if(data1) free(data1); - if(data2) free(data2); - if(mapn) free(mapn); - if(map) free(map); + free(data1); + free(data2); + free(mapn); + free(map); return res; error: if(geom) { @@ -1444,7 +1569,7 @@ scad_step_import struct scad_geometry** geom_array = NULL; res_T res = RES_OK; - if(!filename) { + if(!filename || !name || !out_geometry || !out_geometry_n) { res = RES_BAD_ARG; goto error; } @@ -1524,7 +1649,7 @@ scad_geometry_normal res = RES_BAD_ARG; goto error; } - + ERR(check_device(FUNC_NAME)); if (geom->gmsh_dimTags[0] == 2) { @@ -1535,7 +1660,7 @@ scad_geometry_normal res = RES_BAD_ARG; goto error; } - + ERR(gather_tags(&surface, 1, SIZE_MAX, &data, &sz)); for (i=0; sz/2; ++i) { @@ -1555,7 +1680,7 @@ scad_geometry_normal &coord, &coord_n, &ierr); ERR(gmsh_err_to_res_T(ierr)); - + if (d3_eq_eps(p, coord, 1e-6)) { gmshModelGetNormal(data[2*i + 1], pcoord, pcoord_n, &normals, &normals_n, &ierr); @@ -1577,8 +1702,8 @@ scad_geometry_normal } exit: - *out_geometry = out; - if (data) free(data); + if(out_geometry) *out_geometry = out; + free(data); if (surface) scad_geometry_delete(surface); return res; error: @@ -1600,7 +1725,7 @@ scad_geometry_dilate res = RES_BAD_ARG; goto error; } - + ERR(check_device(FUNC_NAME)); ERR(gather_tags(&geom, 1, SIZE_MAX, &data, &sz)); diff --git a/src/test1.c b/src/test1.c @@ -35,7 +35,6 @@ main(int argc, char* argv[]) struct scad_geometry* geom2 = NULL; struct scad_geometry* cyl = NULL; struct scad_geometry* tmp1 = NULL; - struct scad_geometry* tmp2 = NULL; struct scad_geometry* tmp3 = NULL; struct scad_geometry* f1 = NULL; struct scad_geometry* f2 = NULL; @@ -43,7 +42,6 @@ main(int argc, char* argv[]) struct scad_geometry* geoms[2]; struct scad_geometry* tools[5]; struct mem_allocator allocator; - struct scad_options options = SCAD_DEFAULT_OPTIONS__; (void)argc; (void)argv; @@ -51,23 +49,15 @@ main(int argc, char* argv[]) OK(scad_initialize(NULL, &allocator, 1)); - options.Misc.Step = 1; - options.Misc.SynchronizeOnRunUI = 1; - OK(scad_set_options(&options)); - OK(scad_add_cylinder("c1", p1, d1, 2, PI, &geom1)); OK(scad_add_box("b1", p2, d2, &geom2)); geoms[0] = geom1; geoms[1] = geom2; - BAD(scad_geometries_partition(NULL, geoms, 2, NULL, 0, 0, &tmp1)); - OK(scad_geometries_partition(NULL, geoms, 2, NULL, 0, 1, &tmp1)); + BAD(scad_geometries_partition(NULL, NULL, 0, 0, &tmp1)); + OK(scad_geometries_partition(NULL, geoms, 2, 1, &tmp1)); OK(scad_geometry_delete(tmp1)); OK(scad_cut_geometries("cut_c1", &geom1, 1, & geom2, 1, &tmp1)); - OK(scad_geometries_partition("tmp2", &tmp1, 1, &geom2, 1, 1, &tmp2)); - OK(scad_geometry_delete(tmp2)); - - OK(scad_geometries_partition("tmp2", &tmp1, 1, &geom2, 1, 0, &tmp2)); OK(scad_add_cylinder("cyl", p1, d1, 1, 2*PI, &cyl)); @@ -78,9 +68,9 @@ main(int argc, char* argv[]) tools[0] = geom2; tools[1] = tmp1; - tools[2] = tmp2; + tools[2] = geom1; tools[3] = f1; - BAD(scad_geometries_partition(NULL, &geom1, 1, tools, 4, 0, &tmp3)); + BAD(scad_geometries_partition(NULL, tools, 4, 0, &tmp3)); /* OK(scad_scene_mesh()); */ OK(scad_stl_export(geom1, NULL, 1)); @@ -90,7 +80,6 @@ main(int argc, char* argv[]) /* OK(scad_stl_export(f1, NULL, 1)); */ /* OK(scad_stl_export(f2, NULL, 0)); */ -exit: OK(scad_finalize()); check_memory_allocator(&allocator); @@ -98,7 +87,4 @@ exit: CHK(mem_allocated_size() == 0); return (res == RES_OK) ? EXIT_SUCCESS : EXIT_FAILURE; -error: - fprintf(stderr, "Something failed.\n"); - goto exit; } diff --git a/src/test_api.c b/src/test_api.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "scad.h" +#include "scad_geometry.h" +#include "test_common.h" + +#include <rsys/rsys.h> +#include <rsys/math.h> +#include <rsys/mem_allocator.h> +#include <rsys/logger.h> + +#include <stdlib.h> +#include <stdio.h> + +static void +get_position + (const size_t ivert, double pos[2], void* data) +{ + double* coord = data; + ASSERT(pos && coord); + pos[0] = coord[2*ivert]; + pos[1] = coord[1+2*ivert]; + +} + +int +main(int argc, char* argv[]) +{ + res_T res = RES_OK; + double p1[3] = {0, 0, 0}; + double p2[3] = {0.25, 0.25, 0.8}; + double d1[3] = {1, 1, 1}; + double coord[] = {0, 1.6, 0.5, 0.9, 0.8, 0.6}; + struct scad_geometry* geom1 = NULL; + struct scad_geometry* geom2 = NULL; + struct scad_geometry* geom = NULL; + struct scad_geometry** geom_array = NULL; + struct scad_geometry* geoms[2]; + struct mem_allocator allocator; + struct logger logger; + size_t c; + + (void)argc; (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(logger_init(&allocator, &logger)); + + /* cannot call any API function before a successful call to scad_initialize */ + BAD(scad_finalize()); + BAD(scad_set_options(NULL)); + BAD(scad_synchronize()); + BAD(scad_scene_clear()); + BAD(scad_add_rectangle(NULL, p1, d1, &geom)); + BAD(scad_add_disk(NULL, p1, 1, &geom)); + BAD(scad_add_polygon(NULL, get_position, coord, 0, 3, &geom)); + BAD(scad_add_box(NULL, p1, d1, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 2, 1, &geom)); + BAD(scad_add_sphere(NULL, p1, 1, &geom)); + BAD(scad_step_import("test.step", NULL, &geom_array, &c)); + BAD(scad_scene_mesh()); + BAD(scad_run_ui()); + + /* cannot call any API function after a successful call to scad_finalize */ + OK(scad_initialize(&logger, &allocator, 3)); + OK(scad_finalize()); + + BAD(scad_finalize()); + BAD(scad_set_options(NULL)); + BAD(scad_synchronize()); + BAD(scad_scene_clear()); + BAD(scad_add_rectangle(NULL, p1, d1, &geom)); + BAD(scad_add_disk(NULL, p1, 1, &geom)); + BAD(scad_add_polygon(NULL, get_position, coord, 0, 3, &geom)); + BAD(scad_add_box(NULL, p1, d1, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 2, 1, &geom)); + BAD(scad_add_sphere(NULL, p1, 1, &geom)); + BAD(scad_step_import("test.step", NULL, &geom_array, &c)); + BAD(scad_scene_mesh()); + BAD(scad_run_ui()); + + BAD(scad_initialize(&logger, &allocator, 4)); + BAD(scad_initialize(&logger, &allocator, -1)); + + OK(scad_initialize(&logger, &allocator, 3)); + OK(scad_add_sphere("sphere 1", p1, .1, &geom1)); + OK(scad_add_sphere(NULL, p2, .2, &geom2)); + geoms[0] = geom1; + geoms[1] = geom2; + + OK(scad_add_sphere(NULL, p1, .1, &geom)); + BAD(scad_geometry_delete(NULL)); + OK(scad_geometry_delete(geom)); + + BAD(scad_geometry_get_count(NULL, &c)); + BAD(scad_geometry_get_count(geom1, NULL)); + OK(scad_geometry_get_count(geom1, &c)); + + BAD(scad_add_rectangle(NULL, NULL, d1, &geom)); + BAD(scad_add_rectangle(NULL, p1, NULL, &geom)); + BAD(scad_add_rectangle(NULL, p1, d1, NULL)); + BAD(scad_add_rectangle("sphere 1", p1, d1, &geom)); /* Name already used */ + OK(scad_add_rectangle(NULL, p1, d1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_add_disk(NULL, NULL, 1, &geom)); + BAD(scad_add_disk(NULL, p1, 0, &geom)); + BAD(scad_add_disk(NULL, p1, 1, NULL)); + OK(scad_add_disk(NULL, p1, 1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_add_polygon(NULL, NULL, coord, 0, 3, &geom)); + BAD(scad_add_polygon(NULL, get_position, coord, 0, 2, &geom)); + BAD(scad_add_polygon(NULL, get_position, coord, 0, 2, &geom)); + BAD(scad_add_polygon(NULL, get_position, coord, 0, 3, NULL)); + OK(scad_add_polygon(NULL, get_position, coord, 0, 3, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_add_box(NULL, NULL, d1, &geom)); + BAD(scad_add_box(NULL, p1, NULL, &geom)); + BAD(scad_add_box(NULL, p1, d1, NULL)); + OK(scad_add_box(NULL, p1, d1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_add_cylinder(NULL, NULL, d1, 2, 1, &geom)); + BAD(scad_add_cylinder(NULL, p1, NULL, 2, 1, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 0, 1, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 2, -1, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 2, 3*PI, &geom)); + BAD(scad_add_cylinder(NULL, p1, d1, 2, 1, NULL)); + OK(scad_add_cylinder(NULL, p1, d1, 2, 1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_add_sphere(NULL, NULL, 1, &geom)); + BAD(scad_add_sphere(NULL, p1, 0, &geom)); + BAD(scad_add_sphere(NULL, p1, 1, NULL)); + OK(scad_add_sphere(NULL, p1, 1, &geom)); + OK(scad_geometry_delete(geom)); + + /* BAD(scad_fuse_geometries(NULL, NULL, 0, geoms, 2, &geom)); */ + BAD(scad_fuse_geometries(NULL, geoms, 2, NULL, 0, &geom)); + BAD(scad_fuse_geometries(NULL, NULL, 1, &geom2, 1, &geom)); + BAD(scad_fuse_geometries(NULL, &geom1, 1, NULL, 1, &geom)); + BAD(scad_fuse_geometries(NULL, &geom1, 1, &geom2, 1, NULL)); + OK(scad_fuse_geometries(NULL, &geom1, 1, &geom2, 1, &geom)); + OK(scad_geometry_delete(geom)); + + /* BAD(scad_cut_geometries(NULL, NULL, 0, geoms, 2, &geom)); */ + BAD(scad_cut_geometries(NULL, geoms, 2, NULL, 0, &geom)); + BAD(scad_cut_geometries(NULL, NULL, 1, &geom2, 1, &geom)); + BAD(scad_cut_geometries(NULL, &geom1, 1, NULL, 1, &geom)); + BAD(scad_cut_geometries(NULL, &geom1, 1, &geom2, 1, NULL)); + OK(scad_cut_geometries(NULL, &geom1, 1, &geom2, 1, &geom)); + OK(scad_geometry_delete(geom)); + + /* BAD(scad_intersect_geometries(NULL, NULL, 0, geoms, 2, &geom)); */ + BAD(scad_intersect_geometries(NULL, geoms, 2, NULL, 0, &geom)); + BAD(scad_intersect_geometries(NULL, NULL, 1, &geom2, 1, &geom)); + BAD(scad_intersect_geometries(NULL, &geom1, 1, NULL, 1, &geom)); + BAD(scad_intersect_geometries(NULL, &geom1, 1, &geom2, 1, NULL)); + OK(scad_intersect_geometries(NULL, &geom1, 1, &geom2, 1, &geom)); + OK(scad_geometry_delete(geom)); + + /* BAD(scad_geometries_common_boundaries(NULL, NULL, 0, geoms, 2, &geom)); */ + BAD(scad_geometries_common_boundaries(NULL, geoms, 2, NULL, 0, &geom)); + BAD(scad_geometries_common_boundaries(NULL, NULL, 1, &geom2, 1, &geom)); + BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, NULL, 1, &geom)); + BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, NULL)); + OK(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_geometries_partition(NULL, NULL, 2, 1, geoms)); + BAD(scad_geometries_partition(NULL, geoms, 0, 1, geoms)); + BAD(scad_geometries_partition(NULL, geoms, 2, 1, NULL)); + OK(scad_geometries_partition(NULL, geoms, 2, 1, geoms)); + OK(scad_geometry_delete(geom)); + + BAD(scad_geometry_boundary(NULL, NULL, 0, &geom)); + BAD(scad_geometry_boundary(NULL, &geom1, 1, NULL)); + OK(scad_geometry_boundary(NULL, &geom1, 1, &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_geometry_copy(NULL, NULL, &geom)); + BAD(scad_geometry_copy(geom1, NULL, NULL)); + BAD(scad_geometry_copy(geom1, "sphere 1", NULL)); /* Name already in use */ + OK(scad_geometry_copy(geom1, "Sphere 1", &geom)); + OK(scad_geometry_delete(geom)); + + BAD(scad_geometry_rename(NULL, NULL)); + BAD(scad_geometry_rename(geom2, "sphere 1")); /* Name already in use */ + OK(scad_geometry_rename(geom2, NULL)); + + BAD(scad_geometry_translate(NULL, d1)); + BAD(scad_geometry_translate(geom1, NULL)); + OK(scad_geometry_translate(geom1, d1)); + + BAD(scad_geometry_rotate(NULL, p1, d1, 1)); + BAD(scad_geometry_rotate(geom1, NULL, d1, 1)); + BAD(scad_geometry_rotate(geom1, p1, NULL, 1)); + OK(scad_geometry_rotate(geom1, p1, d1, 1)); + + BAD(scad_geometry_extrude(NULL, NULL, d1, &geom)); + BAD(scad_geometry_extrude(geom1, NULL, NULL, &geom)); + BAD(scad_geometry_extrude(geom1, NULL, d1, NULL)); +#if 0 + /* Crash!? */ + OK(scad_geometry_extrude(geom1, NULL, d1, &geom)); + OK(scad_geometry_delete(geom)); +#endif + + BAD(scad_scene_write(NULL)); + ERR(scad_scene_write("")); + OK(scad_scene_write("/tmp/test.step")); + + BAD(scad_step_import(NULL, "step", &geom_array, &c)); + BAD(scad_step_import("/tmp/test.step", NULL, &geom_array, &c)); + BAD(scad_step_import("/tmp/test.step", "step", NULL, &c)); + BAD(scad_step_import("/tmp/test.step", "step", &geom_array, NULL)); + ERR(scad_step_import("dont_exist.step", "step", &geom_array, &c)); + OK(scad_step_import("/tmp/test.step", "step", &geom_array, &c)); + + BAD(scad_stl_export(NULL, NULL, 0)); + BAD(scad_stl_export(geom2, NULL, 0)); /* geom2 has no name */ + OK(scad_stl_export(geom2, "/tmp/test", 0)); + OK(scad_stl_export(geom1, NULL, 0)); + + BAD(scad_stl_export_split(NULL, NULL, 0)); + BAD(scad_stl_export_split(geom2, NULL, 0)); /* geom2 has no name */ + OK(scad_stl_export_split(geom2, "/tmp/test", 0)); + OK(scad_stl_export_split(geom1, NULL, 0)); + + logger_release(&logger); + OK(scad_finalize()); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + + return (res == RES_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/test_common.h b/src/test_common.h @@ -24,6 +24,7 @@ #define OK(Expr) CHK(RES_OK == (Expr)) #define BAD(Expr) CHK(RES_BAD_ARG == (Expr)) +#define ERR(Expr) CHK(RES_OK != (Expr)) static void check_memory_allocator(struct mem_allocator* allocator) { diff --git a/src/test_export.c b/src/test_export.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "scad.h" +#include "scad_geometry.h" +#include "test_common.h" + +#include <rsys/rsys.h> +#include <rsys/math.h> +#include <rsys/mem_allocator.h> +#include <rsys/logger.h> + +#include <stdlib.h> + +int +main(int argc, char* argv[]) +{ + res_T res = RES_OK; + double p1[3] = {0, 0, 0}; + double p2[3] = {4.25, 4.25, 4.8}; + double d1[3] = {1, 1, 1}; + struct scad_geometry* rectangle = NULL; + struct scad_geometry* cube = NULL; + struct scad_geometry* cube2 = NULL; + struct scad_geometry* geoms[2]; + struct mem_allocator allocator; + struct logger logger; + + (void)argc; (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(logger_init(&allocator, &logger)); + logger_release(&logger); + OK(scad_initialize(&logger, &allocator, 3)); + + OK(scad_add_rectangle("rectangle", p1, d1, &rectangle)); + OK(scad_add_box("cube", p1, d1, &cube)); + OK(scad_add_box(NULL, p2, d1, geoms+1)); + + geoms[0] = cube; + OK(scad_fuse_geometries("cube2", geoms, 1, geoms+1, 1, &cube2)); + + OK(scad_scene_mesh()); + + OK(scad_stl_export(rectangle, NULL, 0)); + OK(scad_stl_export(rectangle, "bin_rectangle", 1)); + + OK(scad_stl_export(cube, NULL, 0)); + OK(scad_stl_export(cube, "bin_cube", 1)); + + OK(scad_stl_export(cube2, NULL, 0)); + OK(scad_stl_export(cube2, "bin_cube2", 1)); + + OK(scad_finalize()); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + + return (res == RES_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/test_partition.c b/src/test_partition.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L + +#include "scad.h" +#include "scad_geometry.h" +#include "test_common.h" + +#include <rsys/rsys.h> +#include <rsys/math.h> +#include <rsys/mem_allocator.h> +#include <rsys/logger.h> +#include <rsys/double3.h> + +#include <stdlib.h> +#include <stdio.h> + +static res_T +two_geoms + (double x, + const int allow_overlapping, + struct mem_allocator* allocator, + struct logger* logger) +{ + double p0[3] = {0, 0, 2}; + double d0[3] = {1, 1, 1}; + double p1[3] = {0, 0, 0}; + double d1[3] = {1, 1, 1}; + double p2[3]; + double d2[3] = {0.5, 0.5, 0.5}; + struct scad_geometry* geoms[2]; + struct scad_geometry* tmp[2]; + struct scad_geometry* pgeoms[2]; + char name[64]; + res_T res; + + OK(scad_initialize(logger, allocator, 3)); + + /* set position for cube #2 */ + d3(p2, x, 0.25, 0.25); + + OK(scad_add_box("cube0", p0, d0, tmp)); + OK(scad_add_box("cube1", p1, d1, tmp+1)); + + OK(scad_fuse_geometries("cubes", tmp, 1, tmp+1, 1, geoms)); + OK(scad_add_box("cube2", p2, d2, geoms+1)); + + res = scad_geometries_partition(NULL, geoms, 2, allow_overlapping, pgeoms); + if(res != RES_OK) goto end; + + OK(scad_scene_mesh()); + + snprintf(name, sizeof(name), "part_%g_1", x); + OK(scad_stl_export(pgeoms[0], name, 0)); + snprintf(name, sizeof(name), "part_%g_2", x); + OK(scad_stl_export(pgeoms[1], name, 1)); + +end: + OK(scad_finalize()); + return res; +} + +int +main(int argc, char* argv[]) +{ + struct mem_allocator allocator; + struct logger logger; + res_T res = RES_OK; + + (void)argc; (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(logger_init(&allocator, &logger)); + + /* First with distant geometries */ + OK(two_geoms(1.1, 0, &allocator, &logger)); + + /* First with contacting geometries */ + OK(two_geoms(1, 0, &allocator, &logger)); + + /* First with overlapping geometries */ + BAD(two_geoms(0.9, 0, &allocator, &logger)); + OK(two_geoms(0.9, 1, &allocator, &logger)); + + logger_release(&logger); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + + return (res == RES_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +}