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