commit eca24493f249ca8cb459814e53236b227489c90a
parent 63e24b5c7dd1b4dcd181559e418c09ac6026e1a9
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 10 Oct 2025 11:00:46 +0200
Merge branch 'release_0.6'
Diffstat:
17 files changed, 3494 insertions(+), 1060 deletions(-)
diff --git a/Makefile b/Makefile
@@ -131,7 +131,8 @@ TEST_SRC =\
src/test_export2.c\
src/test_lifetime.c\
src/test_partition.c\
- src/test_periodic.c
+ src/test_periodic.c\
+ src/test_sync.c
TEST_OBJ = $(TEST_SRC:.c=.o)
TEST_DEP = $(TEST_SRC:.c=.d)
@@ -185,5 +186,6 @@ test_export2 \
test_lifetime \
test_partition \
test_periodic \
+test_sync \
: config.mk scad-local.pc $(LIBNAME)
$(CC) $(CFLAGS_EXE) -o $@ src/$@.o $(LDFLAGS_EXE) $(SCAD_LIBS) $(RSYS_LIBS) -lm
diff --git a/README.md b/README.md
@@ -25,6 +25,39 @@ Edit config.mk as needed, then run:
## Release notes
+### Version 0.6
+
+- Add `scad_add_cone' and `scad_add_torus' API calls.
+- API changes for geometry creation: geometry name is no longer provided to the
+ various add_<something> functions, that now create unnamed geometries; instead
+ names have to be set after geometry creation through `scad_geometry_set_name'.
+- API change for `scad_geometries_boundaries' and
+ `scad_geometries_common_boundaries': now return a list of geometries
+ (that could be grouped through `scad_collect_geometries'); used to return a
+ single geometry containing the (possibly empty) boundary elements (that could
+ be ungrouped using `scad_geometry_explode').
+- API uniformization (involving args order, naming, etc.).
+- Fix geometry naming. Now get_name returns NULL if name was set to NULL or
+ let unset (used to return ""). Allow to set same name again (to the same
+ geometry) without triggering an error.
+- Fix `scad_geometry_get_closest_point'. The returned point was not correct.
+- Fix `scad_geometry_get_normal' to get the normal at the geometry closest
+ point, fixing a memleak in the process.
+- Fix `scad_scene_clear' (geometries with multiple references where not
+ released).
+- Fix `scad_geometries_common_boundaries'. Used to trigger OccIntersect that, as
+ a side effet, partitionned geometries.
+- Fix `scad_step_import' (arguments where inverted).
+- Change `scad_geometry_get_centerofmass'. Now returns the unique center of mass
+ of all the entities involved in the geometry, regardless of their count (used
+ to return one center of mass per entity in the geometry).
+- Rework the auto-sync feature (that manages sync events between gmsh and
+ Open Cascade); this should greatly improve performance.
+- Rename enum members in capital letters.
+- Upgrade gmsh dependency (to 1.14.1) and Open-Cascade dependency (to 7.9.1).
+- Improve code robustness.
+- Improve tests.
+
### Version 0.5.2
- Fix a file name in debug STL output file.
@@ -42,8 +75,6 @@ Edit config.mk as needed, then run:
- Add the `automatic' meshing algorithm.
- Add the `initial mesh only' meshing algorithm.
- Add a geometry visibility management feature.
-- Add `' API call.
-- Add `' API call.
### Version 0.5
@@ -56,7 +87,7 @@ Edit config.mk as needed, then run:
### Version 0.4.1
-- Add `scad_dump_geometry` API call that can be called from a debugging
+- Add `scad_dump_geometry' API call that can be called from a debugging
session
- Remove an invalid assert
- Fix build that used gmsh library in Release when Debug should have
diff --git a/config.mk b/config.mk
@@ -1,4 +1,4 @@
-VERSION = 0.5.2
+VERSION = 0.6
PREFIX = /usr/local
LIB_TYPE = SHARED
@@ -23,7 +23,7 @@ RANLIB = ranlib
PCFLAGS_STATIC = --static
PCFLAGS = $(PCFLAGS_$(LIB_TYPE))
-GMSH_VERSION = 4.12.2
+GMSH_VERSION = 4.14.1
GMSH_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags gmsh)
GMSH_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs gmsh)
diff --git a/src/scad.c b/src/scad.c
@@ -189,7 +189,9 @@ error:
goto exit;
}
-/* Accumulate tags of geometry in tags */
+/* Accumulate the 2D tags of geometry (if it is 2D) or the tags of its boundary
+ * (if it is 3D).
+ * Trigger a call to sync_device() */
res_T
get_2d_tags
(struct scad_geometry* geometry,
@@ -208,6 +210,7 @@ get_2d_tags
data = geometry->gmsh_dimTags;
ASSERT(sz % 2 == 0);
+ ERR(sync_device());
for(i = 0; i < sz; i += 2) {
int dim = data[i];
int tag = data[i+1];
@@ -265,7 +268,7 @@ scad_synchronize
}
gmshModelOccSynchronize(&ierr);
- get_device()->need_synchro = dev->options.Misc.DebugOpenCascadeSync;
+ dev->need_synchro = dev->options.Misc.DebugAutoSync;
ERR(gmsh_err_to_res_T(ierr));
exit:
@@ -291,11 +294,14 @@ scad_run_ui(void)
goto error;
}
- if(dev->options.Misc.SynchronizeOnRunUI && get_device()->need_synchro) {
- ERR(scad_synchronize());
+ if(dev->options.Misc.SynchronizeOnRunUI) {
+ ERR(sync_device());
}
gmshFltkRun(&ierr);
+ if(ierr) {
+ log_error(dev, "Cannot call FLTK: you probably need to build gmsh locally.\n");
+ }
ERR(gmsh_err_to_res_T(ierr));
exit:
@@ -309,13 +315,15 @@ scad_get_dimtag_refcount
(const int dim,
const int tag)
{
- struct tag_desc* desc = device_get_description(dim, tag);
+ struct tag_desc* desc = NULL;
+
+ if(check_device(FUNC_NAME) != RES_OK) return SIZE_MAX;
+ desc = device_get_description(dim, tag);
if(!desc) return SIZE_MAX;
return desc->refcount;
}
-
res_T
scad_scene_write
(const char* name)
@@ -328,6 +336,8 @@ scad_scene_write
goto error;
}
+ ERR(check_device(FUNC_NAME));
+ ERR(sync_device());
gmshWrite(name, &ierr);
ERR(gmsh_err_to_res_T(ierr));
@@ -365,7 +375,7 @@ scad_stl_get_data_partial
int tags_initialized = 0;
res_T res = RES_OK;
- if(!geometry || !triangles) {
+ if(!geometry || !triangles || (!dont && dont_count > 0)) {
res = RES_BAD_ARG;
goto error;
}
@@ -425,8 +435,13 @@ scad_stl_get_data_partial
}
ASSERT(tcount == darray_double_size_get(triangles));
if(count0 == tcount) {
- log_message(dev, "No triangle collected for geometry '%s'.\n",
- str_cget(&geometry->name));
+ if(str_is_empty(&geometry->name)) {
+ log_message(dev, "No triangle collected for unnamed geometry '%p'.\n",
+ (void*)geometry);
+ } else {
+ log_message(dev, "No triangle collected for geometry '%s'.\n",
+ str_cget(&geometry->name));
+ }
}
exit:
@@ -509,7 +524,7 @@ scad_stl_sort_orientation
res = RES_BAD_ARG;
goto error;
}
- if(coord_n == 0 || orientation == Scad_keep_normals_unchanged) {
+ if(coord_n == 0 || orientation == SCAD_KEEP_NORMALS_UNCHANGED) {
goto exit;
}
@@ -534,7 +549,7 @@ scad_stl_sort_orientation
"Triangles duplicates found when sorting out normals (%u / %u) in set '%s'.\n",
tcount_in - utcount_in, tcount_in, set_name);
}
- if(orientation == Scad_force_normals_outward)
+ if(orientation == SCAD_FORCE_NORMALS_OUTWARD)
convention = SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE;
else
convention = SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE;
@@ -642,7 +657,7 @@ scad_stl_sort_orientation
str_set(&dbl_name, set_name);
str_insert(&dbl_name, idx - 4, "_double_sided_triangles");
r = scad_stl_data_write(&dblsided, str_cget(&dbl_name),
- Scad_keep_normals_unchanged, 0);
+ SCAD_KEEP_NORMALS_UNCHANGED, 0);
if(r == RES_OK) {
log_error(get_device(),
"Saved double sided triangles to file '%s'.\n",
@@ -751,6 +766,8 @@ scad_stl_data_write
goto error;
}
+ ERR(check_device(FUNC_NAME));
+
coord_n = darray_double_size_get(triangles);
if(coord_n % 9) {
res = RES_BAD_ARG;
@@ -789,7 +806,11 @@ scad_stl_export
struct str filename;
int initialized = 0;
- if(!geometry || (!file_name && str_is_empty(&geometry->name))) {
+ if(!geometry || (!file_name && str_is_empty(&geometry->name)) ||
+ (orientation != SCAD_KEEP_NORMALS_UNCHANGED &&
+ orientation != SCAD_FORCE_NORMALS_OUTWARD &&
+ orientation != SCAD_FORCE_NORMALS_INWARD))
+ {
res = RES_BAD_ARG;
goto error;
}
@@ -837,7 +858,12 @@ scad_stl_export_partial
struct str filename;
int initialized = 0;
- if(!geometry) {
+ if(!geometry || (!file_name && str_is_empty(&geometry->name)) ||
+ (!dont && dont_count > 0) ||
+ (orientation != SCAD_KEEP_NORMALS_UNCHANGED &&
+ orientation != SCAD_FORCE_NORMALS_OUTWARD &&
+ orientation != SCAD_FORCE_NORMALS_INWARD))
+ {
res = RES_BAD_ARG;
goto error;
}
@@ -880,9 +906,10 @@ scad_stl_export_split
size_t i;
struct scad_geometry** parts = NULL;
struct scad_device* dev = get_device();
- size_t count;
+ size_t cpt = 0, count;
+ struct str name;
+ int init = 0;
res_T res = RES_OK;
- (void)binary;
if(!geometry || (!file_name && str_is_empty(&geometry->name))) {
res = RES_BAD_ARG;
@@ -891,10 +918,13 @@ scad_stl_export_split
ERR(check_device(FUNC_NAME));
- ERR(scad_geometry_explode(geometry, file_name, &parts, &count));
+ ERR(scad_geometry_explode(geometry, &parts, &count));
ASSERT(count*2 == geometry->gmsh_dimTags_n);
+ str_init(dev->allocator, &name);
+ init = 1;
for(i = 0; i < count; i++) {
- ERR(scad_stl_export(parts[i], NULL, orientation, binary));
+ ERR(str_printf(&name, "%s_%ld", file_name, cpt++));
+ ERR(scad_stl_export(parts[i], str_cget(&name), orientation, binary));
}
exit:
@@ -902,6 +932,7 @@ exit:
for(i = 0; i < count; i++) SCAD(geometry_ref_put(parts[i]));
MEM_RM(dev->allocator, parts);
}
+ if(init) str_release(&name);
return res;
error:
goto exit;
@@ -916,6 +947,7 @@ scad_scene_mesh
ERR(check_device(FUNC_NAME));
+ ERR(sync_device());
gmshModelMeshGenerate(2, &ierr);
ERR(gmsh_err_to_res_T(ierr));
diff --git a/src/scad.h b/src/scad.h
@@ -47,51 +47,44 @@ struct scad_geometry; /* Wrapping of dimTags gmsh description */
/* Verbosity levels */
enum scad_verbosity_levels {
- scad_verbosity_fatal_errors = 0,
- Scad_verbosity_errors = 1,
- Scad_verbosity_warnings = 2,
- Scad_verbosity_direct = 3,
- Scad_verbosity_information = 4,
- Scad_verbosity_status = 5,
- Scad_verbosity_debug = 99
+ SCAD_VERBOSITY_FATAL_ERRORS = 0,
+ SCAD_VERBOSITY_ERRORS = 1,
+ SCAD_VERBOSITY_WARNINGS = 2,
+ SCAD_VERBOSITY_DIRECT = 3,
+ SCAD_VERBOSITY_INFORMATION = 4,
+ SCAD_VERBOSITY_STATUS = 5,
+ SCAD_VERBOSITY_DEBUG = 99
};
/* Mesh algorithms */
enum scad_mesh_algorithm {
- Scad_meshAdapt = 1,
- Scad_Automatic = 2, /* Delaunay on planes, meshAdapt elsewhere */
- Scad_Initial_Mesh_Only = 3, /* Avoid new point creation */
- Scad_Delaunay = 5,
- Scad_frontal_Delaunay = 6,
- Scad_Quasi_Structured = 11
+ SCAD_MESHADAPT = 1,
+ SCAD_AUTOMATIC = 2, /* Delaunay on planes, mesh adapt elsewhere */
+ SCAD_INITIAL_MESH_ONLY = 3, /* Avoid new point creation */
+ SCAD_DELAUNAY = 5,
+ SCAD_FRONTAL_DELAUNAY = 6,
+ SCAD_QUASI_STRUCTURED = 11
};
enum scad_sizes_extend_from_boundary {
- Scad_never = 0,
- Scad_surfaces_and_volumes = 1,
- Scad_surfaces_and_volumes_smallest = 2,
- Scad_surfaces_only = -2,
- Scad_volumes_only = -3
+ SCAD_NEVER = 0,
+ SCAD_SURFACES_AND_VOLUMES = 1,
+ SCAD_SURFACES_AND_VOLUMES_SMALLEST = 2,
+ SCAD_SURFACES_ONLY = -2,
+ SCAD_VOLUMES_ONLY = -3
};
enum scad_stl_solids {
- Scad_single_solid = 0,
- Scad_one_solid_per_surface = 1,
- Scad_one_solid_per_physical_surface = 2
+ SCAD_SINGLE_SOLID = 0,
+ SCAD_ONE_SOLID_PER_SURFACE = 1,
+ SCAD_ONE_SOLID_PER_PHYSICAL_SURFACE = 2
};
enum scad_log_refcounting {
- Scad_log_none = 0,
- Scad_log_dimTags_only_undeleted = BIT(0),
- Scad_log_dimTags_all = BIT(1),
- Scad_log_geometry = BIT(2)
-};
-
-/* A type to specify the kind of mesh size specification set by a call to the
- * scad_geometries_set_mesh_size_modifier API call */
-enum scad_size_modifier_type {
- Scad_absolute_size,
- Scad_size_factor
+ SCAD_LOG_NONE = 0,
+ SCAD_LOG_DIMTAGS_ONLY_UNDELETED = BIT(0),
+ SCAD_LOG_DIMTAGS_ALL = BIT(1),
+ SCAD_LOG_GEOMETRY = BIT(2)
};
/* A type to specify options for the gmsh library */
@@ -116,42 +109,59 @@ struct scad_options {
int OCCParallel;
} Geometry;
struct {
- int Step; /* Run UI when entering any scad API function; requires a FLTK-enabled gmsh build */
+ /* Run UI when entering any star-cad API call; requires a FLTK-enabled gmsh
+ * build, possibly a local build of gmsh and OCC */
+ int RunUIAtEachStep;
+ /* Call synchronize first when run_ui is called */
int SynchronizeOnRunUI;
+ /* Log ref counting operations on geometries (lot of logs expected) */
enum scad_log_refcounting LogRefCounting;
- int DebugOpenCascadeSync; /* Systematic call to synchronize; if results change there is a sync bug in star-cad! */
+ /* Triggers a synchronize operation before any star-cad API call. If results
+ * change, there is a bug in star-cad auto-synchronize mechanism.
+ * This slows down star-cad a lot! */
+ int DebugAutoSync;
+ /* Check gmsh and OCC contexts are empty everytime star-cad context is
+ * empty. As a side effect, triggers a synchronize operation. */
+ int DebugEmptyContext;
} Misc;
};
#define SCAD_DEFAULT_OPTIONS__ \
{ { 1, 36, 1e+22, 1e-6, 1, 1, 1, \
- Scad_frontal_Delaunay, \
- Scad_surfaces_and_volumes, \
- Scad_one_solid_per_physical_surface }, \
- { Scad_verbosity_errors, 1 }, \
+ SCAD_FRONTAL_DELAUNAY, \
+ SCAD_SURFACES_AND_VOLUMES, \
+ SCAD_ONE_SOLID_PER_PHYSICAL_SURFACE }, \
+ { SCAD_VERBOSITY_ERRORS, 1 }, \
{ 1 }, \
- { 0, 0, Scad_log_none, 0 } \
+ { 0, 0, SCAD_LOG_NONE, 0, 0 } \
}
static const struct scad_options SCAD_DEFAULT_OPTIONS = SCAD_DEFAULT_OPTIONS__;
+/* A type to specify the kind of mesh size specification set by a call to the
+ * scad_geometries_set_mesh_size_modifier API call */
+enum scad_size_modifier_type {
+ SCAD_ABSOLUTE_SIZE,
+ SCAD_SIZE_FACTOR
+};
+
/* A type to specify what to swap in geometries_swap calls */
enum scad_swap_elements {
- Scad_swap_name = BIT(0),
- Scad_swap_geometry = BIT(1)
+ SCAD_SWAP_NAME = BIT(0),
+ SCAD_SWAP_GEOMETRY = BIT(1)
};
/* A type to specify normals' orientation when writing STL files. */
enum scad_normals_orientation {
- Scad_keep_normals_unchanged, /* The only one allowed with non closed shapes */
- Scad_force_normals_outward,
- Scad_force_normals_inward
+ SCAD_KEEP_NORMALS_UNCHANGED, /* The only one allowed with non closed shapes */
+ SCAD_FORCE_NORMALS_OUTWARD,
+ SCAD_FORCE_NORMALS_INWARD
};
/* A type to specify how partitioning is done. */
enum scad_partition_flags {
- Scad_allow_overlapping = BIT(0),
- Scad_dump_on_overlapping_error = BIT(1)
+ SCAD_ALLOW_OVERLAPPING = BIT(0),
+ SCAD_DUMP_ON_OVERLAPPING_ERROR = BIT(1) /* Dump individual geometries to STL */
};
BEGIN_DECLS
@@ -170,228 +180,368 @@ scad_initialize
2 = errors and warnings,
3 = errors, warnings, and informative messages */
+/* Close the session and release any geometry not yet released.
+ * Once finalized, scad can be initialized again. */
SCAD_API res_T
scad_finalize
(void);
+/* Set global options `options' for scad. */
SCAD_API res_T
scad_set_options
(const struct scad_options* options); /* May be NULL: set default */
+/* Get global options for scad. */
SCAD_API res_T
scad_get_options
(struct scad_options* options);
/*******************************************************************************
- * Geometry API - A geometry is a primitive, a group of primitives, or the
- * result of an operation on geometries.
- * If provided, name must be unique.
+ * Scene API -
+ * All these calls process the scene (i.e. all the existing geomeries) at once.
******************************************************************************/
+/* Get the number of geometries in the scene */
SCAD_API res_T
-scad_geometry_ref_get
- (struct scad_geometry* geom);
-
-SCAD_API res_T
-scad_geometry_ref_put
- (struct scad_geometry* geom);
+scad_scene_count
+ (size_t* count);
+/* Clear the scene from all its geometries */
SCAD_API res_T
scad_scene_clear
(void);
-/* Get the number of components of the geometry `geom' */
-SCAD_API res_T
-scad_geometry_get_count
- (const struct scad_geometry* geom,
- size_t* count);
-
-/* Attach some custom data `data' to geometry `geom'.
- * If provided, release() is called when `geom' is released or if
- * set_custom_data is called again. */
-SCAD_API res_T
-scad_geometry_set_custom_data
- (struct scad_geometry* geom,
- void (*release) (void* data), /* Can be NULL */
- void* data); /* Can be NULL */
-
-/* Get the custom data attached to geometry `geom'.
- * If set_custom_data has not been called before, return NULL. */
-SCAD_API res_T
-scad_geometry_get_custom_data
- (struct scad_geometry* geom,
- void** data);
-
-/* Get a pointer to `geom's name.
- * Note that this reference is only valid during the lifetime of `geom' (don't
- * use name after deleting `geom') */
-SCAD_API res_T
-scad_geometry_get_name
- (const struct scad_geometry* geom,
- const char** name);
-
-/* Swap the internals of geometry pools (swap pool1[i] and pool2[i]); what is
- * swapped is set usig flags. Pools must have the same count. */
-SCAD_API res_T
-scad_geometries_swap
- (struct scad_geometry** pool1,
- struct scad_geometry** pool2,
- const size_t count,
- const int flags);
-
-/* Get the `mass' of the geometry `geom'. It means area for a 2D geometry and
- * volume for a 3D geometry. */
-SCAD_API res_T
-scad_geometry_get_mass
- (struct scad_geometry* geom,
- double* mass);
-
-/* Get the center of mass of the various components of the geometry.
- * Note that `center' must be allocated by the caller with enough room for (at
- * least) 3 times the count of geom (scad_geometry_get_count) doubles */
+/* Write the whole scene in a format that depends on filename extension.
+ * Available formats include "brep", "msh" (gmsh-specific format), "step",
+ * "stl", "vtk", etc. */
SCAD_API res_T
-scad_geometry_get_centerofmass
- (struct scad_geometry* geom,
- double* center);
+scad_scene_write
+ (const char* filename);
+/* Create the mesh of the whole scene.
+ * Note that, due to gmsh capabilities, there is no way to mesh a given list of
+ * geometries. To avoid meshing useless geometries you can either release them
+ * using scad_geometry_ref_put before meshing, or turn them not-visible using
+ * visibility API. */
SCAD_API res_T
-scad_geometry_get_closest_point
- (struct scad_geometry* geom,
- const double* from,
- double* closest,
- double* closest_distance);
+scad_scene_mesh
+ (void);
-/* Get the Boundig Box of geometry `geom' */
-SCAD_API res_T
-scad_geometry_get_bounding_box
- (struct scad_geometry* geom,
- double min[3],
- double max[3]);
+/*******************************************************************************
+ * Geometry API - A geometry is a primitive, a group of primitives, or the
+ * result of an operation on geometries.
+ ******************************************************************************/
/* Add a rectangle to the scene, defined by a point `xyz' and
* `dxdy' the extents along the x-, y-axes. */
SCAD_API res_T
scad_add_rectangle
- (const char* name, /* Can be NULL */
- const double xyz[3],
+ (const double xyz[3],
const double dxdy[2],
struct scad_geometry** rectangle);
-/* Add a disk in (xy) plane to the scene, defined by a the center `xyz' and
+/* Add a disk in the (xy) plane to the scene, defined by its `center' and
* `radius'. */
SCAD_API res_T
scad_add_disk
- (const char* name, /* Can be NULL */
- const double xyz[3],
+ (const double center[3],
const double radius,
struct scad_geometry** disk);
-/* Add a polygonal surface in (xy) plane to the scene at elevation z */
+/* Add a polygon in the (xy) plane to the scene.
+ * The `polygon' has `count' vertice and is at elevation `z', the vertice are
+ * defined by calls to user-provided function `get_position'. */
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 (*get_position)(const size_t ivert, double pos[2], void* 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 */
+ const size_t count,
struct scad_geometry** polygon);
-/* Add a parallelepipedic box to the scene, defined by a point `xyz' and
+/* Add a parallelepipedic `box' to the scene, defined by a point `xyz' and
* `dxdydz' the extents along the x-, y- and z-axes. */
SCAD_API res_T
scad_add_box
- (const char* name, /* Can be NULL */
- const double xyz[3],
+ (const double xyz[3],
const double dxdydz[3],
struct scad_geometry** box);
-/* Add a cylinder to the scene, defined by the center `xyz' of its first
- * circular face, the vector `axis' defining its axis and its radius `rad'. The
- * `angle' argument defines the angular opening (from 0 to 2*Pi). */
+/* Add a `cylinder' to the scene, defined by the center `center' of its first
+ * circular face, the vector `axis' defining its axis and its radius `radius'.
+ * The `angle' argument defines the angular opening (from 0 to 2*PI). */
SCAD_API res_T
scad_add_cylinder
- (const char* name, /* Can be NULL */
- const double xyz[3],
+ (const double center[3],
const double axis[3],
const double radius,
const double angle,
struct scad_geometry** cylinder);
-/* Add a sphere of center `xyz' and radius `rad' to the scene. */
+/* Add a `sphere' of center `center' and radius `radius' to the scene. */
SCAD_API res_T
scad_add_sphere
- (const char* name, /* Can be NULL */
- const double xyz[3],
+ (const double center[3],
const double radius,
struct scad_geometry** sphere);
-/* Check if geometries `geom1' and `geom2' have the same content, that is:
- * - are the same scad_geometries (trivial case),
- * - contain the same internal entities.
- * To check if 2 geometries are "equivalent", one as to apply boolean operators
- * (e.g. cut) and check the result accordingly (e.g. empty result). */
+/* Add a `cone' to the scene, defined by the center `center' of its first
+ * circular face, the vector `axis' defining its axis and its 2 radii `radius1'
+ * and `radius2'. Note that the 2 radii cannot be identical (one of them can be
+ * zero).
+ * The `angle' argument defines the angular opening (from 0 to 2*PI). */
SCAD_API res_T
-scad_geometries_equal
- (struct scad_geometry* geom1,
- struct scad_geometry* geom2,
+scad_add_cone
+ (const double center[3],
+ const double axis[3],
+ const double radius1,
+ const double radius2,
+ const double angle,
+ struct scad_geometry** cone);
+
+/* Add a `torus' to the scene, defined by its `center', the vector `axis'
+ * defining its axis and its 2 positive radii `radius1' and `radius2'.
+ * The `angle' argument defines the angular opening (from 0 to 2*PI).
+ * If `z_axis' is provided, it defines the Z axis of the torus. Otherwise the
+ * absolute Z axis is used. */
+SCAD_API res_T
+scad_add_torus
+ (const double center[3],
+ const double radius1,
+ const double radius2,
+ const double angle,
+ const double z_axis[3], /* Can be NULL */
+ struct scad_geometry** torus);
+
+/* Scale the geometry `geometry' by factors `scale' along the three coordinate axes;
+ * Use `center', as the center of the homothetic transformation. */
+SCAD_API res_T
+scad_geometry_dilate
+ (const struct scad_geometry* geometry,
+ const double center[3],
+ const double scale[3],
+ struct scad_geometry** out_geometry);
+
+/* Translate the geometry `geometry' along (`dx', `dy', `dz'). */
+SCAD_API res_T
+scad_geometry_translate
+ (const struct scad_geometry* geometry,
+ const double dxdydz[3],
+ struct scad_geometry** out_geometry);
+
+/* Rotate the geometry `geometry' by `angle' radians around the axis of revolution
+ * defined by the point `pt' and the direction `dir'. */
+SCAD_API res_T
+scad_geometry_rotate
+ (const struct scad_geometry* geometry,
+ const double pt[3],
+ const double dir[3],
+ const double angle,
+ struct scad_geometry** out_geometry);
+
+/* Extrude the geometry `geometry' using a translation along (`dx', `dy', `dz'). */
+SCAD_API res_T
+scad_geometry_extrude
+ (const struct scad_geometry* geometry,
+ const double dxdydz[3],
+ struct scad_geometry** out_geometry);
+
+/* Return a list of geometries which form the geometry `geometry'.
+ * The output geometries are created unnamed.
+ * Whatever the names, if defined they must be unique.
+ * The result `out_geometries' being allocated using the allocator provided when
+ * initializing star-cad, it should be freed accordingly. */
+SCAD_API res_T
+scad_geometry_explode
+ (const struct scad_geometry* geometry,
+ struct scad_geometry*** out_geometries,
+ size_t* out_count);
+
+/* Ref counting of geometries: get a new reference to geometry `geometry'. */
+SCAD_API res_T
+scad_geometry_ref_get
+ (struct scad_geometry* geometry);
+
+/* Ref counting of geometries: release a reference to geometry `geometry'. */
+SCAD_API res_T
+scad_geometry_ref_put
+ (struct scad_geometry* geometry);
+
+/* Get the number of components of the geometry `geometry'. */
+SCAD_API res_T
+scad_geometry_get_count
+ (const struct scad_geometry* geometry,
+ size_t* count);
+
+/* Check if the geometry `geometry' is empty (has count 0). */
+SCAD_API res_T
+scad_geometry_is_empty
+ (const struct scad_geometry* geometry,
+ int* empty);
+
+/* Attach some custom data `data' to geometry `geometry'.
+ * If provided, release() is called when `geometry' is released or if
+ * set_custom_data is called again. */
+SCAD_API res_T
+scad_geometry_set_custom_data
+ (struct scad_geometry* geometry,
+ void (*release) (void* data), /* Can be NULL */
+ void* data); /* Can be NULL */
+
+/* Get the custom data attached to geometry `geometry'.
+ * If set_custom_data has not been called before, return NULL. */
+SCAD_API res_T
+scad_geometry_get_custom_data
+ (struct scad_geometry* geometry,
+ void** data);
+
+/* Set the name of geometry `geometry'.
+ * If not NULL, names must be unique. */
+SCAD_API res_T
+scad_geometry_set_name
+ (struct scad_geometry* geometry,
+ const char* name); /* Can be NULL */
+
+/* Set the name of geometries in `geometries'.
+ * If `prefix_name' is not NULL, the geometries are named <prefix_name>_<rank>,
+ * <rank> counting from `from_rank'. Otherwise their names are set to NULL.
+ * If not NULL, names must be unique. */
+SCAD_API res_T
+scad_geometries_set_name
+ (struct scad_geometry** geometries,
+ const size_t geometries_count,
+ const char* prefix_name, /* Can be NULL */
+ const size_t from_rank);
+
+/* Get a pointer to `geometry's name, NULL if unnamed.
+ * Note that this reference is only valid during the lifetime of `geometry'
+ * (don't use name after deleting `geometry'). */
+SCAD_API res_T
+scad_geometry_get_name
+ (const struct scad_geometry* geometry,
+ const char** name);
+
+/* Swap the internals of geometry pools `pool1' and `pool2'
+ * (i.e. swap internals of pool1[i] and pool2[i]).
+ * What is swapped is set using `flags'.
+ * Pools must have the same `count'. */
+SCAD_API res_T
+scad_geometries_swap
+ (struct scad_geometry** pool1,
+ struct scad_geometry** pool2,
+ const size_t count,
+ const int flags);
+
+/* Get the `mass' of the geometry `geometry'. It means area for a 2D geometry
+ * and volume for a 3D geometry. */
+SCAD_API res_T
+scad_geometry_get_mass
+ (struct scad_geometry* geometry,
+ double* mass);
+
+/* Get the center of mass of geometry `geometry' in `center'. */
+SCAD_API res_T
+scad_geometry_get_centerofmass
+ (struct scad_geometry* geometry,
+ double center[3]);
+
+/* Get the `closest' point on geometry `geometry' from point `from'.
+ * Return the `closest' point and its `distance'.
+ * The underlying 2D geometry on wich the closest point is located is returned
+ * as a new geometry in `underlying_geometry' if it is not NULL.
+ * If `geometry' is 3D, this underlying geometry is (a part of) its boundary. */
+SCAD_API res_T
+scad_geometry_get_closest_point
+ (struct scad_geometry* geometry,
+ const double from[3],
+ double closest[3],
+ double* distance,
+ struct scad_geometry** underlying_geometry); /* Can be NULL */
+
+/* Get the normal of the geometry `geometry' at position `p'.
+ * The normal is set in `N' and the underlying 2D geometry on which `p' is
+ * located is returned as a new geometry in `underlying_geometry' if it is not
+ * NULL.
+ * If `geometry' is 3D, this underlying geometry is (a part of) its boundary.
+ * Note that the position `p' is supposed to be close enough of `geometry', or
+ * this operation is meaningless (as the normal is taken on a computed point on
+ * the geometry that is the closest point from position `p'). */
+SCAD_API res_T
+scad_geometry_get_normal
+ (struct scad_geometry* geometry,
+ const double p[3],
+ double N[3],
+ struct scad_geometry** underlying_geometry); /* Can be NULL */
+
+/* Get the Boundig Box of geometry `geometry' in the form of `min' and `max'
+ * vectors. */
+SCAD_API res_T
+scad_geometry_get_bounding_box
+ (struct scad_geometry* geometry,
+ double min[3],
+ double max[3]);
+
+/* Check if geometries `geom1' and `geom2' share the same content.
+ * Note that names are not compared, as they CANNOT be the same.
+ * Also note that copied geometries (scad_geometry_copy) are not equal, as their
+ * contents are not shared, but are copies.
+ * On the other hand, collected content (scad_geometries_collect) is equal to
+ * its source.
+ * To check if 2 geometries are copies of one another, one as to apply boolean
+ * operators (e.g. cut) and check the result accordingly (e.g. empty result). */
+SCAD_API res_T
+scad_geometry_equal
+ (const struct scad_geometry* geom1,
+ const struct scad_geometry* geom2,
int* equal);
-/* Check if all the entities of `geometry' are part of the geometries in
+/* Check if all the entities of `geometry' are part of one of the geometries in
* `geometries'. */
SCAD_API res_T
scad_geometry_is_included
- (struct scad_geometry* geometry,
+ (const struct scad_geometry* geometry,
struct scad_geometry** geometries,
const size_t geometries_count,
int* included);
-/* Create a new geometry made from all the entities from `geometries'. */
+/* Create a new geometry `out_geometry' sharing all the content of geometries in
+ * `geometries'.
+ * Note that, while copied geometries (scad_geometry_copy) are not equal as
+ * their internals are copies (not shared content), collected content
+ * (scad_geometries_collect) is equal to its source. */
SCAD_API res_T
-scad_collect_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_collect
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** out_geometry);
/* Compute the boolean union (the fusion) of the geometries in `geometries' and
* `tools'. */
SCAD_API res_T
-scad_fuse_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_fuse
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
struct scad_geometry** out_geometry);
/* Compute the boolean difference between the geometries in `geometries' and
- * `tools'. */
+ * `tools'.
+ * Note that the resulting geometry can be empty. */
SCAD_API res_T
-scad_cut_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_cut
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
struct scad_geometry** out_geometry);
/* Compute the boolean intersection (the common parts) of the geometries
- * in `geometries' and `tools'. */
+ * in `geometries' and `tools'.
+ * Note that the resulting geometry can be empty. */
SCAD_API res_T
-scad_intersect_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
- const size_t geometries_count,
- struct scad_geometry** tools,
- const size_t tools_count,
- struct scad_geometry** out_geometry);
-
-/* compute boundary intersection (the common part) of the geometries in
- * `geometries' and `tools'. */
-SCAD_API res_T
-scad_geometries_common_boundaries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_intersect
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
@@ -400,7 +550,7 @@ scad_geometries_common_boundaries
/* Compute the boolean fragments (general fuse) resulting from the
* intersection of the geometries in `geometries', making all interfaces
* conformal.
- * `flags' should be made by Oring values from enum scad_partition_flags to
+ * `flags' should be made by ORing values from enum scad_partition_flags to
* enable non default behaviours (default is to disallow overlapping).
* The output geometries are created unnamed.
* When applied to geometries of different dimensions, the lower dimensional
@@ -413,134 +563,155 @@ scad_geometries_partition
const int flags,
struct scad_geometry** out_geometries);
-/* Get the boundary of the geometries in `geometries'. */
+/* Compute boundaries' intersection (the common part) of the geometries in
+ * `geometries' and `tools'.
+ * The output geometries are created unnamed.
+ * The result `out_boundaries' being allocated using the allocator provided when
+ * initializing star-cad, it should be freed accordingly.
+ * If there is no common boundary, `out_boundaries' is set to NULL and
+ * `out_count' is set to 0.
+ * Note that there is usually no common boundaries between geometries before
+ * they have been partitioned. */
SCAD_API res_T
-scad_geometry_boundary
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_common_boundaries
+ (struct scad_geometry** geometries,
+ const size_t geometries_count,
+ struct scad_geometry** tools,
+ const size_t tools_count,
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count);
+
+/* Get the boundaries of the geometries in `geometries', considered as a whole.
+ * The output geometries are created unnamed.
+ * The result `out_boundaries' being allocated using the allocator provided when
+ * initializing star-cad, it should be freed accordingly. */
+SCAD_API res_T
+scad_geometries_boundaries
+ (struct scad_geometry** geometries,
const size_t geometries_count,
- struct scad_geometry** out_boundary);
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count);
-/* copy the geometry `geom'. */
+/* Copy the geometry `geometry', except for its name.
+ * The new geometry remains unnamed. */
SCAD_API res_T
scad_geometry_copy
- (const struct scad_geometry* geom,
- const char* name, /* Can be NULL */
+ (const struct scad_geometry* geometry,
struct scad_geometry** out_copy);
-/* copy the geometry `geom'. */
+/* Change the visibility of the geometry `geometry'.
+ * If `recursive' is set, constituents of `geometry' are recursively affected down
+ * to dim 0 (vertices).
+ * Can be used in conjunction with option MeshOnlyVisible. */
SCAD_API res_T
scad_geometry_set_visibility
- (const struct scad_geometry* geom,
+ (const struct scad_geometry* geometry,
int visible,
int recursive);
-/* Change the name of geometry `geom'. */
-SCAD_API res_T
-scad_geometry_rename
- (struct scad_geometry* geom,
- const char* name); /* Can be NULL */
-
-/* Scale the geometry by * factors `scale' along the three coordinate axes;
- * use `center', as the center of the homothetic transformation. */
+/* Flag `target' geometries as being the result of applying the `affine'
+ * tranform to `source' geometries.
+ * The result is that the mesh generated for `target' is the image on the mesh
+ * generated for `source' through the `affine' transform.
+ * Only meaningful for surfaces. If called on a volume, it applies to its 2D
+ * constituents.
+ * The two sets of surfaces must match topologically (same number of points,
+ * etc.). */
SCAD_API res_T
-scad_geometry_dilate
- (const struct scad_geometry* geom,
- const double center[3],
- const double scale[3],
- const char* name, /* Can be NULL */
- struct scad_geometry** out_geometry);
+scad_geometries_set_periodic
+ (struct scad_geometry** source,
+ const size_t source_count,
+ struct scad_geometry** target,
+ const size_t target_count,
+ double affine[16]);
-/* Translate the geometry `geom' along (`dx', `dy', `dz'). */
+/* Set a size modifier for geometries in `geometries'.
+ * When meshing these geometries, triangles' size will be either size*modifier,
+ * or modifier where size would be the size of the triangle in the absence of a
+ * size modifier.
+ * The size modifier is applied recursively down to dimension 0 (points).
+ * If multiple size modifiers are applied, the order matters as the last applied
+ * size modifier remains.
+ * To reset a size modifier, just apply a new Scad_size_factor modifier of 1. */
SCAD_API res_T
-scad_geometry_translate
- (const struct scad_geometry* geom,
- const double dxdydz[3],
- const char* name, /* Can be NULL */
- struct scad_geometry** out_geometry);
+scad_geometries_set_mesh_size_modifier
+ (struct scad_geometry** geometries,
+ const size_t geometries_count,
+ enum scad_size_modifier_type type,
+ double modifier);
-/* Rotate the geometry `geom' by `angle' radians around the axis of revolution
- * defined by the point `pt' and the direction `dir'. */
+/* Set a specific mesh algorithm for geometries in `geometries'.
+ * Only apply to surfaces (dimension 2). If called on a volume, it applies to
+ * its 2D constituents. */
SCAD_API res_T
-scad_geometry_rotate
- (const struct scad_geometry* geom,
- const double pt[3],
- const double dir[3],
- const double angle,
- const char* name, /* Can be NULL */
- struct scad_geometry** out_geometry);
+scad_geometries_set_mesh_algorithm
+ (struct scad_geometry** geometries,
+ const size_t geometries_count,
+ enum scad_mesh_algorithm algorithm);
-/* Extrude the geometry `geom' using a translation along (`dx', `dy', `dz'). */
+/* Clear the mesh of the geometries in `geometries'.
+ * Note that the mesh of a geometry can only be cleared if it is not on the
+ * boundary of another geometry with a non-empty mesh. */
SCAD_API res_T
-scad_geometry_extrude
- (struct scad_geometry* geom,
- const char* name, /* Can be NULL */
- const double dxdydz[3],
- struct scad_geometry** out_geometry);
+scad_geometries_clear_mesh
+ (struct scad_geometry** geometries,
+ const size_t geometries_count);
-/* Return a list of geometries which form the geometry `geom'.
- * The output geometries are named <base>_<rank>, where <base> is either
- * prefix_name or geom's name, and <rank> counting from 0.
- * The result `out_geometries' being allocated using the allocator provided when
- * initializing star-cad, it should be freed accordingly. */
-SCAD_API res_T
-scad_geometry_explode
- (const struct scad_geometry* geom,
- const char* prefix_name, /* Can be NULL */
- struct scad_geometry*** out_geometries,
- size_t* out_geometry_n);
+/*******************************************************************************
+ * I/O API
+ ******************************************************************************/
-/* Import a step model from file `filename'. The imported geometries are
- * recorded in `out_geometries'.
+/* Import a step model from file `filename'.
+ * The imported geometries are recorded in `out_geometries'.
+ * The output geometries are created unnamed.
* Note that `out_geometries' is allocated using the allocator provided when
* initializing star-cad and should be freed accordingly. */
SCAD_API res_T
scad_step_import
(const char* filename, /* name of step file */
- const char* name, /* Can be NULL */
struct scad_geometry*** out_geometries,
- size_t* out_geometry_n);
+ size_t* out_count);
-/* Export the mesh of geometry `geom' to an STL file.
+/* Export the mesh of geometry `geometry' to an STL file.
* In order to get a mesh, one has to call scad_scene_mesh before calling this.
- * If `file_name' is provided it is used to name the file (just adding .stl),
+ * If `filename' is provided it is used to name the file (just adding .stl),
* otherwise the geometry name is used instead (and it is an error if neither
- * file_name nor the geometry name is defined). Mesh orientation can be forced
+ * filename nor the geometry name is defined). Mesh orientation can be forced
* inward or outward only if it defines a closed volume. The file format is
* either binary or ascii, depending on the value of the `binary' argument. */
SCAD_API res_T
scad_stl_export
- (struct scad_geometry* geom,
- const char* file_name,
+ (struct scad_geometry* geometry,
+ const char* filename, /* Can be NULL if geometry name is defined */
const enum scad_normals_orientation orientation,
- const int binary); /* File format */
+ const int binary);
/* Same as previous, but geometries that are part of `exclude' are not exported. */
SCAD_API res_T
scad_stl_export_partial
(struct scad_geometry* geometry,
- struct scad_geometry** exclude,
+ struct scad_geometry** exclude, /* Can be NULL */
const size_t exclude_count,
- const char* file_name,
+ const char* filename, /* Can be NULL if geometry name is defined */
const enum scad_normals_orientation orientation,
const int binary);
-/* Export the geometry `geom' in as many files than its count.
- * The files are named <base>_<rank>.stl, where <base> is either file_name or
- * geom's name, and <rank> counting from 0. */
+/* Export the geometry `geometry' in as many files than its count.
+ * The files are named <base>_<rank>.stl, where <base> is either `filename_base'
+ * (first choice) or `geometry's name, <rank> counting from 0. */
SCAD_API res_T
scad_stl_export_split
- (struct scad_geometry* geom,
- const char* file_name,
+ (struct scad_geometry* geometry,
+ const char* filename_base, /* Can be NULL if geometry name is defined */
const enum scad_normals_orientation orientation,
- const int binary); /* File format */
+ const int binary);
-/* Accumulate the mesh of the geometry `geom' into `triangles', each triangle
+/* Accumulate the mesh of the geometry `geometry' into `triangles', each triangle
* being described by 9 doubles in a STL way.
* In order to get a mesh, one has to call scad_scene_mesh first. */
SCAD_API res_T
scad_stl_get_data
- (struct scad_geometry* geom,
+ (struct scad_geometry* geometry,
struct darray_double* triangles);
/* Same as previous, but geometries in `exclude', that can be 2D and/or 3D, are
@@ -548,7 +719,7 @@ scad_stl_get_data
SCAD_API res_T
scad_stl_get_data_partial
(struct scad_geometry* geometry,
- struct scad_geometry** exclude,
+ struct scad_geometry** exclude, /* Can be NULL */
const size_t exclude_count,
struct darray_double* triangles);
@@ -561,76 +732,12 @@ scad_stl_data_write
const enum scad_normals_orientation orientation,
const int binary);
-/* Write the whole scene in a format that depends on the file name extension. */
-SCAD_API res_T
-scad_scene_write
- (const char* name);
-
-/* Create the mesh of the whole scene. */
-SCAD_API res_T
-scad_scene_mesh
- (void);
-
-/* Flag `target' geometries as being the result of applying the `affine'
- * tranform to `source' geometries.
- * The result is that the mesh generated for `target' is the image on the mesh
- * generated for `source' through the `affine' transform.
- * Only apply to surfaces (dimension 2). If called on a volume, it applies to
- * its 2D constituents.
- * The two sets of surfaces must match exactly (same number of points, etc.). */
-SCAD_API res_T
-scad_geometries_set_periodic
- (struct scad_geometry** source,
- const size_t source_count,
- struct scad_geometry** target,
- const size_t target_count,
- double affine[16]);
-/* Set a size modifier for geometries in `geometries'.
- * When meshing these geometries, triangles' size will be either size*modifier,
- * or modifier where size would be the size of the triangle in the absence of a
- * size modifier.
- * The size modifier is applied recursively down to dimension 0 (points).
- * If multiple size modifiers are applied, the order matters as the last applied
- * size modifier remains.
- * To reset a size modifier, just apply a new Scad_size_factor modifier of 1. */
-SCAD_API res_T
-scad_geometries_set_mesh_size_modifier
- (struct scad_geometry** geometries,
- const size_t geometries_count,
- enum scad_size_modifier_type type,
- double modifier);
-
-/* Set a specific mesh algorithm for geometries in `geometries'.
- * Only apply to surfaces (dimension 2). If called on a volume, it applies to
- * its 2D constituents. */
-SCAD_API res_T
-scad_geometries_set_mesh_algorithm
- (struct scad_geometry** geometries,
- const size_t geometries_count,
- enum scad_mesh_algorithm algorithm);
-
-/* Clear the mesh of the geometries in `geometries'.
- * Note that the mesh of a geometry can only be cleared if it is not on the
- * boundary of another geometry with a non-empty mesh. */
-SCAD_API res_T
-scad_geometries_clear_mesh
- (struct scad_geometry** geometries,
- const size_t geometries_count);
-
-/* Get the normal of the geometry `geom' at position `p'.
- * The normal is set in `N' and the underlying 2D entity to which `p' belongs is
- * returned as a new geometry in `out_geometry'. */
-SCAD_API res_T
-scad_geometry_normal
- (struct scad_geometry* geom,
- double p[3],
- double N[3],
- const char* name, /* Can be NULL */
- struct scad_geometry** out_geometry);
-
-/* The following API calls are meant for debugging purposes.
- * They can be called from gdb. */
+/*******************************************************************************
+ * Debug API
+ * The following API calls are meant for debugging purposes.
+ * They can be called from gdb.
+ ******************************************************************************/
/* Open gmsh in GUI mode so that the model can be inspected and even modified.
* To use it from gdb:
@@ -663,19 +770,21 @@ scad_get_dimtag_refcount
(const int dim,
const int tag);
-/* Dump geometry `geom' with address/name, ref count and tags.
+/* Dump geometry `geometry' with address/name, ref count and its OCC internal
+ * dim.tag list.
* To use it from gdb:
* (gdb) call scad_dump_geometry( <geom_ptr> )
*/
SCAD_API res_T
scad_dump_geometry
- (const struct scad_geometry* geom);
+ (const struct scad_geometry* geometry);
-/* Dump all the geometries with address/name, ref count and tags.
+/* Dump all the geometries with address/name, ref count and and their OCC
+ * internal dim.tag lists.
* To use it from gdb:
* (gdb) call scad_dump_geometries()
*/
-SCAD_API void
+SCAD_API res_T
scad_dump_geometries
(void);
diff --git a/src/scad_device.c b/src/scad_device.c
@@ -30,58 +30,6 @@
/*******************************************************************************
* Local functions
******************************************************************************/
-static void
-device_release_tags_of_dim
- (struct scad_device* dev,
- const int dim)
-{
- struct htable_tags2desc* table;
- struct htable_tags2desc_iterator it, end;
- int fst = 1;
- int ierr;
- ASSERT(dev);
- CHK(dim == 2 || dim == 3); /* other dims not managed yet */
-
- table = dev->tags2desc + dim - 2;
- htable_tags2desc_begin(table, &it);
- htable_tags2desc_end(table, &end);
- while(!htable_tags2desc_iterator_eq(&it, &end)) {
- int dt[2], tag = *htable_tags2desc_iterator_key_get(&it);
- struct tag_desc* desc = device_get_description(dim, tag);
- ASSERT(desc->refcount > 0);
- htable_tags2desc_iterator_next(&it);
- /* desc is a descriptor for a non-released tag */
- if(fst) {
- fst = 0;
- logger_print(dev->logger, dev->log_type,
- "Some tags were not removed properly.\n");
- }
- logger_print(dev->logger, dev->log_type, "Tag %d.%d (refcount = %lu).\n",
- dim, tag, (long unsigned)desc->refcount);
- /* Remove tag according to policy */
- dt[0] = dim;
- dt[1] = tag;
- switch(desc->delete_policy) {
- case Scad_do_not_delete:
- logger_print(dev->logger, dev->log_type,
- "Tag %d.%d not deleted due to policy.\n",
- dim, tag);
- break;
- case Scad_delete_non_recursive:
- logger_print(dev->logger, dev->log_type,
- "Tag %d.%d non-recursively deleted due to policy.\n",
- dim, tag);
- gmshModelOccRemove(dt, 2, 0, &ierr);
- break;
- case Scad_delete_recursive:
- gmshModelOccRemove(dt, 2, 1, &ierr);
- break;
- default: FATAL("Invalid enum value");
- }
- }
- htable_tags2desc_release(table);
-}
-
static res_T
device_release(struct scad_device* dev)
{
@@ -97,8 +45,8 @@ device_release(struct scad_device* dev)
option = dev->options.Misc.LogRefCounting;
empty = htable_geometries_is_empty(&dev->allgeom);
log_type = empty ? LOG_OUTPUT : LOG_WARNING;
- log = (option & Scad_log_dimTags_all)
- || (!empty && (option & Scad_log_dimTags_only_undeleted));
+ log = (option & SCAD_LOG_DIMTAGS_ALL)
+ || (!empty && (option & SCAD_LOG_DIMTAGS_ONLY_UNDELETED));
dev->log = log;
dev->log_type = log_type;
@@ -113,13 +61,15 @@ device_release(struct scad_device* dev)
}
while(!htable_geometries_iterator_eq(&it, &end)) {
struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it);
- SCAD(geometry_ref_put(geom));
+ while(geom->ref > 0) {
+ SCAD(geometry_ref_put(geom));
+ }
htable_geometries_iterator_next(&it);
}
htable_names_release(&dev->geometry_names);
htable_geometries_release(&dev->allgeom);
- device_release_tags_of_dim(dev, 2);
- device_release_tags_of_dim(dev, 3);
+ htable_tags2desc_release(dev->tags2desc);
+ htable_tags2desc_release(dev->tags2desc+1);
htable_size_modifiers_release(&dev->size_modifiers_by_dim[0]);
htable_size_modifiers_release(&dev->size_modifiers_by_dim[1]);
htable_size_modifiers_release(&dev->size_modifiers_by_dim[2]);
@@ -130,6 +80,11 @@ device_release(struct scad_device* dev)
MEM_RM(dev->allocator, dev);
htable_geometries_release(&tmp);
+ if(dev->options.Misc.DebugEmptyContext) {
+ /* After releasing all star-cad stuff, gmsh and OCC contexts must be empty */
+ return check_empty_gmsh_occ(dev);
+ }
+
return res;
}
@@ -191,12 +146,29 @@ check_device
goto error;
}
- if(get_device()->need_synchro) {
- ERR(scad_synchronize());
+ if(g_device->options.Misc.RunUIAtEachStep) {
+ ERR(scad_run_ui());
+ }
+
+ if(g_device->options.Misc.DebugEmptyContext
+ && htable_geometries_size_get(&g_device->allgeom) == 0)
+ {
+ ERR(check_empty_gmsh_occ(g_device));
}
- if(g_device->options.Misc.Step) {
- ERR(scad_run_ui());
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+sync_device(void)
+{
+ res_T res = RES_OK;
+
+ if(g_device->need_synchro) {
+ ERR(scad_synchronize()); /* Reset need_synchro according to options */
}
exit:
@@ -218,7 +190,7 @@ device_register_tags
{
res_T res = RES_OK;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
+ int log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
ASSERT(geom);
@@ -265,7 +237,6 @@ scad_dump_geometry
(const struct scad_geometry* geom)
{
res_T res = RES_OK;
- struct scad_device* dev = get_device();
size_t i;
if(!geom) {
@@ -274,11 +245,6 @@ scad_dump_geometry
}
ERR(check_device(FUNC_NAME));
- if(htable_geometries_is_empty(&dev->allgeom)) {
- printf("No geometry defined.\n");
- return res;
- }
-
if(str_is_empty(&geom->name)) {
printf("Unnamed geometry %p (count is %lu), tags: ",
(void*)geom, (long unsigned)geom->ref);
@@ -299,28 +265,35 @@ error:
goto exit;
}
-void
+res_T
scad_dump_geometries
(void)
{
+ res_T res = RES_OK;
struct scad_device* dev = get_device();
struct htable_geometries_iterator it, end;
+ size_t cpt = 0;
+
+ ERR(check_device(FUNC_NAME));
- if(!dev) {
- printf("Error: star-cad is not initialized.\n");
- return;
- }
if(htable_geometries_is_empty(&dev->allgeom)) {
printf("No geometry defined.\n");
- return;
+ goto exit; /* Not an error */
}
htable_geometries_begin(&dev->allgeom, &it);
htable_geometries_end(&dev->allgeom, &end);
while(!htable_geometries_iterator_eq(&it, &end)) {
struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it);
- SCAD(dump_geometry(geom));
+ ERR(scad_dump_geometry(geom));
+ cpt++;
htable_geometries_iterator_next(&it);
}
+ printf("Counted %ld geometries.\n", cpt);
+
+exit:
+ return res;
+error:
+ goto exit;
}
static void
@@ -355,7 +328,7 @@ do_device_tags_ref_get
res_T res = RES_OK;
size_t i;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
+ int log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
enum log_type log_type = dev->log_type;
ASSERT(dimTags || count == 0);
@@ -374,6 +347,7 @@ do_device_tags_ref_get
struct tag_desc d;
tag_desc_init(dev->allocator, &d);
ERR(htable_tags2desc_set(t2d, &tag, &d));
+ dev->need_synchro = 1;
if(log) {
logger_print(dev->logger, log_type, "New tag %d.%d (count set to 1).\n",
dim, tag);
@@ -451,6 +425,7 @@ do_device_tags_ref_put
dim, tag);
}
gmshModelOccRemove(dimTags+i, 2, 0, &ierr);
+ dev->need_synchro = 1;
ERR(gmsh_err_to_res_T(ierr));
break;
case Scad_delete_recursive:
@@ -459,6 +434,7 @@ do_device_tags_ref_put
dim, tag);
}
gmshModelOccRemove(dimTags+i, 2, 1, &ierr);
+ dev->need_synchro = 1;
ERR(gmsh_err_to_res_T(ierr));
break;
default: FATAL("Invalid enum value");
@@ -558,6 +534,78 @@ error:
goto exit;
}
+res_T
+check_empty_gmsh_occ(struct scad_device* dev)
+{
+ int* dimTags = NULL;
+ size_t dimTags_n, i;
+ int ierr, found, d;
+ struct str msg;
+ int msg_initialized = 0;
+ res_T res = RES_OK;
+
+ found = 0;
+ for(d = 3; d >= 0; d--) {
+ gmshFree(dimTags);
+ dimTags = NULL;
+ gmshModelOccGetEntities(&dimTags, &dimTags_n, d, &ierr);
+ ASSERT(dimTags_n % 2 == 0);
+ if(dimTags_n == 0)
+ continue;
+ found = 1;
+ log_error(dev,
+ "There are %ld unreferenced Open-Cascade entities of dim %d from an empty star-cad context%c\n",
+ dimTags_n / 2, d, (d > 1 ? ':' : '.'));
+ if(d < 2) continue;
+ if(!msg_initialized) str_init(dev->allocator, &msg);
+ for(i = 0; i < dimTags_n; i += 2) {
+ const int dim = dimTags[i];
+ const int tag = dimTags[i+1];
+ ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
+ }
+ log_error(dev," tags [%s]\n", str_cget(&msg));
+ }
+ if(found) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(sync_device());
+
+ found = 0;
+ for(d = 3; d >= 0; d--) {
+ gmshFree(dimTags);
+ dimTags = NULL;
+ gmshModelGetEntities(&dimTags, &dimTags_n, d, &ierr);
+ ASSERT(dimTags_n % 2 == 0);
+ if(dimTags_n == 0)
+ continue;
+ found = 1;
+ log_error(dev,
+ "There are %ld unreferenced gmsh entities of dim %d from an empty star-cad context%c\n",
+ dimTags_n / 2, d, (d > 1 ? ':' : '.'));
+ if(d < 2) continue;
+ if(!msg_initialized) str_init(dev->allocator, &msg);
+ for(i = 0; i < dimTags_n; i += 2) {
+ const int dim = dimTags[i];
+ const int tag = dimTags[i+1];
+ ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
+ }
+ log_error(dev," tags [%s]\n", str_cget(&msg));
+ }
+ if(found) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ gmshFree(dimTags);
+ if(msg_initialized) str_release(&msg);
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* API scad_device functions
******************************************************************************/
@@ -594,10 +642,10 @@ scad_initialize
}
g_device->logger = logger ? logger : LOGGER_DEFAULT;
g_device->allocator = allocator;
- g_device->need_synchro = g_device->options.Misc.DebugOpenCascadeSync;
+ g_device->need_synchro = g_device->options.Misc.DebugAutoSync;
g_device->verbose = verbose;
g_device->log_type = LOG_OUTPUT;
- g_device->log = (g_device->options.Misc.LogRefCounting != Scad_log_none);
+ g_device->log = (g_device->options.Misc.LogRefCounting != SCAD_LOG_NONE);
htable_names_init(allocator, &g_device->geometry_names);
htable_geometries_init(allocator, &g_device->allgeom);
htable_tags2desc_init(allocator, &g_device->tags2desc[0]);
@@ -635,8 +683,8 @@ scad_finalize
empty = htable_geometries_is_empty(&dev->allgeom);
log_type = empty ? LOG_OUTPUT : LOG_WARNING;
- log = (option & Scad_log_dimTags_all)
- || (!empty && (option & Scad_log_dimTags_only_undeleted));
+ log = (option & SCAD_LOG_DIMTAGS_ALL)
+ || (!empty && (option & SCAD_LOG_DIMTAGS_ONLY_UNDELETED));
if(log) {
logger_print(dev->logger, log_type,
"Finalizing scad; undeleted tags will be automatically unregistered.\n");
@@ -706,17 +754,18 @@ scad_set_options
if(options) {
/* Check non-gmsh option validity if user-provided */
- (void)actual_options->Misc.Step; /* int boolean: always OK */
+ (void)actual_options->Misc.RunUIAtEachStep; /* int boolean: always OK */
(void)actual_options->Misc.SynchronizeOnRunUI; /* int boolean: always OK */
(void)actual_options->Misc.LogRefCounting; /* int boolean: always OK */
- (void)actual_options->Misc.DebugOpenCascadeSync; /* int boolean: always OK */
+ (void)actual_options->Misc.DebugAutoSync; /* int boolean: always OK */
+ (void)actual_options->Misc.DebugEmptyContext; /* int boolean: always OK */
}
dev->options = *actual_options;
/* Update logging policy */
dev->log
- = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
+ = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
exit:
return res;
diff --git a/src/scad_device.h b/src/scad_device.h
@@ -56,7 +56,9 @@ hash_str(const struct str* a)
#include <rsys/hash_table.h>
enum delete_policy {
+ /* Delete the tag and all its lower-dimension components */
Scad_delete_recursive,
+ /* Delete only the tag, not its lower-dimension components */
Scad_delete_non_recursive,
Scad_do_not_delete
};
@@ -196,6 +198,9 @@ LOCAL_SYM res_T
check_device
(const char* function_name);
+LOCAL_SYM res_T
+sync_device(void);
+
LOCAL_SYM struct scad_device*
get_device
(void);
@@ -234,4 +239,8 @@ device_unregister_tags
const enum log_type log_type,
struct scad_geometry* geom);
+LOCAL_SYM res_T
+check_empty_gmsh_occ
+ (struct scad_device* dev);
+
#endif
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -22,6 +22,7 @@
#include <rsys/mem_allocator.h>
#include <rsys/str.h>
#include <rsys/math.h>
+#include <rsys/double2.h>
#include <rsys/double3.h>
#include <rsys/logger.h>
#include <rsys/hash_table.h>
@@ -55,51 +56,50 @@ struct coord_pair {
static res_T
geom_set_name
(struct scad_geometry* geom,
- const char* name)
+ const struct str* name) /* Can be NULL but not "" */
{
struct scad_device* dev = get_device();
- struct mem_allocator* allocator = dev->allocator;
- struct str str_name;
- int name_initialized = 0;
- int same_name;
+ int same_name, name_isnt_null, previous_name_is_null;
res_T res = RES_OK;
ASSERT(geom);
+ ASSERT(!name || !str_is_empty(name));
+ previous_name_is_null = str_is_empty(&geom->name);
if(name) {
- if(strlen(name) == 0) {
- res = RES_BAD_ARG;
- log_error(get_device(), "Geometry name \"\" is invalid.\n");
- goto error;
- }
- str_init(allocator, &str_name);
- name_initialized = 1;
- ERR(str_set(&str_name, name));
- if(htable_names_find(&dev->geometry_names, &str_name)) {
- /* if defined, names must be unique */
+ name_isnt_null = 1;
+ same_name = (!previous_name_is_null) && (0 == str_cmp(name, &geom->name));
+ } else {
+ name_isnt_null = 0;
+ same_name = previous_name_is_null;
+ }
+
+ if(same_name) /* No change needed */
+ goto exit;
+
+ if(name_isnt_null) {
+ struct scad_geometry** g
+ = htable_names_find(&dev->geometry_names, name);
+ if(g) { /* if defined, names must be unique */
res = RES_BAD_ARG;
log_error(get_device(), "Geometry name '%s' is allready in use.\n",
- name);
+ str_cget(name));
goto error;
}
}
- same_name = (!name && str_is_empty(&geom->name))
- || (name && 0 == strcmp(name, str_cget(&geom->name)));
-
- if(!same_name) {
+ if(!previous_name_is_null) {
size_t n = htable_names_erase(&dev->geometry_names, &geom->name);
- ASSERT((n == 1) == !str_is_empty(&geom->name)); (void)n;
- ERR(str_set(&geom->name, name));
+ ASSERT((n == 1)); (void)n;
}
- if(name) {
- ERR(htable_names_set(&dev->geometry_names, &geom->name, &geom));
+ if(name_isnt_null) {
+ ERR(str_copy(&geom->name, name));
+ ERR(htable_names_set(&dev->geometry_names, name, &geom));
} else {
str_clear(&geom->name);
}
exit:
- if(name_initialized) str_release(&str_name);
return res;
error:
goto exit;
@@ -107,8 +107,7 @@ error:
static int
mixed_dim_err_msg
- (const char* name, /* Can be NULL */
- const char* op,
+ (const char* op,
struct scad_geometry** geometries,
const size_t geometries_count,
int* dim)
@@ -122,8 +121,7 @@ mixed_dim_err_msg
if(*dim == INT_MAX) *dim = d;
else if (*dim != d) {
log_error(dev,
- "Dimension mismatch in %s operation creating '%s' geometry.\n",
- op, (name ? name : "unnamed"));
+ "Dimension mismatch in %s operation creating geometry.\n", op);
return 1;
}
}
@@ -133,8 +131,7 @@ mixed_dim_err_msg
static res_T
geometry_create
- (const char* name,
- struct scad_geometry** out_geometry)
+ (struct scad_geometry** out_geometry)
{
res_T res = RES_OK;
struct scad_geometry* geom = NULL;
@@ -153,10 +150,8 @@ geometry_create
ref_init(&geom->ref);
str_init(allocator, &geom->name);
ERR(htable_geometries_set(&dev->allgeom, &geom, &one));
- ERR(geom_set_name(geom, name));
- dev->need_synchro = 1;
- if(dev->options.Misc.LogRefCounting & Scad_log_geometry) {
+ if(dev->options.Misc.LogRefCounting & SCAD_LOG_GEOMETRY) {
if(str_is_empty(&geom->name)) {
logger_print(dev->logger, dev->log_type,
"Creating unnamed geometry %p (count set to 1).\n", (void*)geom);
@@ -178,6 +173,123 @@ error:
goto end;
}
+enum tag_operation {
+ COMMON_TAGS,
+ UNIQUE_TAGS
+};
+
+static res_T
+process_tag_list
+ (const int* dt1,
+ const size_t c1,
+ const int* dt2,
+ const size_t c2,
+ const enum tag_operation op,
+ int** out_dimTags,
+ size_t* out_dimTags_n)
+{
+ res_T res = RES_OK;
+ size_t i, d, c = 0, sz = 0;
+ struct scad_device* dev = get_device();
+ struct mem_allocator* allocator = dev->allocator;
+ struct htable_tags t2, t3;
+ struct htable_tags_iterator it, end;
+ int* dimTags = NULL;
+ const char set1 = BIT(0), set2 = BIT(1), both = set1 | set2;
+
+ ASSERT((dt1 || c1 == 0) && (dt2 || c2 == 0) && out_dimTags && out_dimTags_n);
+
+ htable_tags_init(allocator, &t2);
+ htable_tags_init(allocator, &t3);
+
+ /* list tags and flags them whith set(s) they are from */
+ for(i = 0; i < c1; i += 2) {
+ int dim = dt1[i];
+ int tag = dt1[i+1];
+ struct htable_tags* tn = (dim == 2) ? &t2 : &t3;
+ ASSERT(dim == 2 || dim == 3);
+ ERR(htable_tags_set(tn, &tag, &set1));
+ }
+ for(i = 0; i < c2; i += 2) {
+ char *fl, tmp;
+ int dim = dt2[i];
+ int tag = dt2[i+1];
+ struct htable_tags* tn = (dim == 2) ? &t2 : &t3;
+ ASSERT(dim == 2 || dim == 3);
+ fl = htable_tags_find(tn, &tag);
+ if(fl == NULL) {
+ tmp = set2;
+ fl = &tmp;
+ } else {
+ *fl |= set2;
+ }
+ ERR(htable_tags_set(tn, &tag, fl));
+ }
+
+ switch(op) {
+ case COMMON_TAGS:
+ for(d = 2; d <= 3; d++) {
+ struct htable_tags* tn = (d == 2) ? &t2 : &t3;
+ htable_tags_begin(tn, &it);
+ htable_tags_end(tn, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ if(*htable_tags_iterator_data_get(&it) == both) sz++;
+ htable_tags_iterator_next(&it);
+ }
+ }
+ break;
+ case UNIQUE_TAGS:
+ sz = htable_tags_size_get(&t2) + htable_tags_size_get(&t3);
+ break;
+ default: FATAL("Invalid enum value");
+ }
+
+ /* Build result */
+ if(sz > 0) {
+ dimTags = MEM_ALLOC(allocator, sz * 2 * sizeof(*dimTags));
+ if(!dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ for(d = 2; d <= 3; d++) {
+ struct htable_tags* tn = (d == 2) ? &t2 : &t3;
+ htable_tags_begin(tn, &it);
+ htable_tags_end(tn, &end);
+ while(!htable_tags_iterator_eq(&it, &end)) {
+ int add;
+ switch(op) {
+ case COMMON_TAGS:
+ add = (*htable_tags_iterator_data_get(&it) == both);
+ break;
+ case UNIQUE_TAGS:
+ add = 1;
+ break;
+ default: FATAL("Invalid enum value");
+ }
+ if(add) {
+ dimTags[c++] = 2;
+ dimTags[c++] = *htable_tags_iterator_key_get(&it);
+ }
+ htable_tags_iterator_next(&it);
+ }
+ }
+ ASSERT(sz*2 == c);
+ }
+
+exit:
+ *out_dimTags_n = c;
+ *out_dimTags = dimTags;
+ htable_tags_release(&t2);
+ htable_tags_release(&t3);
+ return res;
+error:
+ MEM_RM(allocator, dimTags);
+ dimTags = NULL;
+ c = 0;
+ goto exit;
+}
+
static res_T
gather_tags
(struct scad_geometry** geometries,
@@ -276,6 +388,8 @@ error:
goto exit;
}
+/* Recursivelly get the tags of geometries, possibly down to dim 0.
+ * Trigger a call to sync_device() */
static res_T
gather_tags_recursive
(struct scad_geometry** geometries,
@@ -312,6 +426,7 @@ gather_tags_recursive
/* Recursively build result by dimension and list constituents,
* begining with dim==3 */
+ ERR(sync_device());
for(dim = 3; dim >= down_to_dim; dim--) {
size_t c = 0;
sz[dim] = 2 * htable_tags_size_get(t+dim);
@@ -404,11 +519,10 @@ geometry_release(ref_T* ref)
size_t n;
ASSERT(ref);
- dev->need_synchro = 1;
geom = CONTAINER_OF(ref, struct scad_geometry, ref);
CHK(RES_OK == device_unregister_tags(dev->log, dev->log_type, geom));
MEM_RM(allocator, geom->gmsh_dimTags);
- if(str_len(&geom->name) != 0) {
+ if(!str_is_empty(&geom->name)) {
n = htable_names_erase(&dev->geometry_names, &geom->name);
ASSERT(n == 1);
}
@@ -435,7 +549,7 @@ scad_geometry_ref_get
ERR(check_device(FUNC_NAME));
ref_get(&geom->ref);
- if(dev->options.Misc.LogRefCounting & Scad_log_geometry) {
+ if(dev->options.Misc.LogRefCounting & SCAD_LOG_GEOMETRY) {
if(str_is_empty(&geom->name)) {
logger_print(dev->logger, dev->log_type,
"Getting a reference on unnamed geometry %p (count set to %lu).\n",
@@ -463,7 +577,7 @@ scad_geometry_ref_put
if(!geom) return RES_BAD_ARG;
ERR(check_device(FUNC_NAME));
- if(dev->options.Misc.LogRefCounting & Scad_log_geometry) {
+ if(dev->options.Misc.LogRefCounting & SCAD_LOG_GEOMETRY) {
if(str_is_empty(&geom->name)) {
logger_print(dev->logger, dev->log_type,
"Putting a reference on unnamed geometry %p (count set to %lu).\n",
@@ -483,6 +597,28 @@ error:
}
res_T
+scad_scene_count
+ (size_t* count)
+{
+ res_T res = RES_OK;
+ struct scad_device* dev = get_device();
+
+ if(!count) {
+ res =RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+
+ *count = htable_geometries_size_get(&dev->allgeom);
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
scad_scene_clear
(void)
{
@@ -506,8 +642,8 @@ scad_scene_clear
htable_geometries_end(&tmp, &end);
empty = htable_geometries_is_empty(&dev->allgeom);
log_type = empty ? LOG_OUTPUT : LOG_WARNING;
- log = (option & Scad_log_dimTags_all)
- || (!empty && (option & Scad_log_dimTags_only_undeleted));
+ log = (option & SCAD_LOG_DIMTAGS_ALL)
+ || (!empty && (option & SCAD_LOG_DIMTAGS_ONLY_UNDELETED));
SWAP(int, dev->log, log);
SWAP(enum log_type, dev->log_type, log_type);
if(dev->log) {
@@ -518,7 +654,9 @@ scad_scene_clear
}
while(!htable_geometries_iterator_eq(&it, &end)) {
struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it);
- ERR(scad_geometry_ref_put(geom));
+ while(geom->ref > 0) {
+ ERR(scad_geometry_ref_put(geom));
+ }
htable_geometries_iterator_next(&it);
}
if(dev->log) {
@@ -562,6 +700,28 @@ error:
}
res_T
+scad_geometry_is_empty
+ (const struct scad_geometry* geom,
+ int* empty)
+{
+ res_T res = RES_OK;
+
+ if(!geom || !empty) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+
+ *empty = (geom->gmsh_dimTags_n == 0);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
scad_geometry_set_custom_data
(struct scad_geometry* geom,
void (*release) (void* data),
@@ -631,11 +791,10 @@ scad_geometry_set_visibility
data = geom->gmsh_dimTags;
sz = geom->gmsh_dimTags_n;
+ ERR(sync_device());
gmshModelSetVisibility(data, sz, visible, recursive, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- get_device()->need_synchro = 1;
-
exit:
return res;
error:
@@ -648,28 +807,34 @@ scad_geometries_clear_mesh
const size_t geometries_count)
{
res_T res = RES_OK;
- int ierr;
- size_t sz;
- int* data = NULL;
+ int ierr, dim;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+ size_t sz[4];
+ int *data[4] = { NULL, NULL, NULL, NULL};
- if(!geometries) {
+ if(!geometries || geometries_count == 0) {
res = RES_BAD_ARG;
goto error;
}
ERR(check_device(FUNC_NAME));
-
allocator = dev->allocator;
- ERR(gather_tags(geometries, geometries_count, &data, &sz));
- gmshModelMeshClear(data, sz, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- dev->need_synchro = 1;
+ ERR(gather_tags_recursive(geometries, geometries_count, 0, data, sz));
+ for(dim = 3; dim >= 0; dim--) {
+ /* Cannot clear the mesh of lower dim entities if linked to higher dim
+ * entities with uncleared mesh: start from the higher dim down to 0 */
+ gmshModelMeshClear(data[dim], sz[dim], &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ }
exit:
- if(allocator) MEM_RM(allocator, data);
+ if(allocator) {
+ for(dim = 3; dim >= 0; dim--) {
+ MEM_RM(allocator, data[dim]);
+ }
+ }
return res;
error:
goto exit;
@@ -689,7 +854,11 @@ scad_geometry_get_name
ERR(check_device(FUNC_NAME));
- *name = str_cget(&geom->name);
+ if(str_is_empty(&geom->name)) {
+ *name = NULL;
+ } else {
+ *name = str_cget(&geom->name);
+ }
exit:
return res;
@@ -707,8 +876,12 @@ scad_geometry_get_mass
size_t i;
int* data = NULL;
size_t sz = 0;
+ double m = 0;
- if(!geom || !mass) goto error;
+ if(!geom || !mass) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
ERR(check_device(FUNC_NAME));
@@ -716,16 +889,16 @@ scad_geometry_get_mass
sz = geom->gmsh_dimTags_n;
ref_dim = data[0];
- *mass = 0;
for(i = 0; i < sz; i += 2) {
- double geom_mass = 0;
+ double geom_mass;
int dim = data[i], tag = data[i+1];
int ierr = 0;
if(ref_dim != dim) goto error;
gmshModelOccGetMass(dim, tag, &geom_mass, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- *mass += geom_mass;
+ m += geom_mass;
}
+ *mass = m;
exit:
return res;
@@ -736,28 +909,42 @@ error:
res_T
scad_geometry_get_closest_point
(struct scad_geometry* geom,
- const double* from,
- double* closest,
- double* closest_distance)
+ const double from[3],
+ double closest[3],
+ double* closest_distance,
+ struct scad_geometry** out_geometry)
{
res_T res = RES_OK;
size_t i = 0;
double* coord = NULL;
double* pcoord = NULL;
double tmp[3], min[3], min_d = DBL_MAX;
+ struct scad_device* dev = get_device();
+ struct darray_int tags;
+ const int* data = NULL;
+ size_t sz = 0;
+ int initialized = 0, min_tag = -1;
+ struct scad_geometry* out = NULL;
- if(!geom || !from || !closest) {
+ if(!geom || !from || !closest || !closest_distance) {
res = RES_BAD_ARG;
goto error;
}
ERR(check_device(FUNC_NAME));
- for(i = 0; i < geom->gmsh_dimTags_n; i += 2) {
+ darray_int_init(dev->allocator, &tags);
+ initialized = 1;
+
+ ERR(get_2d_tags(geom, &tags));
+ data = darray_int_cdata_get(&tags);
+ sz = darray_int_size_get(&tags);
+
+ for(i = 0; i < sz; i++) {
double d;
int ierr = 0;
- int dim = geom->gmsh_dimTags[i];
- int tag = geom->gmsh_dimTags[i + 1];
+ int dim = 2;
+ int tag = data[i];
size_t pcoord_n;
size_t coord_n;
@@ -768,31 +955,55 @@ scad_geometry_get_closest_point
ASSERT(coord_n == 3);
d = d3_len(d3_sub(tmp, from, coord));
if(d < min_d) {
+ min_tag = tag;
min_d = d;
- d3_set(min, tmp);
+ d3_set(min, coord);
}
gmshFree(coord);
gmshFree(pcoord);
coord = pcoord = NULL;
}
+ ASSERT(min_tag != -1);
d3_set(closest, min);
*closest_distance = min_d;
+ if(out_geometry) {
+ ERR(geometry_create(&out));
+ out->gmsh_dimTags =
+ MEM_ALLOC(dev->allocator, 2 * sizeof(*out->gmsh_dimTags));
+ if(!out->gmsh_dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ out->gmsh_dimTags_n = 2;
+ out->gmsh_dimTags[0] = 2;
+ out->gmsh_dimTags[1] = min_tag;
+ ERR(device_register_tags(out));
+ }
exit:
- gmshFree(coord);
- gmshFree(pcoord);
+ if(initialized) darray_int_release(&tags);
+ if(out_geometry) *out_geometry = out;
+ gmshFree(coord);
+ gmshFree(pcoord);
return res;
error:
+ if(out) {
+ SCAD(geometry_ref_put(out));
+ out = NULL;
+ }
goto exit;
}
res_T
scad_geometry_get_centerofmass
(struct scad_geometry* geom,
- double* center)
+ double center[3])
{
res_T res = RES_OK;
- size_t i = 0;
+ double *centers = NULL, *masses = NULL;
+ size_t i = 0, count;
+ struct mem_allocator* allocator;
+ int ierr;
if(!geom || !center) {
res = RES_BAD_ARG;
@@ -801,19 +1012,39 @@ scad_geometry_get_centerofmass
ERR(check_device(FUNC_NAME));
- for(i = 0; i < geom->gmsh_dimTags_n; i += 2) {
- double x, y, z;
- int ierr = 0;
+ ASSERT(geom->gmsh_dimTags_n % 2 == 0);
+ count = geom->gmsh_dimTags_n / 2;
+ if(count == 1) {
int dim = geom->gmsh_dimTags[i];
int tag = geom->gmsh_dimTags[i + 1];
- gmshModelOccGetCenterOfMass(dim, tag, &x, &y, &z, &ierr);
+ gmshModelOccGetCenterOfMass(dim, tag, center, center+1, center+2, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- center[3*i] = x;
- center[3*i + 1] = y;
- center[3*i + 2] = z;
+ } else {
+ double c[3] = { 0, 0, 0 }, tmp[3], m = 0;
+ allocator = get_device()->allocator;
+ centers = MEM_ALLOC(allocator, count * 3 * sizeof(*centers));
+ masses = MEM_ALLOC(allocator, count * sizeof(*masses));
+ if(!centers || !masses) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ for(i = 0; i < count; i++) {
+ int dim = geom->gmsh_dimTags[2*i];
+ int tag = geom->gmsh_dimTags[2*i + 1];
+ gmshModelOccGetCenterOfMass(dim, tag,
+ centers+3*i, centers+3*i+1, centers+3*i+2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccGetMass(dim, tag, masses+i, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ d3_add(c, c, d3_muld(tmp, centers+3*i, masses[i]));
+ m += masses[i];
+ }
+ d3_muld(center, c, 1/m);
}
exit:
+ if(centers) MEM_RM(allocator, centers);
+ if(masses) MEM_RM(allocator, masses);
return res;
error:
goto exit;
@@ -859,8 +1090,7 @@ error:
res_T
scad_add_rectangle
- (const char* name,
- const double xyz[3],
+ (const double xyz[3],
const double dxdy[2],
struct scad_geometry** out_geometry)
{
@@ -881,7 +1111,7 @@ scad_add_rectangle
gmsh_ID = gmshModelOccAddRectangle(SPLIT3(xyz), SPLIT2(dxdy), -1, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags
= MEM_ALLOC(allocator, geom->gmsh_dimTags_n * sizeof(*geom->gmsh_dimTags));
@@ -907,8 +1137,7 @@ error:
res_T
scad_add_disk
- (const char* name,
- const double xyz[3],
+ (const double xyz[3],
const double radius,
struct scad_geometry** out_geometry)
{
@@ -930,7 +1159,7 @@ scad_add_disk
NULL, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags
= MEM_ALLOC(allocator, geom->gmsh_dimTags_n * sizeof(*geom->gmsh_dimTags));
@@ -956,8 +1185,7 @@ error:
res_T
scad_add_polygon
- (const char* name,
- void (*get_position)(const size_t ivert, double pos[2], void* data),
+ (void (*get_position)(const size_t ivert, double pos[2], void* data),
void* data,
const double z,
const size_t count,
@@ -1007,7 +1235,7 @@ scad_add_polygon
gmsh_ID = gmshModelOccAddPlaneSurface(&loop, 1, -1, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
if(!geom->gmsh_dimTags) {
@@ -1036,8 +1264,7 @@ error:
res_T
scad_add_box
- (const char* name,
- const double xyz[3],
+ (const double xyz[3],
const double dxdydz[3],
struct scad_geometry** out_geometry)
{
@@ -1058,7 +1285,7 @@ scad_add_box
gmsh_ID = gmshModelOccAddBox(SPLIT3(xyz), SPLIT3(dxdydz), -1, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
if(!geom->gmsh_dimTags) {
@@ -1083,8 +1310,7 @@ error:
res_T
scad_add_cylinder
- (const char* name,
- const double xyz[3],
+ (const double xyz[3],
const double axis[3],
const double radius,
const double angle,
@@ -1108,7 +1334,7 @@ scad_add_cylinder
angle, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
if(!geom->gmsh_dimTags) {
@@ -1133,8 +1359,7 @@ error:
int
scad_add_sphere
- (const char* name,
- const double xyz[3],
+ (const double xyz[3],
const double radius,
struct scad_geometry** out_geometry)
{
@@ -1156,7 +1381,7 @@ scad_add_sphere
gmshModelOccAddSphere(SPLIT3(xyz), radius, -1, -PI/2, PI/2, 2*PI, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = 2;
geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
if(!geom->gmsh_dimTags) {
@@ -1180,9 +1405,115 @@ error:
}
SCAD_API res_T
-scad_geometries_equal
- (struct scad_geometry* geom1,
- struct scad_geometry* geom2,
+scad_add_cone
+ (const double center[3],
+ const double axis[3],
+ const double radius1,
+ const double radius2,
+ const double angle,
+ struct scad_geometry** cone)
+{
+ res_T res = RES_OK;
+ int ierr, gmsh_ID;
+ struct scad_geometry* geom = NULL;
+ struct scad_device* dev = get_device();
+ struct mem_allocator* allocator = NULL;
+
+ if(!center || !axis || radius1 < 0 || radius2 < 0 || (radius1 == radius2)
+ || angle < 0 || angle > 2*PI || !cone)
+ {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+ allocator = dev->allocator;
+
+ gmsh_ID =
+ gmshModelOccAddCone(SPLIT3(center), SPLIT3(axis), radius1, radius2,
+ -1, 2*PI, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+
+ ERR(geometry_create(&geom));
+ geom->gmsh_dimTags_n = 2;
+ geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
+ if(!geom->gmsh_dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ geom->gmsh_dimTags[0] = 3;
+ geom->gmsh_dimTags[1] = gmsh_ID;
+
+ ERR(device_register_tags(geom));
+
+exit:
+ if(cone) *cone = geom;
+ return res;
+error:
+ if(geom) {
+ SCAD(geometry_ref_put(geom));
+ geom = NULL;
+ }
+ goto exit;
+}
+
+SCAD_API res_T
+scad_add_torus
+ (const double center[3],
+ const double radius1,
+ const double radius2,
+ const double angle,
+ const double z_axis[3], /* Can be NULL */
+ struct scad_geometry** torus)
+{
+ res_T res = RES_OK;
+ int ierr, gmsh_ID;
+ struct scad_geometry* geom = NULL;
+ struct scad_device* dev = get_device();
+ struct mem_allocator* allocator = NULL;
+
+ if(!center || radius1 <= 0 || radius2 <= 0 || angle < 0 || angle > 2*PI
+ || !torus)
+ {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+ allocator = dev->allocator;
+
+ gmsh_ID =
+ gmshModelOccAddTorus(SPLIT3(center), radius1, radius2,
+ -1, 2*PI, z_axis, (z_axis == NULL ? 0 : 3), &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+
+ ERR(geometry_create(&geom));
+ geom->gmsh_dimTags_n = 2;
+ geom->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*geom->gmsh_dimTags));
+ if(!geom->gmsh_dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ geom->gmsh_dimTags[0] = 3;
+ geom->gmsh_dimTags[1] = gmsh_ID;
+
+ ERR(device_register_tags(geom));
+
+exit:
+ if(torus) *torus = geom;
+ return res;
+error:
+ if(geom) {
+ SCAD(geometry_ref_put(geom));
+ geom = NULL;
+ }
+ goto exit;
+}
+
+SCAD_API res_T
+scad_geometry_equal
+ (const struct scad_geometry* geom1,
+ const struct scad_geometry* geom2,
int* equal)
{
res_T res = RES_OK;
@@ -1248,7 +1579,7 @@ error:
SCAD_API res_T
scad_geometry_is_included
- (struct scad_geometry* geometry,
+ (const struct scad_geometry* geometry,
struct scad_geometry** geometries,
const size_t geometries_count,
int* included)
@@ -1260,7 +1591,7 @@ scad_geometry_is_included
int initialized = 0;
size_t i, n;
- if(!geometry || !geometries || !included) {
+ if(!geometry || !geometries || geometries_count == 0 || !included) {
res = RES_BAD_ARG;
goto error;
}
@@ -1318,9 +1649,8 @@ error:
}
res_T
-scad_fuse_geometries
- (const char* name,
- struct scad_geometry** geometries,
+scad_geometries_fuse
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
@@ -1337,6 +1667,10 @@ scad_fuse_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1349,13 +1683,26 @@ scad_fuse_geometries
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccFuse(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map, &mapn, &mapnn,
+ -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccFuse(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
+ ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = tagoutn;
geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
if(!geom->gmsh_dimTags) {
@@ -1367,6 +1714,10 @@ scad_fuse_geometries
ERR(device_register_tags(geom));
exit:
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
if(out_geometry) *out_geometry = geom;
if(allocator) {
MEM_RM(allocator, data1);
@@ -1386,9 +1737,8 @@ error:
}
res_T
-scad_collect_geometries
- (const char* name,
- struct scad_geometry** geometries,
+scad_geometries_collect
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** out_geometry)
{
@@ -1406,7 +1756,7 @@ scad_collect_geometries
ERR(gather_tags(geometries, geometries_count, &data, &sz));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = sz;
geom->gmsh_dimTags = data;
@@ -1424,9 +1774,8 @@ error:
}
res_T
-scad_cut_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_cut
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
@@ -1443,6 +1792,10 @@ scad_cut_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1455,13 +1808,26 @@ scad_cut_geometries
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccCut(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map, &mapn,
+ &mapnn, -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccCut(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
+ ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = tagoutn;
geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
if(!geom->gmsh_dimTags) {
@@ -1481,12 +1847,16 @@ exit:
gmshFree(mapn);
gmshFree(tagout);
free_gmsh_map(map, mapnn);
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
return res;
error:
if(ierr) {
int dim = INT_MAX;
- if(!mixed_dim_err_msg(name, "cut", geometries, geometries_count, &dim))
- mixed_dim_err_msg(name, "cut", tools, tools_count, &dim);
+ if(!mixed_dim_err_msg("cut", geometries, geometries_count, &dim))
+ mixed_dim_err_msg("cut", tools, tools_count, &dim);
if(geom) {
SCAD(geometry_ref_put(geom));
geom = NULL;
@@ -1497,9 +1867,8 @@ error:
}
res_T
-scad_intersect_geometries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+scad_geometries_intersect
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
@@ -1516,6 +1885,10 @@ scad_intersect_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1528,17 +1901,28 @@ scad_intersect_geometries
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccIntersect(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map,
+ &mapn, &mapnn, -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccIntersect(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
+ ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
+ ERR(geometry_create(&geom));
geom->gmsh_dimTags_n = tagoutn;
- if (tagoutn == 0){
- geom->gmsh_dimTags = NULL;
- } else {
+ if(tagoutn != 0){
geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
if(!geom->gmsh_dimTags) {
res = RES_MEM_ERR;
@@ -1558,6 +1942,10 @@ exit:
gmshFree(mapn);
gmshFree(tagout);
free_gmsh_map(map, mapnn);
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
return res;
error:
if(geom) {
@@ -1570,34 +1958,35 @@ error:
res_T
scad_geometries_common_boundaries
- (const char* name, /* Can be NULL */
- struct scad_geometry** geometries,
+ (struct scad_geometry** geometries,
const size_t geometries_count,
struct scad_geometry** tools,
const size_t tools_count,
- struct scad_geometry** out_geometry)
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count)
{
res_T res = RES_OK;
int* tagout = NULL;
- int** map = NULL;
- size_t* mapn = NULL;
- size_t tagoutn, mapnn = 0, sz1, sz2;
+ size_t tagoutn, sz1, sz2, u_sz;
int* data1 = NULL;
int* data2 = NULL;
+ int* unique = NULL;
int ierr = 0;
int* bound1 = NULL;
int* bound2 = NULL;
size_t n1, n2;
- struct scad_geometry* geom = NULL;
+ struct scad_geometry** out_geom = NULL;
struct mem_allocator* allocator = NULL;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
- enum log_type log_type = dev->log_type;
- size_t i;
+ int log;
+ enum log_type log_type;
+ size_t i, c = 0, n;
struct str msg;
- int init = 0;
+ int msg_initialized = 0;
- if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
+ if(!geometries || !geometries_count || !tools || !tools_count
+ || !out_boundaries || !out_count)
+ {
res = RES_BAD_ARG;
goto error;
}
@@ -1608,39 +1997,30 @@ scad_geometries_common_boundaries
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 longer used by any star-cad geometry */
+ /* data1 and data2 can have tags in common: deduplicate them!
+ * (even if the refcounting stuff can manage duplicates) */
+ ERR(process_tag_list(data1, sz1, data2, sz2, UNIQUE_TAGS, &unique, &u_sz));
+
+ ERR(sync_device());
gmshModelGetBoundary(data1, sz1, &bound1, &n1, 1, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
gmshModelGetBoundary(data2, sz2, &bound2, &n2, 1, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- gmshModelOccIntersect(bound1, n1, bound2, n2, &tagout, &tagoutn, &map,
- &mapn, &mapnn, -1, 0/*no delete*/, 0/*no delete*/, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
- geom->gmsh_dimTags_n = tagoutn;
+ ERR(process_tag_list(bound1, n1, bound2, n2, COMMON_TAGS, &tagout, &tagoutn));
+ ASSERT(tagoutn % 2 == 0);
+ c = tagoutn / 2;
+
if(tagoutn == 0) {
- if(name) {
- log_message(dev, "Common boundary '%s' is empty.\n", name);
- } else {
- log_message(dev, "Unnamed common boundary %p is empty.\n", (void*)geom);
- }
- geom->gmsh_dimTags = NULL;
- } else {
- geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
- if(!geom->gmsh_dimTags) {
- res = RES_MEM_ERR;
- goto error;
- }
- memcpy(geom->gmsh_dimTags, tagout, tagoutn * sizeof(*tagout));
+ log_message(dev, "Common boundary list is empty.\n");
+ goto exit;
}
- ERR(device_register_tags(geom));
-
+ log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
+ log_type = dev->log_type;
if(log) {
str_init(allocator, &msg);
- init = 1;
+ msg_initialized = 1;
logger_print(dev->logger, log_type,
"Common boundaries specific tag management:\n");
ERR(str_printf(&msg, " tags ["));
@@ -1650,59 +2030,73 @@ scad_geometries_common_boundaries
ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
}
ERR(str_append_printf(&msg, "] getting a ref to tags ["));
- for(i = 0; i < sz1; i += 2) {
- const int dim = data1[i];
- const int tag = data1[i+1];
+ for(i = 0; i < u_sz; i += 2) {
+ const int dim = unique[i];
+ const int tag = unique[i+1];
ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag));
}
- for(i = 0; i < sz2; i += 2) {
- const int dim = data2[i];
- const int tag = data2[i+1];
- ERR(str_append_printf(&msg, ", %d.%d", dim, tag));
- }
logger_print(dev->logger, log_type, "%s].\n", str_cget(&msg));
}
- for(i = 0; i < tagoutn; i += 2) {
+
+ out_geom = MEM_CALLOC(allocator, c, sizeof(*out_geom));
+ if(!out_geom) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ for(i = 0, n = 0; i < tagoutn; i += 2, n++) {
int dim = tagout[i];
int tag = tagout[i+1];
- struct tag_desc* desc = device_get_description(dim, tag);
+ struct tag_desc* desc;
ASSERT(dim == 2);
- if(!desc) {
- res = RES_BAD_OP;
+ ERR(geometry_create(out_geom+n));
+ out_geom[n]->gmsh_dimTags_n = 2;
+ out_geom[n]->gmsh_dimTags = MEM_ALLOC(allocator,
+ 2 * sizeof(*out_geom[n]->gmsh_dimTags));
+ if(!out_geom[n]->gmsh_dimTags) {
+ res = RES_MEM_ERR;
goto error;
}
+ out_geom[n]->gmsh_dimTags[0] = dim;
+ out_geom[n]->gmsh_dimTags[1] = tag;
+ ERR(device_register_tags(out_geom[n]));
/* Need to protect out_geometry's tags by getting a ref on input tags or
* deleting input geometry will possibly delete them */
- ERR(device_register_ref_to_tags(dim, tag, data1, sz1));
- ERR(device_register_ref_to_tags(dim, tag, data2, sz2));
+ ERR(device_register_ref_to_tags(dim, tag, unique, u_sz));
/* As the 2D tags will be deleted when the 3D tag they are part of are
* deleted, they shouldn't be deleted when the geometry they belongs to are
* released. */
+ desc = device_get_description(dim, tag);
+ ASSERT(desc);
desc->delete_policy = Scad_do_not_delete;
}
exit:
- if(init) str_release(&msg);
- if(out_geometry) *out_geometry = geom;
+ if(msg_initialized) str_release(&msg);
+ if(out_boundaries) *out_boundaries = out_geom;
+ if(out_count) *out_count = c;
if(allocator) {
MEM_RM(allocator, data1);
MEM_RM(allocator, data2);
+ MEM_RM(allocator, unique);
+ MEM_RM(allocator, tagout);
}
gmshFree(bound1);
gmshFree(bound2);
- gmshFree(mapn);
- gmshFree(tagout);
- free_gmsh_map(map, mapnn);
return res;
error:
if(ierr) {
int dim = INT_MAX;
- if(!mixed_dim_err_msg(name, "common boundary", geometries, geometries_count, &dim))
- mixed_dim_err_msg(name, "common boundary", tools, tools_count, &dim);
+ if(!mixed_dim_err_msg("common boundary", geometries, geometries_count, &dim))
+ mixed_dim_err_msg("common boundary", tools, tools_count, &dim);
}
- if(geom) {
- SCAD(geometry_ref_put(geom));
- geom = NULL;
+ if(out_geom) {
+ for(i = 0; i < c; i++) {
+ if(out_geom[i]) SCAD(geometry_ref_put(out_geom[i]));
+ }
+ MEM_RM(allocator, out_geom);
+ out_geom = NULL;
+ c = 0;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
goto exit;
@@ -1714,7 +2108,6 @@ scad_geometry_rotate
const double pt[3],
const double axis[3],
const double angle,
- const char* name, /* Can be NULL */
struct scad_geometry** out_geometry)
{
int ierr = 0;
@@ -1728,11 +2121,10 @@ scad_geometry_rotate
ERR(check_device(FUNC_NAME));
- ERR(scad_geometry_copy(geom, name, &out));
+ ERR(scad_geometry_copy(geom, &out));
gmshModelOccRotate(out->gmsh_dimTags, out->gmsh_dimTags_n, SPLIT3(pt),
SPLIT3(axis), angle, &ierr);
- get_device()->need_synchro = 1;
ERR(gmsh_err_to_res_T(ierr));
exit:
@@ -1746,8 +2138,7 @@ error:
res_T
scad_geometry_extrude
- (struct scad_geometry* geom,
- const char* name,
+ (const struct scad_geometry* geom,
const double dxdydz[3],
struct scad_geometry** out_geometry)
{
@@ -1755,16 +2146,13 @@ scad_geometry_extrude
int *tagout = NULL;
size_t tagoutn;
size_t i;
-#ifndef NDEBUG
- size_t j;
-#endif
int *ed, *extrude_data = NULL;
size_t extrude_sz = 0;
int ierr = 0;
struct scad_geometry* extrude_geom = NULL;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
- enum log_type log_type = dev->log_type;
+ int log;
+ enum log_type log_type;
struct mem_allocator* allocator = NULL;
struct str msg;
int init = 0;
@@ -1777,10 +2165,27 @@ scad_geometry_extrude
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
+ /* OCC cannot extrude 3D geometries */
+ for(i = 0; i < geom->gmsh_dimTags_n; i += 2) {
+ const int dim = geom->gmsh_dimTags[i];
+ if(dim != 2) {
+ if(str_is_empty(&geom->name)) {
+ log_error(get_device(),
+ "Cannot extrude unnamed 3D geometry '%p'.\n",
+ (void*)geom);
+ } else {
+ log_error(get_device(),
+ "Cannot extrude 3D geometry '%s'.\n",
+ str_cget(&geom->name));
+ }
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
gmshModelOccExtrude(geom->gmsh_dimTags, geom->gmsh_dimTags_n, SPLIT3(dxdydz),
&tagout, &tagoutn, NULL, 0, NULL, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- get_device()->need_synchro = 1;
/* Output includes both the 3D result and its 2D constituents.
* Keep only 3D entities. */
@@ -1797,24 +2202,20 @@ scad_geometry_extrude
for(i = 0; i < tagoutn; i += 2) {
int dim = tagout[i];
int tag = tagout[i+1];
-#ifndef NDEBUG
- /* Expecting geom's tags not part of tagout */
- for(j = 0; j < geom->gmsh_dimTags_n; j += 2) {
- ASSERT(dim != geom->gmsh_dimTags[j] || tag != geom->gmsh_dimTags[j+1]);
- }
-#endif
if(dim == 3) {
*ed++ = dim;
*ed++ = tag;
}
}
- ERR(geometry_create(name, &extrude_geom));
+ ERR(geometry_create(&extrude_geom));
extrude_geom->gmsh_dimTags_n = extrude_sz;
extrude_geom->gmsh_dimTags = extrude_data;
ERR(device_register_tags(extrude_geom));
+ log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
+ log_type = dev->log_type;
if(log) {
str_init(allocator, &msg);
init = 1;
@@ -1838,15 +2239,12 @@ scad_geometry_extrude
const int tag = geom->gmsh_dimTags[i+1];
struct tag_desc* desc = device_get_description(dim, tag);
ASSERT(dim == 2);
- if(!desc) {
- res = RES_BAD_OP;
- goto error;
- }
+ ASSERT(desc != NULL);
/* Need to protect input geometry's tags by getting a ref on output tags or
* deleting out_geometry will possibly delete them */
ERR(device_register_ref_to_tags(dim, tag, extrude_data, extrude_sz));
/* As the 2D tags will be deleted when the 3D tag they are part of are
- * deleted, they shouldn't be deleted when the geometry they belongs to are
+ * deleted, they shouldn't be deleted when the geometry they belongs to is
* released. */
desc->delete_policy = Scad_do_not_delete;
}
@@ -1868,21 +2266,19 @@ error:
res_T
scad_geometry_explode
(const struct scad_geometry* geom,
- const char* prefix_name, /* Can be NULL */
struct scad_geometry*** out_geometry,
- size_t* out_geometry_n)
+ size_t* out_n)
{
res_T res = RES_OK;
int* data = NULL;
- size_t i, sz = 0;
+ size_t i, n, sz = 0;
struct scad_geometry** geom_array = NULL;
struct str name;
int name_initialized = 0;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- const char* base_name = NULL;
- if(!geom || !out_geometry || !out_geometry_n) {
+ if(!geom || !out_geometry || !out_n) {
res = RES_BAD_ARG;
goto error;
}
@@ -1900,42 +2296,32 @@ scad_geometry_explode
goto error;
}
- if(prefix_name || !str_is_empty(&geom->name)) {
- base_name = prefix_name ? prefix_name : str_cget(&geom->name);
- str_init(allocator, &name);
- name_initialized = 1;
- }
-
- for(i = 0; i < sz/2; ++i) {
- if(base_name) {
- ERR(str_set(&name, base_name));
- ERR(str_append_printf(&name,"_%lu", (unsigned long)i));
- ERR(geometry_create(str_cget(&name), geom_array+i));
- } else {
- ERR(geometry_create(NULL, geom_array+i));
- }
- geom_array[i]->gmsh_dimTags_n = 2;
- geom_array[i]->gmsh_dimTags
- = MEM_ALLOC(allocator, 2 * sizeof(*geom_array[i]->gmsh_dimTags));
- if(!geom_array[i]->gmsh_dimTags) {
+ for(i = 0, n = 0; i < sz; i += 2, n++) {
+ const int dim = data[i];
+ const int tag = data[i+1];
+ ERR(geometry_create(geom_array+n));
+ geom_array[n]->gmsh_dimTags_n = 2;
+ geom_array[n]->gmsh_dimTags
+ = MEM_ALLOC(allocator, 2 * sizeof(*geom_array[0]->gmsh_dimTags));
+ if(!geom_array[n]->gmsh_dimTags) {
res = RES_MEM_ERR;
goto error;
}
- geom_array[i]->gmsh_dimTags[0] = data[2*i];
- geom_array[i]->gmsh_dimTags[1] = data[2*i+1];
+ geom_array[n]->gmsh_dimTags[0] = dim;
+ geom_array[n]->gmsh_dimTags[1] = tag;
- ERR(device_register_tags(geom_array[i]));
+ ERR(device_register_tags(geom_array[n]));
}
exit:
- if(out_geometry_n) *out_geometry_n = sz/2 ;
+ if(out_n) *out_n = sz/2 ;
if(out_geometry) *out_geometry = geom_array;
if(name_initialized) str_release(&name);
return res;
error:
if(geom_array) {
- for(i = 0; i < sz/2; i++) {
- if(geom_array[i]) SCAD(geometry_ref_put(geom_array[i]));
+ for(i = 0, n = 0; i < sz; i += 2, n++) {
+ if(geom_array[n]) SCAD(geometry_ref_put(geom_array[n]));
}
MEM_RM(allocator, geom_array);
geom_array = NULL;
@@ -1947,7 +2333,6 @@ error:
res_T
scad_geometry_copy
(const struct scad_geometry* geom,
- const char* name, /* Can be NULL */
struct scad_geometry** out_geometry)
{
res_T res = RES_OK;
@@ -1970,10 +2355,11 @@ scad_geometry_copy
sz1 = geom->gmsh_dimTags_n;
data1 = geom->gmsh_dimTags;
gmshModelOccCopy(data1, sz1, &tagout, &tagoutn, &ierr);
- get_device()->need_synchro = 1;
+
+ ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, ©));
+ ERR(geometry_create(©));
copy->gmsh_dimTags_n = tagoutn;
copy->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
if(!copy->gmsh_dimTags) {
@@ -1998,11 +2384,60 @@ error:
}
res_T
-scad_geometry_rename
+scad_geometries_set_name
+ (struct scad_geometry** geometries,
+ const size_t geometries_count,
+ const char* prefix_name, /* Can be NULL */
+ const size_t from_rank) /* Can be NULL */
+{
+ res_T res = RES_OK;
+ struct str tmp;
+ int initialized = 0;
+ struct mem_allocator* allocator = NULL;
+ size_t i, cpt;
+
+ if(!geometries || geometries_count == 0) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+
+ if(!prefix_name) {
+ for(i = 0; i < geometries_count; i++) {
+ ERR(geom_set_name(geometries[i], NULL));
+ }
+ }
+ else if(strlen(prefix_name) == 0) {
+ log_error(get_device(), "Geometry name \"\" is invalid.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ } else {
+ str_init(allocator, &tmp);
+ initialized = 1;
+ cpt = from_rank;
+ for(i = 0; i < geometries_count; i++) {
+ ERR(str_printf(&tmp, "%s_%ld", prefix_name, cpt++));
+ ERR(geom_set_name(geometries[i], &tmp));
+ }
+ }
+
+exit:
+ if(initialized) str_release(&tmp);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scad_geometry_set_name
(struct scad_geometry* geom,
const char* name) /* Can be NULL */
{
res_T res = RES_OK;
+ struct str tmp;
+ int initialized = 0;
+ struct mem_allocator* allocator = NULL;
if(!geom) {
res = RES_BAD_ARG;
@@ -2011,9 +2446,22 @@ scad_geometry_rename
ERR(check_device(FUNC_NAME));
- ERR(geom_set_name(geom, name));
+ if(!name) {
+ ERR(geom_set_name(geom, NULL));
+ }
+ else if(strlen(name) == 0) {
+ log_error(get_device(), "Geometry name \"\" is invalid.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ } else {
+ str_init(allocator, &tmp);
+ initialized = 1;
+ ERR(str_set(&tmp, name));
+ ERR(geom_set_name(geom, &tmp));
+ }
exit:
+ if(initialized) str_release(&tmp);
return res;
error:
goto exit;
@@ -2023,7 +2471,6 @@ res_T
scad_geometry_translate
(const struct scad_geometry* geom,
const double dxdydz[3],
- const char* name, /* Can be NULL */
struct scad_geometry** out_geometry)
{
int ierr = 0;
@@ -2037,11 +2484,10 @@ scad_geometry_translate
ERR(check_device(FUNC_NAME));
- ERR(scad_geometry_copy(geom, name, &out));
+ ERR(scad_geometry_copy(geom, &out));
gmshModelOccTranslate(out->gmsh_dimTags, out->gmsh_dimTags_n, SPLIT3(dxdydz),
&ierr);
- get_device()->need_synchro = 1;
ERR(gmsh_err_to_res_T(ierr));
exit:
@@ -2094,8 +2540,8 @@ scad_geometries_partition
int dont_call_fragment = 0;
char* overlap = NULL;
const int invalid_flags =
- ~(Scad_allow_overlapping | Scad_dump_on_overlapping_error);
- const int dump_overlapping_err = flags & Scad_dump_on_overlapping_error;
+ ~(SCAD_ALLOW_OVERLAPPING | SCAD_DUMP_ON_OVERLAPPING_ERROR);
+ const int dump_overlapping_err = flags & SCAD_DUMP_ON_OVERLAPPING_ERROR;
static size_t err_cpt = 0;
struct str tmp;
@@ -2144,10 +2590,8 @@ scad_geometries_partition
ERR(gmsh_err_to_res_T(ierr));
ASSERT(sz == 2*mapnn); /* Because input tags where deduplicated */
- get_device()->need_synchro = 1;
-
/* Check first if there was an overlapping problem */
- if(!(flags & Scad_allow_overlapping)) {
+ if(!(flags & SCAD_ALLOW_OVERLAPPING)) {
/* No overlapping means that each tag in geometries is translated into a
* single tag in map */
size_t ov = 0;
@@ -2185,25 +2629,25 @@ scad_geometries_partition
str_printf(&tmp, "unamed_partition_error_%lu_%lu",
err_cpt, (long unsigned)item_cpt++);
tmp_err =
- scad_stl_export(g, str_cget(&tmp), Scad_keep_normals_unchanged, 0);
+ scad_stl_export(g, str_cget(&tmp), SCAD_KEEP_NORMALS_UNCHANGED, 0);
if(tmp_err == RES_OK) {
log_error(get_device(),
"Unnamed geometry '%p' overlapping (dumped in '%s).\n",
(void*)g, str_cget(&tmp));
} else {
- log_error(get_device(), "Could not dump geoemtry.\n");
+ log_error(get_device(), "Could not dump geometry.\n");
}
} else {
str_printf(&tmp, "%s_partition_error_%lu_%lu",
str_cget(&g->name), err_cpt, (long unsigned)item_cpt++);
tmp_err =
- scad_stl_export(g, str_cget(&tmp), Scad_keep_normals_unchanged, 0);
+ scad_stl_export(g, str_cget(&tmp), SCAD_KEEP_NORMALS_UNCHANGED, 0);
if(tmp_err == RES_OK) {
log_error(get_device(),
"Geometry '%s' overlapping (dumped in '%s).\n",
str_cget(&g->name), str_cget(&tmp));
} else {
- log_error(get_device(), "Could not dump geoemtry.\n");
+ log_error(get_device(), "Could not dump geometry.\n");
}
}
}
@@ -2292,7 +2736,7 @@ scad_geometries_partition
ASSERT(c == 2*n);
/* Create geometry */
- ERR(geometry_create(NULL, geoms+i));
+ ERR(geometry_create(geoms+i));
geoms[i]->gmsh_dimTags_n = c;
geoms[i]->gmsh_dimTags = dt;
ERR(device_register_tags(geoms[i]));
@@ -2326,6 +2770,9 @@ error:
}
if(tagout) {
gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
+ /* Do not check ierr, first because we are in error handler already, but
+ * also because an error is expected if these OCC entities have allready
+ * been freed through the call to ref_put above */
}
goto exit;
}
@@ -2343,14 +2790,15 @@ scad_geometries_swap
struct mem_allocator* allocator = NULL;
struct str tmp, msg;
- if(!pool1 || !pool2) {
+ if(!pool1 || !pool2 || !flags || count == 0) {
res = RES_BAD_ARG;
goto error;
}
+ ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- if(flags & Scad_swap_name) str_init(allocator, &tmp);
- if(flags & Scad_swap_geometry && dev->log) str_init(allocator, &msg);
+ if(flags & SCAD_SWAP_NAME) str_init(allocator, &tmp);
+ if(flags & SCAD_SWAP_GEOMETRY && dev->log) str_init(allocator, &msg);
for(i = 0; i < count; i++) {
struct scad_geometry *g1 = pool1[i], *g2 = pool2[i];
size_t c1 = g1->gmsh_dimTags_n, c2 = g2->gmsh_dimTags_n;
@@ -2358,7 +2806,7 @@ scad_geometries_swap
if(pool1[i] == pool2[i])
continue;
/* Swap content according to flags. Don't swap refcount! */
- if(flags & Scad_swap_name) {
+ if(flags & SCAD_SWAP_NAME) {
if(dev->log) {
if(str_is_empty(&g1->name) && str_is_empty(&g2->name)) {
/* Do nothing */
@@ -2396,7 +2844,7 @@ scad_geometries_swap
ERR(str_copy(&g2->name, &tmp));
}
}
- if(flags & Scad_swap_geometry) {
+ if(flags & SCAD_SWAP_GEOMETRY) {
/* Swap in tag2geom tables */
size_t n;
if(dev->log) {
@@ -2431,8 +2879,7 @@ scad_geometries_swap
for(n = 0; n < c2; n += 2) {
int dim = dt2[n];
int tag = dt2[n+1];
- if(n) { ERR(str_append_printf(&msg, ",")); }
- ERR(str_append_printf(&msg, " %d.%d", dim, tag));
+ ERR(str_append_printf(&msg, (n ? ", %d.%d" : "%d.%d"), dim, tag));
}
logger_print(dev->logger, dev->log_type, "%s.\n", str_cget(&msg));
if(str_is_empty(&g2->name)) {
@@ -2457,35 +2904,35 @@ scad_geometries_swap
}
exit:
- if(flags & Scad_swap_name) str_release(&tmp);
- if(flags & Scad_swap_geometry && dev->log) str_release(&msg);
+ if(flags & SCAD_SWAP_NAME) str_release(&tmp);
+ if(flags & SCAD_SWAP_GEOMETRY && dev->log) str_release(&msg);
return res;
error:
goto exit;
}
res_T
-scad_geometry_boundary
- (const char* name,
- struct scad_geometry** geometries,
+scad_geometries_boundaries
+ (struct scad_geometry** geometries,
const size_t geometries_count,
- struct scad_geometry** out_geometry)
+ struct scad_geometry*** out_boundaries,
+ size_t *out_count)
{
res_T res = RES_OK;
int* tagout = NULL;
size_t tagoutn, sz;
int* data = NULL;
int ierr = 0;
- struct scad_geometry* geom = NULL;
+ struct scad_geometry** out_geom = NULL;
struct mem_allocator* allocator = NULL;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
- enum log_type log_type = dev->log_type;
- size_t i;
+ int log;
+ enum log_type log_type;
+ size_t i, c = 0, n;
struct str msg;
- int init = 0;
+ int msg_initialized = 0;
- if(!geometries || !out_geometry) {
+ if(!geometries || geometries_count == 0 || !out_boundaries || !out_count) {
res = RES_BAD_ARG;
goto error;
}
@@ -2494,23 +2941,23 @@ scad_geometry_boundary
allocator = dev->allocator;
ERR(gather_tags(geometries, geometries_count, &data, &sz));
+ ERR(sync_device());
gmshModelGetBoundary(data, sz, &tagout, &tagoutn, 1, 0, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ERR(geometry_create(name, &geom));
- geom->gmsh_dimTags_n = tagoutn;
- geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * 2 * sizeof(*tagout));
- if(!geom->gmsh_dimTags) {
+ ASSERT(tagoutn % 2 == 0);
+ c = tagoutn / 2;
+ out_geom = MEM_CALLOC(allocator, c, sizeof(*out_geom));
+ if(!out_geom) {
res = RES_MEM_ERR;
goto error;
}
- memcpy(geom->gmsh_dimTags, tagout, tagoutn * sizeof(*tagout));
-
- ERR(device_register_tags(geom));
+ log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
+ log_type = dev->log_type;
if(log) {
str_init(allocator, &msg);
- init = 1;
+ msg_initialized = 1;
logger_print(dev->logger, log_type, "Boundary specific tag management:\n");
ERR(str_printf(&msg, " tags ["));
for(i = 0; i < tagoutn; i += 2) {
@@ -2526,34 +2973,50 @@ scad_geometry_boundary
}
logger_print(dev->logger, log_type, "%s].\n", str_cget(&msg));
}
- for(i = 0; i < tagoutn; i += 2) {
+
+ for(i = 0, n = 0; i < tagoutn; i += 2, n++) {
int dim = tagout[i];
int tag = tagout[i+1];
- struct tag_desc* desc = device_get_description(dim, tag);
+ struct tag_desc* desc = NULL;
ASSERT(dim == 2);
- if(!desc) {
- res = RES_BAD_OP;
+ ERR(geometry_create(out_geom+n));
+ out_geom[n]->gmsh_dimTags_n = 2;
+ out_geom[n]->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*tagout));
+ if(!out_geom[n]->gmsh_dimTags) {
+ res = RES_MEM_ERR;
goto error;
}
+ out_geom[n]->gmsh_dimTags[0] = dim;
+ out_geom[n]->gmsh_dimTags[1] = tag;
+
+ ERR(device_register_tags(out_geom[n]));
+
/* Need to protect out_geometry's tags by getting a ref on input tags or
* deleting input geometry will possibly delete them */
ERR(device_register_ref_to_tags(dim, tag, data, sz));
/* As the 2D tags will be deleted when the 3D tag they are part of are
* deleted, they shouldn't be deleted when the geometry they belongs to are
* released. */
+ desc = device_get_description(dim, tag);
+ ASSERT(desc);
desc->delete_policy = Scad_do_not_delete;
}
exit:
- if(init) str_release(&msg);
+ if(msg_initialized) str_release(&msg);
if(allocator) MEM_RM(allocator, data);
- if(out_geometry) *out_geometry = geom;
+ if(out_boundaries) *out_boundaries = out_geom;
+ if(out_count) *out_count = c;
gmshFree(tagout);
return res;
error:
- if(geom) {
- SCAD(geometry_ref_put(geom));
- geom = NULL;
+ if(out_geom) {
+ for(i = 0; i < c; i++) {
+ if(out_geom[i]) SCAD(geometry_ref_put(out_geom[i]));
+ }
+ MEM_RM(allocator, out_geom);
+ out_geom = NULL;
+ c = 0;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
goto exit;
@@ -2562,9 +3025,8 @@ error:
res_T
scad_step_import
(const char* filename,
- const char* name,
struct scad_geometry*** out_geometry,
- size_t* out_geometry_n)
+ size_t* out_n)
{
int ierr;
int* tagout = NULL;
@@ -2576,7 +3038,7 @@ scad_step_import
struct scad_device* dev = get_device();
res_T res = RES_OK;
- if(!filename || !out_geometry || !out_geometry_n) {
+ if(!filename || !out_geometry || !out_n) {
res = RES_BAD_ARG;
goto error;
}
@@ -2599,14 +3061,7 @@ scad_step_import
str_init(allocator, &strname);
name_initialized = 1;
for(i=0; i<ga_sz; ++i) {
- if (name) {
- ERR(str_set(&strname, name));
- ERR(str_append_printf(&strname,"_%lu", (unsigned long)i));
- ERR(geometry_create(str_cget(&strname), geom_array+i));
- } else {
- ERR(geometry_create(NULL, geom_array+i));
- }
-
+ ERR(geometry_create(geom_array+i));
geom_array[i]->gmsh_dimTags_n = 2;
geom_array[i]->gmsh_dimTags
= MEM_ALLOC(allocator, 2 * sizeof(*geom_array[i]->gmsh_dimTags));
@@ -2622,7 +3077,7 @@ scad_step_import
exit:
gmshFree(tagout);
- if(out_geometry_n) *out_geometry_n = ga_sz ;
+ if(out_n) *out_n = ga_sz ;
if(out_geometry) *out_geometry = geom_array;
if(name_initialized) str_release(&strname);
return res;
@@ -2640,11 +3095,10 @@ error:
}
res_T
-scad_geometry_normal
+scad_geometry_get_normal
(struct scad_geometry* geom,
- double p[3],
+ const double p[3],
double N[3],
- const char* name, /* Can be NULL */
struct scad_geometry** out_geometry)
{
res_T res = RES_OK;
@@ -2654,16 +3108,19 @@ scad_geometry_normal
size_t sz = 0;
struct scad_geometry* out = NULL;
struct scad_device* dev = get_device();
- int log = (dev->options.Misc.LogRefCounting & Scad_log_dimTags_all);
- enum log_type log_type = dev->log_type;
+ int log;
+ enum log_type log_type;
struct mem_allocator* allocator = NULL;
double* coord = NULL;
double* pcoord = NULL;
double* normals = NULL;
struct darray_int tags;
int initialized = 0;
+ double d, min_d = DBL_MAX, pcoord_min[2];
+ int min_tag = -1;
+ size_t normals_n;
- if(!geom || !p || !N || !out_geometry) {
+ if(!geom || !p || !N) {
res = RES_BAD_ARG;
goto error;
}
@@ -2678,71 +3135,67 @@ scad_geometry_normal
data = darray_int_cdata_get(&tags);
sz = darray_int_size_get(&tags);
+ log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL);
+ log_type = dev->log_type;
+
+ /* Find the closest point on tags of geom */
for(i = 0; i < sz; ++i) {
size_t pcoord_n;
size_t coord_n;
- size_t normals_n;
const int dim = 2;
int tag = data[i];
+ double tmp[3];
gmshModelGetClosestPoint(dim, tag, p, 3, &coord, &coord_n, &pcoord,
&pcoord_n, &ierr);
ERR(gmsh_err_to_res_T(ierr));
ASSERT(pcoord_n == (size_t)dim);
ASSERT(coord_n == 3);
-
- if(d3_eq_eps(p, coord, 1e-6)) {
- gmshModelGetNormal(tag, pcoord, pcoord_n, &normals, &normals_n, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- ASSERT(normals_n == 3);
-
- ERR(geometry_create(name, &out));
- out->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*out->gmsh_dimTags));
- if(!out->gmsh_dimTags) {
- res = RES_MEM_ERR;
- goto error;
- }
- out->gmsh_dimTags_n = 2;
- out->gmsh_dimTags[0] = dim;
- out->gmsh_dimTags[1] = tag;
- d3_set(N, normals);
-
- ERR(device_register_tags(out));
-
- /* Need to protect geometries' tags or deleting out geometry will possibly
- * delete them */
- if(log) {
- logger_print(dev->logger, log_type,
- "Tag %d.%d getting a reference to other tags.\n", dim, tag);
- }
- ERR(device_register_ref_to_tags(dim, tag, geom->gmsh_dimTags,
- geom->gmsh_dimTags_n));
- if(log) {
- logger_print(dev->logger, log_type,
- "Tag %d.%d getting a reference to other tags done.\n", dim, tag);
- }
-
- break;
+ d = d3_len(d3_sub(tmp, p, coord));
+ if(d < min_d) {
+ min_d = d;
+ min_tag = tag;
+ d2_set(pcoord_min, pcoord);
}
-
gmshFree(coord);
gmshFree(pcoord);
coord = pcoord = NULL;
}
- if(!out) { /* Could not find a matching surface */
- if(str_is_empty(&geom->name)) {
- log_warning(get_device(),
- "Could not get normal at vertex %g %g %g "
- "as unamed geometry %p is not close enough.\n",
- SPLIT3(p), (void*)geom);
- } else {
- log_warning(get_device(),
- "Could not get normal at vertex %g %g %g "
- "as geometry %s is not close enough.\n",
- SPLIT3(p), str_cget(&geom->name));
+ if(min_d == DBL_MAX) { /* At least if sz==0 */
+ goto exit;
+ }
+
+ /* Get the normal at the selected point */
+ gmshModelGetNormal(min_tag, pcoord_min, 2, &normals, &normals_n, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ ASSERT(normals_n == 3);
+ d3_set(N, normals);
+
+ /* Create a geometry if required */
+ if(out_geometry) {
+ ERR(geometry_create(&out));
+ out->gmsh_dimTags = MEM_ALLOC(allocator, 2 * sizeof(*out->gmsh_dimTags));
+ if(!out->gmsh_dimTags) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ out->gmsh_dimTags_n = 2;
+ out->gmsh_dimTags[0] = 2;
+ out->gmsh_dimTags[1] = min_tag;
+ ERR(device_register_tags(out));
+
+ /* Need to protect geometries' tags or deleting out geometry will possibly
+ * delete them */
+ if(log) {
+ logger_print(dev->logger, log_type,
+ "Tag %d.%d getting a reference to other tags.\n", 2, min_tag);
+ }
+ ERR(device_register_ref_to_tags(2, min_tag, geom->gmsh_dimTags,
+ geom->gmsh_dimTags_n));
+ if(log) {
+ logger_print(dev->logger, log_type,
+ "Tag %d.%d getting a reference to other tags done.\n", 2, min_tag);
}
- res = RES_BAD_ARG;
- goto error;
}
exit:
@@ -2753,6 +3206,10 @@ exit:
if(out_geometry) *out_geometry = out;
return res;
error:
+ if(out) {
+ SCAD(geometry_ref_put(out));
+ out = NULL;
+ }
goto exit;
}
@@ -2761,7 +3218,6 @@ scad_geometry_dilate
(const struct scad_geometry* geom,
const double center[3],
const double scale[3],
- const char* name,
struct scad_geometry** out_geometry)
{
res_T res = RES_OK;
@@ -2775,7 +3231,7 @@ scad_geometry_dilate
ERR(check_device(FUNC_NAME));
- ERR(scad_geometry_copy(geom, name, &out));
+ ERR(scad_geometry_copy(geom, &out));
gmshModelOccDilate(out->gmsh_dimTags, out->gmsh_dimTags_n, SPLIT3(center),
SPLIT3(scale), &ierr);
@@ -2803,14 +3259,16 @@ scad_geometries_set_mesh_size_modifier
int* tagout[4] = { NULL, NULL, NULL, NULL };
size_t tagoutn[4] = { 0, 0, 0, 0}, i;
- if(!geometries || geometries_count == 0 || modifier <= 0) {
+ if(!geometries || geometries_count == 0 || modifier <= 0
+ || (type != SCAD_ABSOLUTE_SIZE && type != SCAD_SIZE_FACTOR))
+ {
res = RES_BAD_ARG;
goto error;
}
ERR(check_device(FUNC_NAME));
- if(type == Scad_absolute_size) modifier = -modifier;
+ if(type == SCAD_ABSOLUTE_SIZE) modifier = -modifier;
ERR(gather_tags_recursive(geometries, geometries_count, 0, tagout, tagoutn));
for(dim = 0; dim < 4; dim++) {
for(i = 0; i < tagoutn[dim]; i += 2) {
@@ -2836,12 +3294,14 @@ scad_geometries_set_mesh_size_modifier
}
}
- gmshModelMeshSetSizeCallback( (some ? size_callback : NULL), NULL, &ierr);
+ gmshModelMeshSetSizeCallback((some ? size_callback : NULL), NULL, &ierr);
ERR(gmsh_err_to_res_T(ierr));
exit:
- for(dim = 0; dim < 4; dim++) {
- MEM_RM(dev->allocator, tagout[dim]);
+ if(dev) {
+ for(dim = 0; dim < 4; dim++) {
+ MEM_RM(dev->allocator, tagout[dim]);
+ }
}
return res;
error:
@@ -2860,7 +3320,14 @@ scad_geometries_set_mesh_algorithm
int* tagout[4] = { NULL, NULL, NULL, NULL };
size_t tagoutn[4], i;
- if(!geometries || geometries_count == 0) {
+ if(!geometries || geometries_count == 0 ||
+ (algorithm != SCAD_MESHADAPT &&
+ algorithm != SCAD_AUTOMATIC &&
+ algorithm != SCAD_INITIAL_MESH_ONLY &&
+ algorithm != SCAD_DELAUNAY &&
+ algorithm != SCAD_FRONTAL_DELAUNAY &&
+ algorithm != SCAD_QUASI_STRUCTURED))
+ {
res = RES_BAD_ARG;
goto error;
}
@@ -2876,8 +3343,10 @@ scad_geometries_set_mesh_algorithm
}
exit:
- for(i = 2; i < 4; i++) {
- MEM_RM(dev->allocator, tagout[i]);
+ if(dev) {
+ for(i = 2; i < 4; i++) {
+ MEM_RM(dev->allocator, tagout[i]);
+ }
}
return res;
error:
@@ -2894,12 +3363,13 @@ scad_geometries_set_periodic
{
res_T res = RES_OK;
struct scad_device* dev = get_device();
- struct mem_allocator* allocator = dev->allocator;
+ struct mem_allocator* allocator = NULL;
int ierr;
int* src_dimTagout[4] = { NULL, NULL, NULL, NULL };
int* tgt_dimTagout[4] = { NULL, NULL, NULL, NULL };
int* src_tags = NULL, *tgt_tags = NULL;
- size_t src_dimTagoutn[4], tgt_dimTagoutn[4], src_tagsn = 0, tgt_tagsn = 0, i;
+ size_t src_dimTagoutn[4] = { 0,0,0,0 }, tgt_dimTagoutn[4] = { 0,0,0,0 };
+ size_t src_tagsn = 0, tgt_tagsn = 0, i;
if(!source || source_count == 0 || !target || target_count == 0 || !affine) {
res = RES_BAD_ARG;
@@ -2918,6 +3388,7 @@ scad_geometries_set_periodic
goto error;
}
+ allocator = dev->allocator;
src_tags = MEM_ALLOC(allocator, src_tagsn);
tgt_tags = MEM_ALLOC(allocator, tgt_tagsn);
if(!src_tags || !tgt_tags) {
@@ -2935,12 +3406,14 @@ scad_geometries_set_periodic
ERR(gmsh_err_to_res_T(ierr));
exit:
- for(i = 2; i < 4; i++) {
- MEM_RM(dev->allocator, src_dimTagout[i]);
- MEM_RM(dev->allocator, tgt_dimTagout[i]);
+ if(dev) {
+ for(i = 2; i < 4; i++) {
+ MEM_RM(dev->allocator, src_dimTagout[i]);
+ MEM_RM(dev->allocator, tgt_dimTagout[i]);
+ }
+ MEM_RM(dev->allocator, src_tags);
+ MEM_RM(dev->allocator, tgt_tags);
}
- MEM_RM(dev->allocator, src_tags);
- MEM_RM(dev->allocator, tgt_tags);
return res;
error:
goto exit;
diff --git a/src/test_api.c b/src/test_api.c
@@ -20,12 +20,25 @@
#include <rsys/rsys.h>
#include <rsys/str.h>
#include <rsys/math.h>
+#include <rsys/double3.h>
#include <rsys/mem_allocator.h>
#include <rsys/dynamic_array_double.h>
#include <stdlib.h>
#include <stdio.h>
+#define STRINGIZE(x) STRINGIZE2(x)
+#define STRINGIZE2(x) #x
+#define LINE_STRING STRINGIZE(__LINE__)
+
+static void
+dummy_release
+ (void* data)
+{
+ (void) data;
+ return;
+}
+
static void
get_position
(const size_t ivert, double pos[2], void* data)
@@ -34,17 +47,21 @@ get_position
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};
+ const double p1[3] = {0, 0, 0};
+ const double p2[3] = {0.25, 0.25, 0.8};
+ const double p3[3] = {0.85, 0, 0};
+ const double p4[3] = {1, 0, 0};
+ const double d0[3] = {0.1, 0.1, 0.1};
+ const double d1[3] = {1, 1, 1};
+ const double d2[3] = {1, 1, 0};
+ const double s[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;
@@ -55,242 +72,1547 @@ main(int argc, char* argv[])
struct mem_allocator allocator;
struct darray_double trg;
struct scad_options options = SCAD_DEFAULT_OPTIONS;
- const char* name;
+ struct scad_options opt = SCAD_DEFAULT_OPTIONS;
+ const char *name, *name2;
+ double m, tmp[3], tmp2[3];
+ double affine[16] = { 1, 0, 0, 0.25, 0, 1, 0, 0.25, 0, 0, 1, 0.8, 0, 0, 0, 1 };
size_t i, c;
+ int e;
+ void* data;
(void)argc; (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ options.Misc.DebugEmptyContext = 1;
+ options.Mesh.MeshSizeExtendFromBoundary = 0;
+ options.Mesh.MeshSizeFromPoints = 0;
+
/* cannot call any API function before a successful call to scad_initialize */
+ geom1 = geom2 = geom =
+ (struct scad_geometry*)1; /* To allow tests go past arg!=NULL */
BAD(scad_finalize());
- BAD(scad_set_options(NULL));
- BAD(scad_synchronize());
+ BAD(scad_set_options(&options));
+ BAD(scad_get_options(&options));
+ BAD(scad_scene_count(&c));
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_write("test.step"));
BAD(scad_scene_mesh());
+ BAD(scad_add_rectangle(p1, d2, &geom));
+ BAD(scad_add_disk(p1, 1, &geom));
+ BAD(scad_add_polygon(get_position, coord, 0, 3, &geom));
+ BAD(scad_add_box(p1, d1, &geom));
+ BAD(scad_add_cylinder(p1, d1, 2, 1, &geom));
+ BAD(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_add_cone(p1, d1, 1, 1, 2*PI, &geom));
+ BAD(scad_add_torus(p1, 1, 1, 2*PI, NULL, &geom));
+ BAD(scad_geometry_dilate(geom1, p1, p1, &geom));
+ BAD(scad_geometry_translate(geom1, p1, &geom));
+ BAD(scad_geometry_rotate(geom1, p1, p1, 2, &geom));
+ BAD(scad_geometry_extrude(geom1, p1, &geom));
+ BAD(scad_geometry_explode(geom1, &geom_array, &c));
+ BAD(scad_geometry_ref_get(geom1));
+ BAD(scad_geometry_ref_put(geom1));
+ BAD(scad_geometry_get_count(geom1, NULL));
+ BAD(scad_geometry_is_empty(geom1, &e));
+ BAD(scad_geometry_set_custom_data(geom1, NULL, NULL));
+ BAD(scad_geometry_get_custom_data(geom1, (void*)&trg));
+ BAD(scad_geometry_set_name(geom1, name));
+ BAD(scad_geometries_set_name(&geom1, 1, name, 0));
+ BAD(scad_geometry_get_name(geom1, &name));
+ BAD(scad_geometries_swap(&geom1, &geom2, 1, 0));
+ BAD(scad_geometry_get_mass(geom1, &m));
+ BAD(scad_geometry_get_centerofmass(geom1, tmp));
+ BAD(scad_geometry_get_closest_point(geom1, p1, tmp, &m, NULL));
+ BAD(scad_geometry_get_normal(geom1, tmp, tmp, &geom));
+ BAD(scad_geometry_get_bounding_box(geom1, tmp, tmp));
+ BAD(scad_geometry_equal(geom1, geom2, &e));
+ BAD(scad_geometry_is_included(geom1, &geom2, 1, &e));
+ BAD(scad_geometries_collect(&geom1, 1, &geom2));
+ BAD(scad_geometries_fuse(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_cut(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_intersect(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_partition(&geom1, 1, 0, &geom));
+ BAD(scad_geometries_common_boundaries(&geom1, 1, &geom2, 1, &geom_array, &c));
+ BAD(scad_geometries_boundaries(&geom1, 1, &geom_array, &c));
+ BAD(scad_geometry_copy(geom1, &geom2));
+ BAD(scad_geometry_set_visibility(geom1, 0, 0));
+ BAD(scad_geometries_set_periodic(&geom1, 1, &geom2, 1, affine));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 1, SCAD_ABSOLUTE_SIZE, 1));
+ BAD(scad_geometries_set_mesh_algorithm(&geom1, 1, SCAD_QUASI_STRUCTURED));
+ BAD(scad_geometries_clear_mesh(&geom1, 1));
+ BAD(scad_step_import("test.step", &geom_array, &c));
+ BAD(scad_stl_export(geom1, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_partial(geom1, &geom1, 1, "test.stl",
+ SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_split(geom1, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_get_data(geom1, &trg));
+ BAD(scad_stl_get_data_partial(geom1, &geom2, 1, &trg));
+ BAD(scad_stl_data_write(&trg, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
BAD(scad_run_ui());
- BAD(scad_geometry_get_name(geom, &name));
+ BAD(scad_synchronize());
+ CHK(SIZE_MAX == scad_get_dimtag_refcount(3, 0));
+ BAD(scad_dump_geometry(geom));
+ BAD(scad_dump_geometries());
/* cannot call any API function after a successful call to scad_finalize */
OK(scad_initialize(NULL, &allocator, 3));
OK(scad_finalize());
BAD(scad_finalize());
- BAD(scad_set_options(NULL));
- BAD(scad_synchronize());
+ BAD(scad_set_options(&options));
+ BAD(scad_get_options(&options));
+ BAD(scad_scene_count(&c));
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_write("test.step"));
BAD(scad_scene_mesh());
+ BAD(scad_add_rectangle(p1, d2, &geom));
+ BAD(scad_add_disk(p1, 1, &geom));
+ BAD(scad_add_polygon(get_position, coord, 0, 3, &geom));
+ BAD(scad_add_box(p1, d1, &geom));
+ BAD(scad_add_cylinder(p1, d1, 2, 1, &geom));
+ BAD(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_add_cone(p1, d1, 1, 1, 2*PI, &geom));
+ BAD(scad_add_torus(p1, 1, 1, 2*PI, NULL, &geom));
+ BAD(scad_geometry_dilate(geom1, p1, p1, &geom));
+ BAD(scad_geometry_translate(geom1, p1, &geom));
+ BAD(scad_geometry_rotate(geom1, p1, p1, 2, &geom));
+ BAD(scad_geometry_extrude(geom1, p1, &geom));
+ BAD(scad_geometry_explode(geom1, &geom_array, &c));
+ BAD(scad_geometry_ref_get(geom1));
+ BAD(scad_geometry_ref_put(geom1));
+ BAD(scad_geometry_get_count(geom1, NULL));
+ BAD(scad_geometry_is_empty(geom1, &e));
+ BAD(scad_geometry_set_custom_data(geom1, NULL, NULL));
+ BAD(scad_geometry_get_custom_data(geom1, (void*)&trg));
+ BAD(scad_geometry_set_name(geom1, name));
+ BAD(scad_geometries_set_name(&geom1, 1, name, 0));
+ BAD(scad_geometry_get_name(geom1, &name));
+ BAD(scad_geometries_swap(&geom1, &geom2, 1, 0));
+ BAD(scad_geometry_get_mass(geom1, &m));
+ BAD(scad_geometry_get_centerofmass(geom1, tmp));
+ BAD(scad_geometry_get_closest_point(geom1, tmp, tmp, &m, NULL));
+ BAD(scad_geometry_get_normal(geom1, tmp, tmp, &geom));
+ BAD(scad_geometry_get_bounding_box(geom1, tmp, tmp));
+ BAD(scad_geometry_equal(geom1, geom2, &e));
+ BAD(scad_geometry_is_included(geom1, &geom2, 1, &e));
+ BAD(scad_geometries_collect(&geom1, 1, &geom2));
+ BAD(scad_geometries_fuse(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_cut(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_intersect(&geom1, 1, &geom2, 1, &geom));
+ BAD(scad_geometries_partition(&geom1, 1, 0, &geom));
+ BAD(scad_geometries_common_boundaries(&geom1, 1, &geom2, 1, &geom_array, &c));
+ BAD(scad_geometries_boundaries(&geom1, 1, &geom_array, &c));
+ BAD(scad_geometry_copy(geom1, &geom2));
+ BAD(scad_geometry_set_visibility(geom1, 0, 0));
+ BAD(scad_geometries_set_periodic(&geom1, 1, &geom2, 1, affine));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 1, SCAD_ABSOLUTE_SIZE, 1));
+ BAD(scad_geometries_set_mesh_algorithm(&geom1, 1, SCAD_QUASI_STRUCTURED));
+ BAD(scad_geometries_clear_mesh(&geom1, 1));
+ BAD(scad_step_import("test.step", &geom_array, &c));
+ BAD(scad_stl_export(geom1, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_partial(geom1, &geom1, 1, "test.stl",
+ SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_split(geom1, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_get_data(geom1, &trg));
+ BAD(scad_stl_get_data_partial(geom1, &geom2, 1, &trg));
+ BAD(scad_stl_data_write(&trg, "test.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
BAD(scad_run_ui());
- BAD(scad_geometry_get_name(geom, &name));
+ BAD(scad_synchronize());
+ CHK(SIZE_MAX == scad_get_dimtag_refcount(3, 0));
+ BAD(scad_dump_geometry(geom));
+ BAD(scad_dump_geometries());
BAD(scad_initialize(NULL, &allocator, 4));
BAD(scad_initialize(NULL, &allocator, -1));
-
OK(scad_initialize(NULL, &allocator, 3));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
OK(scad_set_options(NULL));
OK(scad_set_options(&options));
- 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_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_get_options(NULL));
+ OK(scad_get_options(&opt));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_scene_count(NULL));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+ OK(scad_add_rectangle(p1, d2, &geom));
+ OK(scad_scene_count(&c));
+ CHK(c == 1);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_scene_clear());
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+ OK(scad_add_rectangle(p1, d2, &geom));
+ OK(scad_scene_clear());
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+ OK(scad_add_rectangle(p1, d2, &geom));
+ OK(scad_geometry_ref_get(geom));
+ OK(scad_scene_clear());
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_scene_write(NULL));
+ ERR(scad_scene_write(""));
+ ERR(scad_scene_write("/tmp/test.bad"));
+ OK(scad_scene_write("/tmp/test"LINE_STRING".step"));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_rectangle(NULL, NULL, NULL));
+ BAD(scad_add_rectangle(NULL, NULL, &geom));
+ BAD(scad_add_rectangle(NULL, d1, NULL));
+ BAD(scad_add_rectangle(p1, NULL, NULL));
+ BAD(scad_add_rectangle(NULL, d2, &geom));
+ BAD(scad_add_rectangle(p1, NULL, &geom));
+ BAD(scad_add_rectangle(p1, d2, NULL));
+ OK(scad_add_rectangle(p1, d2, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_disk(NULL, -1, NULL));
+ BAD(scad_add_disk(NULL, -1, &geom));
+ BAD(scad_add_disk(NULL, 1, NULL));
+ BAD(scad_add_disk(p1, -1, NULL));
+ BAD(scad_add_disk(NULL, 1, &geom));
+ BAD(scad_add_disk(p1, -1, &geom));
+ BAD(scad_add_disk(p1, 1, NULL));
+ OK(scad_add_disk(p1, 1, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_polygon(NULL, coord, 0, 0, NULL));
+ BAD(scad_add_polygon(get_position, coord, 0, 0, NULL));
+ BAD(scad_add_polygon(NULL, coord, 0, 3, NULL));
+ BAD(scad_add_polygon(NULL, coord, 0, 0, &poly));
+ BAD(scad_add_polygon(NULL, coord, 0, 3, &poly));
+ BAD(scad_add_polygon(get_position, coord, 0, 0, &poly));
+ BAD(scad_add_polygon(get_position, coord, 0, 3, NULL));
+ OK(scad_add_polygon(get_position, coord, 0, 3, &poly));
+ OK(scad_geometry_ref_put(poly));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_box(NULL, NULL, NULL));
+ BAD(scad_add_box(NULL, NULL, &geom));
+ BAD(scad_add_box(NULL, d1, NULL));
+ BAD(scad_add_box(p1, NULL, NULL));
+ BAD(scad_add_box(NULL, d1, &geom));
+ BAD(scad_add_box(p1, NULL, &geom));
+ BAD(scad_add_box(p1, d1, NULL));
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_cylinder(NULL, NULL, -1, -1, NULL));
+ BAD(scad_add_cylinder(NULL, NULL, -1, -1, &geom));
+ BAD(scad_add_cylinder(NULL, NULL, -1, 1, NULL));
+ BAD(scad_add_cylinder(NULL, NULL, 1, -1, NULL));
+ BAD(scad_add_cylinder(NULL, d1, -1, -1, NULL));
+ BAD(scad_add_cylinder(p1, NULL, -1, -1, NULL));
+ BAD(scad_add_cylinder(NULL, NULL, -1, 1, &geom));
+ BAD(scad_add_cylinder(NULL, NULL, 1, -1, &geom));
+ BAD(scad_add_cylinder(NULL, d1, -1, -1, &geom));
+ BAD(scad_add_cylinder(p1, NULL, -1, -1, &geom));
+ BAD(scad_add_cylinder(NULL, NULL, 1, 1, NULL));
+ BAD(scad_add_cylinder(NULL, d1, -1, 1, NULL));
+ BAD(scad_add_cylinder(p1, NULL, -1, 1, NULL));
+ BAD(scad_add_cylinder(NULL, d1, 1, -1, NULL));
+ BAD(scad_add_cylinder(p1, NULL, 1, -1, NULL));
+ BAD(scad_add_cylinder(p1, d1, -1, -1, NULL));
+ BAD(scad_add_cylinder(NULL, NULL, 1, 1, &geom));
+ BAD(scad_add_cylinder(NULL, d1, -1, 1, &geom));
+ BAD(scad_add_cylinder(p1, NULL, -1, 1, &geom));
+ BAD(scad_add_cylinder(NULL, d1, 1, -1, &geom));
+ BAD(scad_add_cylinder(p1, NULL, 1, -1, &geom));
+ BAD(scad_add_cylinder(p1, d1, -1, -1, &geom));
+ BAD(scad_add_cylinder(NULL, d1, 1, 1, NULL));
+ BAD(scad_add_cylinder(p1, NULL, 1, 1, NULL));
+ BAD(scad_add_cylinder(p1, d1, -1, 1, NULL));
+ BAD(scad_add_cylinder(p1, d1, 1, -1, NULL));
+ BAD(scad_add_cylinder(NULL, d1, 1, 1, &geom));
+ BAD(scad_add_cylinder(p1, NULL, 1, 1, &geom));
+ BAD(scad_add_cylinder(p1, d1, -1, 1, &geom));
+ BAD(scad_add_cylinder(p1, d1, 1, 3*PI, &geom));
+ BAD(scad_add_cylinder(p1, d1, 1, 1, NULL));
+ OK(scad_add_cylinder(p1, d1, 1, 1, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_sphere(NULL, -1, NULL));
+ BAD(scad_add_sphere(NULL, -1, &geom));
+ BAD(scad_add_sphere(NULL, 1, NULL));
+ BAD(scad_add_sphere(p1, -1, NULL));
+ BAD(scad_add_sphere(NULL, 1, &geom));
+ BAD(scad_add_sphere(p1, 0, &geom));
+ BAD(scad_add_sphere(p1, 1, NULL));
+ OK(scad_add_sphere(p1, 1, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_cone(NULL, NULL, -1, -1, -1, NULL));
+ BAD(scad_add_cone(NULL, NULL, -1, -1, -1, &geom));
+ BAD(scad_add_cone(NULL, NULL, -1, -1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, NULL, -1, -1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, NULL, -1, 1, -1, NULL));
+ BAD(scad_add_cone(NULL, NULL, -1, 1, -1, &geom));
+ BAD(scad_add_cone(NULL, NULL, -1, 1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, NULL, -1, 1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, NULL, 0, -1, -1, NULL));
+ BAD(scad_add_cone(NULL, NULL, 0, -1, -1, &geom));
+ BAD(scad_add_cone(NULL, NULL, 0, -1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, NULL, 0, -1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, NULL, 0, 1, -1, NULL));
+ BAD(scad_add_cone(NULL, NULL, 0, 1, -1, &geom));
+ BAD(scad_add_cone(NULL, NULL, 0, 1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, NULL, 0, 1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, d1, -1, -1, -1, NULL));
+ BAD(scad_add_cone(NULL, d1, -1, -1, -1, &geom));
+ BAD(scad_add_cone(NULL, d1, -1, -1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, d1, -1, -1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, d1, -1, 1, -1, NULL));
+ BAD(scad_add_cone(NULL, d1, -1, 1, -1, &geom));
+ BAD(scad_add_cone(NULL, d1, -1, 1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, d1, -1, 1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, d1, 0, -1, -1, NULL));
+ BAD(scad_add_cone(NULL, d1, 0, -1, -1, &geom));
+ BAD(scad_add_cone(NULL, d1, 0, -1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, d1, 0, -1, 2*PI, &geom));
+ BAD(scad_add_cone(NULL, d1, 0, 1, -1, NULL));
+ BAD(scad_add_cone(NULL, d1, 0, 1, -1, &geom));
+ BAD(scad_add_cone(NULL, d1, 0, 1, 2*PI, NULL));
+ BAD(scad_add_cone(NULL, d1, 0, 1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, NULL, -1, -1, -1, NULL));
+ BAD(scad_add_cone(p1, NULL, -1, -1, -1, &geom));
+ BAD(scad_add_cone(p1, NULL, -1, -1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, NULL, -1, -1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, NULL, -1, 1, -1, NULL));
+ BAD(scad_add_cone(p1, NULL, -1, 1, -1, &geom));
+ BAD(scad_add_cone(p1, NULL, -1, 1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, NULL, -1, 1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, NULL, 0, -1, -1, NULL));
+ BAD(scad_add_cone(p1, NULL, 0, -1, -1, &geom));
+ BAD(scad_add_cone(p1, NULL, 0, -1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, NULL, 0, -1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, NULL, 0, 1, -1, NULL));
+ BAD(scad_add_cone(p1, NULL, 0, 1, -1, &geom));
+ BAD(scad_add_cone(p1, NULL, 0, 1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, NULL, 0, 1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, d1, -1, -1, -1, NULL));
+ BAD(scad_add_cone(p1, d1, -1, -1, -1, &geom));
+ BAD(scad_add_cone(p1, d1, -1, -1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, d1, -1, -1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, d1, -1, 1, -1, NULL));
+ BAD(scad_add_cone(p1, d1, -1, 1, -1, &geom));
+ BAD(scad_add_cone(p1, d1, -1, 1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, d1, -1, 1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, d1, 0, -1, -1, NULL));
+ BAD(scad_add_cone(p1, d1, 0, -1, -1, &geom));
+ BAD(scad_add_cone(p1, d1, 0, -1, 2*PI, NULL));
+ BAD(scad_add_cone(p1, d1, 0, -1, 2*PI, &geom));
+ BAD(scad_add_cone(p1, d1, 0, 1, -1, NULL));
+ BAD(scad_add_cone(p1, d1, 0, 1, -1, &geom));
+ BAD(scad_add_cone(p1, d1, 0, 1, 2*PI, NULL));
+ OK(scad_add_cone(p1, d1, 0, 1, 2*PI, &geom));
+ OK(scad_geometry_ref_put(geom));
+ BAD(scad_add_cone(p1, d1, 1, 1, 2*PI, &geom)); /* r1 == r2 */
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ BAD(scad_add_torus(NULL, 0, 0, -1, NULL, NULL));
+ BAD(scad_add_torus(NULL, 0, 0, -1, NULL, &geom));
+ BAD(scad_add_torus(NULL, 0, 0, -1, d1, NULL));
+ BAD(scad_add_torus(NULL, 0, 0, -1, d1, &geom));
+ BAD(scad_add_torus(NULL, 0, 0, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(NULL, 0, 0, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(NULL, 0, 0, 2*PI, d1, NULL));
+ BAD(scad_add_torus(NULL, 0, 0, 2*PI, d1, &geom));
+ BAD(scad_add_torus(NULL, 0, 1, -1, NULL, NULL));
+ BAD(scad_add_torus(NULL, 0, 1, -1, NULL, &geom));
+ BAD(scad_add_torus(NULL, 0, 1, -1, d1, NULL));
+ BAD(scad_add_torus(NULL, 0, 1, -1, d1, &geom));
+ BAD(scad_add_torus(NULL, 0, 1, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(NULL, 0, 1, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(NULL, 0, 1, 2*PI, d1, NULL));
+ BAD(scad_add_torus(NULL, 0, 1, 2*PI, d1, &geom));
+ BAD(scad_add_torus(NULL, 1, 0, -1, NULL, NULL));
+ BAD(scad_add_torus(NULL, 1, 0, -1, NULL, &geom));
+ BAD(scad_add_torus(NULL, 1, 0, -1, d1, NULL));
+ BAD(scad_add_torus(NULL, 1, 0, -1, d1, &geom));
+ BAD(scad_add_torus(NULL, 1, 0, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(NULL, 1, 0, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(NULL, 1, 0, 2*PI, d1, NULL));
+ BAD(scad_add_torus(NULL, 1, 0, 2*PI, d1, &geom));
+ BAD(scad_add_torus(NULL, 1, 1, -1, NULL, NULL));
+ BAD(scad_add_torus(NULL, 1, 1, -1, NULL, &geom));
+ BAD(scad_add_torus(NULL, 1, 1, -1, d1, NULL));
+ BAD(scad_add_torus(NULL, 1, 1, -1, d1, &geom));
+ BAD(scad_add_torus(NULL, 1, 1, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(NULL, 1, 1, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(NULL, 1, 1, 2*PI, d1, NULL));
+ BAD(scad_add_torus(NULL, 1, 1, 2*PI, d1, &geom));
+ BAD(scad_add_torus(p1, 0, 0, -1, NULL, NULL));
+ BAD(scad_add_torus(p1, 0, 0, -1, NULL, &geom));
+ BAD(scad_add_torus(p1, 0, 0, -1, d1, NULL));
+ BAD(scad_add_torus(p1, 0, 0, -1, d1, &geom));
+ BAD(scad_add_torus(p1, 0, 0, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(p1, 0, 0, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(p1, 0, 0, 2*PI, d1, NULL));
+ BAD(scad_add_torus(p1, 0, 0, 2*PI, d1, &geom));
+ BAD(scad_add_torus(p1, 0, 1, -1, NULL, NULL));
+ BAD(scad_add_torus(p1, 0, 1, -1, NULL, &geom));
+ BAD(scad_add_torus(p1, 0, 1, -1, d1, NULL));
+ BAD(scad_add_torus(p1, 0, 1, -1, d1, &geom));
+ BAD(scad_add_torus(p1, 0, 1, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(p1, 0, 1, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(p1, 0, 1, 2*PI, d1, NULL));
+ BAD(scad_add_torus(p1, 0, 1, 2*PI, d1, &geom));
+ BAD(scad_add_torus(p1, 1, 0, -1, NULL, NULL));
+ BAD(scad_add_torus(p1, 1, 0, -1, NULL, &geom));
+ BAD(scad_add_torus(p1, 1, 0, -1, d1, NULL));
+ BAD(scad_add_torus(p1, 1, 0, -1, d1, &geom));
+ BAD(scad_add_torus(p1, 1, 0, 2*PI, NULL, NULL));
+ BAD(scad_add_torus(p1, 1, 0, 2*PI, NULL, &geom));
+ BAD(scad_add_torus(p1, 1, 0, 2*PI, d1, NULL));
+ BAD(scad_add_torus(p1, 1, 0, 2*PI, d1, &geom));
+ BAD(scad_add_torus(p1, 1, 1, -1, NULL, NULL));
+ BAD(scad_add_torus(p1, 1, 1, -1, NULL, &geom));
+ BAD(scad_add_torus(p1, 1, 1, -1, d1, NULL));
+ BAD(scad_add_torus(p1, 1, 1, -1, d1, &geom));
+ BAD(scad_add_torus(p1, 1, 1, 2*PI, NULL, NULL));
+ OK(scad_add_torus(p1, 1, 1, 2*PI, NULL, &geom));
+ OK(scad_geometry_ref_put(geom));
+ BAD(scad_add_torus(p1, 1, 1, 2*PI, d1, NULL));
+ OK(scad_add_torus(p1, 1, 1, 2*PI, d1, &geom));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ BAD(scad_geometry_dilate(NULL, NULL, NULL, NULL));
+ BAD(scad_geometry_dilate(NULL, NULL, NULL, &geom));
+ BAD(scad_geometry_dilate(NULL, NULL, s, NULL));
+ BAD(scad_geometry_dilate(NULL, p1, NULL, NULL));
+ BAD(scad_geometry_dilate(geom1, NULL, NULL, NULL));
+ BAD(scad_geometry_dilate(NULL, NULL, s, &geom));
+ BAD(scad_geometry_dilate(NULL, p1, NULL, &geom));
+ BAD(scad_geometry_dilate(geom1, NULL, NULL, &geom));
+ BAD(scad_geometry_dilate(NULL, p1, s, NULL));
+ BAD(scad_geometry_dilate(geom1, NULL, s, NULL));
+ BAD(scad_geometry_dilate(NULL, p1, s, &geom));
+ BAD(scad_geometry_dilate(geom1, NULL, p1, &geom));
+ BAD(scad_geometry_dilate(geom1, p1, NULL, &geom));
+ BAD(scad_geometry_dilate(geom1, p1, s, NULL));
+ OK(scad_geometry_dilate(geom1, p1, s, &geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
- OK(scad_add_sphere(NULL, p1, .1, &geom));
+ OK(scad_add_sphere(p1, 1, &geom1));
+ BAD(scad_geometry_translate(NULL, NULL, NULL));
+ BAD(scad_geometry_translate(NULL, NULL, &geom));
+ BAD(scad_geometry_translate(NULL, d1, NULL));
+ BAD(scad_geometry_translate(geom1, NULL, NULL));
+ BAD(scad_geometry_translate(NULL, d1, &geom));
+ BAD(scad_geometry_translate(geom1, NULL, &geom));
+ BAD(scad_geometry_translate(geom1, d1, NULL));
+ OK(scad_geometry_translate(geom1, d1, &geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ BAD(scad_geometry_rotate(NULL, NULL, NULL, 1, NULL));
+ BAD(scad_geometry_rotate(NULL, NULL, NULL, 1, &geom));
+ BAD(scad_geometry_rotate(NULL, NULL, d1, 1, NULL));
+ BAD(scad_geometry_rotate(NULL, p1, NULL, 1, NULL));
+ BAD(scad_geometry_rotate(geom1, NULL, NULL, 1, NULL));
+ BAD(scad_geometry_rotate(NULL, NULL, d1, 1, &geom));
+ BAD(scad_geometry_rotate(NULL, p1, NULL, 1, &geom));
+ BAD(scad_geometry_rotate(geom1, NULL, NULL, 1, &geom));
+ BAD(scad_geometry_rotate(NULL, p1, d1, 1, NULL));
+ BAD(scad_geometry_rotate(geom1, NULL, d1, 1, NULL));
+ BAD(scad_geometry_rotate(geom1, p1, NULL, 1, NULL));
+ BAD(scad_geometry_rotate(NULL, p1, d1, 1, &geom));
+ BAD(scad_geometry_rotate(geom1, NULL, d1, 1, &geom));
+ BAD(scad_geometry_rotate(geom1, p1, NULL, 1, &geom));
+ BAD(scad_geometry_rotate(geom1, p1, d1, 1, NULL));
+ OK(scad_geometry_rotate(geom1, p1, d1, 1, &geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_polygon(get_position, coord, 0, 3, &poly));
+ BAD(scad_geometry_extrude(NULL, NULL, NULL));
+ BAD(scad_geometry_extrude(NULL, NULL, &geom));
+ BAD(scad_geometry_extrude(NULL, d1, NULL));
+ BAD(scad_geometry_extrude(poly, NULL, NULL));
+ BAD(scad_geometry_extrude(NULL, d1, &geom));
+ BAD(scad_geometry_extrude(poly, NULL, &geom));
+ BAD(scad_geometry_extrude(poly, d1, NULL));
+ OK(scad_geometry_extrude(poly, d1, &geom));
+ OK(scad_geometry_ref_put(poly));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_polygon(get_position, coord, 0, 3, geoms+0));
+ OK(scad_geometry_translate(geoms[0], d1, geoms+1));
+ OK(scad_geometries_collect(geoms, 2, &poly));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+ OK(scad_geometry_extrude(poly, d1, &geom));
+ OK(scad_geometry_ref_put(poly));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometry_extrude(geom, d1, &geom2));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, geoms+0));
+ OK(scad_add_sphere(p2, 2, geoms+1));
+ OK(scad_geometries_collect(geoms, 2, &geom));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+ BAD(scad_geometry_explode(NULL, NULL, NULL));
+ BAD(scad_geometry_explode(NULL, NULL, &c));
+ BAD(scad_geometry_explode(NULL, &geom_array, NULL));
+ BAD(scad_geometry_explode(geom, NULL, NULL));
+ BAD(scad_geometry_explode(NULL, &geom_array, &c));
+ BAD(scad_geometry_explode(geom, NULL, &c));
+ BAD(scad_geometry_explode(geom, &geom_array, NULL));
+ OK(scad_geometry_explode(geom, &geom_array, &c));
+ OK(scad_geometry_ref_put(geom));
+ CHK(c == 2);
+ OK(scad_geometry_ref_put(geom_array[0]));
+ OK(scad_geometry_ref_put(geom_array[1]));
+ MEM_RM(&allocator, geom_array);
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
BAD(scad_geometry_ref_get(NULL));
OK(scad_geometry_ref_get(geom));
BAD(scad_geometry_ref_put(NULL));
OK(scad_geometry_ref_put(geom));
OK(scad_geometry_ref_put(geom));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
BAD(scad_geometry_get_count(NULL, &c));
- BAD(scad_geometry_get_count(geom1, NULL));
- OK(scad_geometry_get_count(geom1, &c));
+ BAD(scad_geometry_get_count(geom, NULL));
+ OK(scad_add_sphere(p1, 1, &geom));
+ OK(scad_geometry_get_count(geom, &c));
+ CHK(c == 1);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom));
+ OK(scad_add_sphere(p3, 0.1, &geom1));
+ OK(scad_geometries_intersect(&geom, 1, &geom1, 1, &geom2));
+ BAD(scad_geometry_is_empty(NULL, &e));
+ BAD(scad_geometry_is_empty(geom, NULL));
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 0);
+ OK(scad_geometry_is_empty(geom2, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometry_set_custom_data(NULL, NULL, NULL));
+ OK(scad_geometry_set_custom_data(geom, NULL, NULL));
+ OK(scad_geometry_set_custom_data(geom, NULL, (void*)&e));
+ OK(scad_geometry_set_custom_data(geom, dummy_release, NULL));
+ OK(scad_geometry_set_custom_data(geom, dummy_release, (void*)&e));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometry_get_custom_data(NULL, NULL));
+ BAD(scad_geometry_get_custom_data(geom, NULL));
+ OK(scad_geometry_get_custom_data(geom, &data));
+ CHK(data == NULL); /* NULL when unset */
+ OK(scad_geometry_set_custom_data(geom, NULL, (void*)&c));
+ OK(scad_geometry_get_custom_data(geom, &data));
+ CHK(data == (void*)&c);
+ OK(scad_geometry_set_custom_data(geom, NULL, NULL));
+ OK(scad_geometry_get_custom_data(geom, &data));
+ CHK(data == NULL);
+ OK(scad_geometry_set_custom_data(geom, dummy_release, (void*)&c));
+ OK(scad_geometry_get_custom_data(geom, &data));
+ CHK(data == (void*)&c);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ OK(scad_add_sphere(p2, 2, &geom2));
+ BAD(scad_geometry_set_name(NULL, NULL));
+ OK(scad_geometry_set_name(geom1, "sphere 1"));
+ OK(scad_geometry_set_name(geom1, "sphere 1")); /* Same geometry: OK */
+ name = "sphere 2";
+ OK(scad_geometry_set_name(geom2, name));
+ BAD(scad_geometry_set_name(geom2, "sphere 1")); /* Name already in use */
+ OK(scad_geometry_get_name(geom2, &name2));
+ CHK(0 == strcmp(name, name2)); /* Name was left unchanged */
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geoms[0]));
+ OK(scad_add_sphere(p2, 2, &geoms[1]));
+ BAD(scad_geometries_set_name(NULL, 0, NULL, 0));
+ BAD(scad_geometries_set_name(NULL, 2, NULL, 0));
+ BAD(scad_geometries_set_name(geoms, 0, NULL, 0));
+ OK(scad_geometries_set_name(geoms, 2, NULL, 0));
+ BAD(scad_geometries_set_name(NULL, 0, "name", 0));
+ BAD(scad_geometries_set_name(NULL, 2, "name", 0));
+ BAD(scad_geometries_set_name(geoms, 0, "name", 0));
+ OK(scad_geometries_set_name(geoms, 2, "name", 0));
+ OK(scad_geometries_set_name(geoms, 2, "name", 0)); /* Same geometries: OK */
+ OK(scad_geometry_get_name(geoms[1], &name));
+ BAD(scad_geometries_set_name(geoms+1, 1, "name", 0)); /* Name already in use */
+ OK(scad_geometry_get_name(geoms[1], &name2));
+ CHK(0 == strcmp(name, name2)); /* Name was left unchanged */
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometry_get_name(NULL, &name));
+ BAD(scad_geometry_get_name(geom, NULL));
+ OK(scad_geometry_get_name(geom, &name));
+ CHK(name == NULL);
+ name = "sphere 1";
+ OK(scad_geometry_set_name(geom, name));
+ OK(scad_geometry_get_name(geom, &name2));
+ CHK(0 == strcmp(name, name2));
+ OK(scad_geometry_set_name(geom, NULL));
+ OK(scad_geometry_get_name(geom, &name));
+ CHK(name == NULL);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ OK(scad_add_sphere(p2, 2, &geom2));
+ /* Sharing content */
+ OK(scad_geometries_collect(&geom1, 1, geoms+0));
+ OK(scad_geometries_collect(&geom2, 1, geoms+1));
+ OK(scad_geometry_set_name(geom1, "sphere 1"));
+ OK(scad_geometry_set_name(geom2, "sphere 2"));
+ BAD(scad_geometries_swap(NULL, NULL, 0, 0));
+ BAD(scad_geometries_swap(NULL, NULL, 0, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(NULL, NULL, 1, 0));
+ BAD(scad_geometries_swap(NULL, &geom2, 0, 0));
+ BAD(scad_geometries_swap(&geom1, NULL, 0, 0));
+ BAD(scad_geometries_swap(NULL, NULL, 1, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(NULL, &geom2, 0, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(&geom1, NULL, 0, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(NULL, &geom2, 1, 0));
+ BAD(scad_geometries_swap(&geom1, NULL, 1, 0));
+ BAD(scad_geometries_swap(&geom1, &geom2, 0, 0));
+ BAD(scad_geometries_swap(NULL, &geom2, 1, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(&geom1, NULL, 1, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(&geom1, &geom2, 0, SCAD_SWAP_GEOMETRY));
+ BAD(scad_geometries_swap(&geom1, &geom2, 1, 0));
+ OK(scad_geometries_swap(&geom1, &geom2, 1, SCAD_SWAP_GEOMETRY));
+ /* Names not swapped */
+ OK(scad_geometry_get_name(geom1, &name));
+ OK(scad_geometry_get_name(geom2, &name2));
+ CHK(0 == strcmp(name, "sphere 1"));
+ CHK(0 == strcmp(name2, "sphere 2"));
+ /* Geometries swaped */
+ OK(scad_geometry_equal(geom1, geoms[1], &e));
+ CHK(e);
+ OK(scad_geometry_equal(geom2, geoms[0], &e));
+ CHK(e);
+ OK(scad_geometries_swap(&geom1, &geom2, 1, SCAD_SWAP_NAME));
+ /* Names swapped */
+ OK(scad_geometry_get_name(geom1, &name));
+ OK(scad_geometry_get_name(geom2, &name2));
+ CHK(0 == strcmp(name, "sphere 2"));
+ CHK(0 == strcmp(name2, "sphere 1"));
+ /* Geometries not swaped */
+ OK(scad_geometry_equal(geom1, geoms[1], &e));
+ CHK(e);
+ OK(scad_geometry_equal(geom2, geoms[0], &e));
+ CHK(e);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, &geom1));
+ BAD(scad_geometry_get_mass(NULL, NULL));
+ BAD(scad_geometry_get_mass(NULL, &m));
+ BAD(scad_geometry_get_mass(geom1, NULL));
+ OK(scad_geometry_get_mass(geom1, &m));
+ CHK(eq_eps(m, 1, 1e-6)); /* Mass of 2D object is its surface */
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ OK(scad_geometry_get_mass(geom1, &m));
+ CHK(eq_eps(m, PI*4/3, 1e-6)); /* Mass of 3D object is its volume */
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, &geom1));
+ d3_add(tmp2, p1, d3_muld(tmp2, d2, 0.5));
+ BAD(scad_geometry_get_centerofmass(NULL, NULL));
+ BAD(scad_geometry_get_centerofmass(NULL, tmp));
+ BAD(scad_geometry_get_centerofmass(geom1, NULL));
+ OK(scad_geometry_get_centerofmass(geom1, tmp));
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, geoms+0));
+ OK(scad_add_rectangle(p2, d2, geoms+1));
+ d3_add(tmp2, d3_muld(tmp2, d3_add(tmp2, p1, p2), 0.5), d3_muld(tmp, d2, 0.5));
+ OK(scad_geometries_collect(geoms, 2, &geom1));
+ OK(scad_geometry_get_centerofmass(geom1, tmp));
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ OK(scad_geometry_get_centerofmass(geom1, tmp));
+ CHK(d3_eq_eps(tmp, p1, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
- 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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, geoms+0));
+ OK(scad_add_sphere(p2, 1, geoms+1));
+ OK(scad_geometries_collect(geoms, 2, &geom1));
+ d3_muld(tmp2, d3_add(tmp2, p1, p2), 0.5);
+ OK(scad_geometry_get_centerofmass(geom1, tmp));
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, &geom1));
+ BAD(scad_geometry_get_closest_point(NULL, NULL, NULL, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, NULL, NULL, &m, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, NULL, tmp, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, p3, NULL, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, NULL, NULL, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, NULL, tmp, &m, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, p3, NULL, &m, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, NULL, NULL, &m, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, p3, tmp, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, NULL, tmp, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, p3, NULL, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, p3, tmp, NULL, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, p3, NULL, &m, NULL));
+ BAD(scad_geometry_get_closest_point(geom1, NULL, tmp, &m, NULL));
+ BAD(scad_geometry_get_closest_point(NULL, p3, tmp, &m, NULL));
+ OK(scad_geometry_get_closest_point(geom1, p3, tmp, &m, NULL));
+ OK(scad_geometry_get_closest_point(geom1, p3, tmp, &m, &geom));
+ CHK(d3_eq_eps(tmp, p3, 1e-6));
+ CHK(eq_eps(m, 0, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ d3_normalize(tmp, p2);
+ d3_muld(tmp2, tmp, 0.9999);
+ OK(scad_geometry_get_closest_point(geom1, tmp2, tmp, &m, NULL));
+ OK(scad_geometry_get_closest_point(geom1, tmp2, tmp, &m, &geom));
+ CHK(d3_eq_eps(tmp2, tmp, 1e-3));
+ CHK(eq_eps(m, d3_len(d3_sub(tmp, tmp2, tmp)), 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, &geom1));
+ BAD(scad_geometry_get_normal(NULL, NULL, NULL, NULL));
+ BAD(scad_geometry_get_normal(NULL, NULL, tmp, NULL));
+ BAD(scad_geometry_get_normal(NULL, p3, NULL, NULL));
+ BAD(scad_geometry_get_normal(geom1, NULL, NULL, NULL));
+ BAD(scad_geometry_get_normal(NULL, p3, tmp, NULL));
+ BAD(scad_geometry_get_normal(geom1, NULL, tmp, NULL));
+ BAD(scad_geometry_get_normal(geom1, p3, NULL, NULL));
+ d3(tmp2, 0.3, 0.3, 0);
+ OK(scad_geometry_get_normal(geom1, tmp2, tmp, NULL));
+ OK(scad_geometry_get_normal(geom1, tmp2, tmp, &geom));
+ d3(tmp2, 0, 0, 1);
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ d3_normalize(tmp2, p2);
+ OK(scad_geometry_get_normal(geom1, tmp2, tmp, NULL));
+ OK(scad_geometry_get_normal(geom1, tmp2, tmp, &geom));
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometry_get_bounding_box(NULL, NULL, NULL));
+ BAD(scad_geometry_get_bounding_box(NULL, NULL, tmp2));
+ BAD(scad_geometry_get_bounding_box(NULL, tmp, NULL));
+ BAD(scad_geometry_get_bounding_box(geom, NULL, NULL));
+ BAD(scad_geometry_get_bounding_box(NULL, tmp, tmp2));
+ BAD(scad_geometry_get_bounding_box(geom, NULL, tmp2));
+ BAD(scad_geometry_get_bounding_box(geom, tmp, NULL));
+ OK(scad_geometry_get_bounding_box(geom, tmp, tmp2));
+ CHK(d3_eq_eps(d3_muld(tmp, tmp, -1), tmp2, 1e-6));
+ d3(tmp, 1,1,1);
+ CHK(d3_eq_eps(tmp, tmp2, 1e-6));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ OK(scad_geometries_collect(&geom, 1, &geom2));
+ BAD(scad_geometry_equal(NULL, NULL, NULL));
+ BAD(scad_geometry_equal(NULL, NULL, &e));
+ BAD(scad_geometry_equal(NULL, geom2, NULL));
+ BAD(scad_geometry_equal(geom, NULL, NULL));
+ BAD(scad_geometry_equal(NULL, geom2, &e));
+ BAD(scad_geometry_equal(geom, NULL, &e));
+ BAD(scad_geometry_equal(geom, geom2, NULL));
+ OK(scad_geometry_equal(geom, geom2, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_add_sphere(p1, 1, &geom2));
+ OK(scad_geometry_equal(geom, geom2, &e));
+ CHK(e == 0);
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom2));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ OK(scad_geometries_collect(&geom, 1, &geom2));
+ BAD(scad_geometry_is_included(NULL, NULL, 0, NULL));
+ BAD(scad_geometry_is_included(NULL, NULL, 0, &e));
+ BAD(scad_geometry_is_included(NULL, NULL, 1, NULL));
+ BAD(scad_geometry_is_included(NULL, &geom2, 0, NULL));
+ BAD(scad_geometry_is_included(geom, NULL, 0, NULL));
+ BAD(scad_geometry_is_included(NULL, NULL, 1, &e));
+ BAD(scad_geometry_is_included(NULL, &geom2, 0, &e));
+ BAD(scad_geometry_is_included(geom, NULL, 0, &e));
+ BAD(scad_geometry_is_included(NULL, &geom2, 1, NULL));
+ BAD(scad_geometry_is_included(geom, NULL, 1, NULL));
+ BAD(scad_geometry_is_included(geom, &geom2, 0, NULL));
+ BAD(scad_geometry_is_included(geom, &geom2, 1, NULL));
+ BAD(scad_geometry_is_included(geom, &geom2, 0, &e));
+ BAD(scad_geometry_is_included(geom, NULL, 1, &e));
+ BAD(scad_geometry_is_included(NULL, &geom2, 1, &e));
+ OK(scad_geometry_is_included(geom, &geom2, 1, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_add_sphere(p1, 1, &geom2));
+ OK(scad_geometry_is_included(geom, &geom2, 1, &e));
+ CHK(e == 0);
OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom2));
- 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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom));
+ BAD(scad_geometries_collect(NULL, 0, NULL));
+ BAD(scad_geometries_collect(NULL, 0, &geom2));
+ BAD(scad_geometries_collect(NULL, 1, NULL));
+ BAD(scad_geometries_collect(&geom, 0, NULL));
+ BAD(scad_geometries_collect(NULL, 1, &geom2));
+ BAD(scad_geometries_collect(&geom, 0, &geom2));
+ BAD(scad_geometries_collect(&geom, 1, NULL));
+ OK(scad_geometries_collect(&geom, 1, &geom2));
OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom2));
- BAD(scad_add_polygon(NULL, NULL, coord, 0, 3, &poly));
- BAD(scad_add_polygon(NULL, get_position, coord, 0, 2, &poly));
- BAD(scad_add_polygon(NULL, get_position, coord, 0, 2, &poly));
- BAD(scad_add_polygon(NULL, get_position, coord, 0, 3, NULL));
- OK(scad_add_polygon(NULL, get_position, coord, 0, 3, &poly));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
- 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_add_box(p1, d0, &geom1));
+ OK(scad_add_box(p2, d0, &geom2));
+ BAD(scad_geometries_fuse(NULL, 0, NULL, 0, NULL));
+ BAD(scad_geometries_fuse(NULL, 0, NULL, 0, &geom));
+ BAD(scad_geometries_fuse(NULL, 0, NULL, 1, NULL));
+ BAD(scad_geometries_fuse(NULL, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_fuse(NULL, 1, NULL, 0, NULL));
+ BAD(scad_geometries_fuse(&geom1, 0, NULL, 0, NULL));
+ BAD(scad_geometries_fuse(NULL, 0, NULL, 1, &geom));
+ BAD(scad_geometries_fuse(NULL, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_fuse(NULL, 1, NULL, 0, &geom));
+ BAD(scad_geometries_fuse(&geom1, 0, NULL, 0, &geom));
+ BAD(scad_geometries_fuse(NULL, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_fuse(NULL, 1, NULL, 1, NULL));
+ BAD(scad_geometries_fuse(&geom1, 0, NULL, 1, NULL));
+ BAD(scad_geometries_fuse(NULL, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_fuse(&geom1, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_fuse(&geom1, 1, NULL, 0, NULL));
+ BAD(scad_geometries_fuse(NULL, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_fuse(NULL, 1, NULL, 1, &geom));
+ BAD(scad_geometries_fuse(&geom1, 0, NULL, 1, &geom));
+ BAD(scad_geometries_fuse(NULL, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_fuse(&geom, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_fuse(&geom, 1, NULL, 0, &geom));
+ BAD(scad_geometries_fuse(NULL, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_fuse(&geom, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_fuse(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_fuse(&geom, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_fuse(&geom1, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_fuse(&geom1, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_fuse(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_fuse(&geom1, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_fuse(NULL, 1, &geom2, 1, &geom));
+ OK(scad_geometries_fuse(&geom1, 1, &geom2, 1, &geom)); /* disjoint geometries */
+ OK(scad_geometry_get_count(geom, &c));
+ CHK(c == 2);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_add_box(p2, d1, &geom2));
+ OK(scad_geometries_fuse(&geom1, 1, &geom2, 1, &geom)); /* non-disjoint geometries */
+ OK(scad_geometry_get_count(geom, &c));
+ CHK(c == 1);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d0, &geom1));
+ OK(scad_add_box(p2, d0, &geom2));
+ BAD(scad_geometries_cut(NULL, 0, NULL, 0, &geom));
+ BAD(scad_geometries_cut(NULL, 0, NULL, 1, NULL));
+ BAD(scad_geometries_cut(NULL, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_cut(NULL, 1, NULL, 0, NULL));
+ BAD(scad_geometries_cut(&geom1, 0, NULL, 0, NULL));
+ BAD(scad_geometries_cut(NULL, 0, NULL, 1, &geom));
+ BAD(scad_geometries_cut(NULL, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_cut(NULL, 1, NULL, 0, &geom));
+ BAD(scad_geometries_cut(&geom1, 0, NULL, 0, &geom));
+ BAD(scad_geometries_cut(NULL, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_cut(NULL, 1, NULL, 1, NULL));
+ BAD(scad_geometries_cut(&geom1, 0, NULL, 1, NULL));
+ BAD(scad_geometries_cut(NULL, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_cut(&geom1, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_cut(&geom1, 1, NULL, 0, NULL));
+ BAD(scad_geometries_cut(NULL, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_cut(NULL, 1, NULL, 1, &geom));
+ BAD(scad_geometries_cut(&geom1, 0, NULL, 1, &geom));
+ BAD(scad_geometries_cut(NULL, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_cut(&geom, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_cut(&geom, 1, NULL, 0, &geom));
+ BAD(scad_geometries_cut(NULL, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_cut(&geom, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_cut(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_cut(&geom, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_cut(&geom1, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_cut(&geom1, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_cut(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_cut(&geom1, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_cut(NULL, 1, &geom2, 1, &geom));
+ OK(scad_geometries_cut(&geom1, 1, &geom2, 1, &geom)); /* disjoint geometries */
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 0);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_add_box(p2, d1, &geom2));
+ OK(scad_geometries_cut(&geom1, 1, &geom2, 1, &geom)); /* non-disjoint geometries */
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 0);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_geometries_cut(&geom1, 1, &geom1, 1, &geom));
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom1));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 1, &geom1));
+ OK(scad_geometries_cut(&geom1, 1, &geom1, 1, &geom));
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom1));
OK(scad_geometry_ref_put(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_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d0, &geom1));
+ OK(scad_add_box(p2, d0, &geom2));
+ BAD(scad_geometries_intersect(NULL, 0, NULL, 0, &geom));
+ BAD(scad_geometries_intersect(NULL, 0, NULL, 1, NULL));
+ BAD(scad_geometries_intersect(NULL, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_intersect(NULL, 1, NULL, 0, NULL));
+ BAD(scad_geometries_intersect(&geom1, 0, NULL, 0, NULL));
+ BAD(scad_geometries_intersect(NULL, 0, NULL, 1, &geom));
+ BAD(scad_geometries_intersect(NULL, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_intersect(NULL, 1, NULL, 0, &geom));
+ BAD(scad_geometries_intersect(&geom1, 0, NULL, 0, &geom));
+ BAD(scad_geometries_intersect(NULL, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_intersect(NULL, 1, NULL, 1, NULL));
+ BAD(scad_geometries_intersect(&geom1, 0, NULL, 1, NULL));
+ BAD(scad_geometries_intersect(NULL, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_intersect(&geom1, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_intersect(&geom1, 1, NULL, 0, NULL));
+ BAD(scad_geometries_intersect(NULL, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_intersect(NULL, 1, NULL, 1, &geom));
+ BAD(scad_geometries_intersect(&geom1, 0, NULL, 1, &geom));
+ BAD(scad_geometries_intersect(NULL, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_intersect(&geom, 0, &geom2, 0, &geom));
+ BAD(scad_geometries_intersect(&geom, 1, NULL, 0, &geom));
+ BAD(scad_geometries_intersect(NULL, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_intersect(&geom, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_intersect(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_intersect(&geom, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_intersect(&geom1, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_intersect(&geom1, 1, &geom2, 0, &geom));
+ BAD(scad_geometries_intersect(&geom1, 1, NULL, 1, &geom));
+ BAD(scad_geometries_intersect(&geom1, 0, &geom2, 1, &geom));
+ BAD(scad_geometries_intersect(NULL, 1, &geom2, 1, &geom));
+ OK(scad_geometries_intersect(&geom1, 1, &geom2, 1, &geom));
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
OK(scad_geometry_ref_put(geom));
- BAD(scad_geometries_partition(NULL, 2, 1, out_geoms));
- BAD(scad_geometries_partition(geoms, 0, 1, out_geoms));
- BAD(scad_geometries_partition(geoms, 2, 1, NULL));
- OK(scad_geometries_partition(geoms, 2, 1, out_geoms));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_add_box(p2, d1, &geom2));
+ OK(scad_geometries_intersect(&geom1, 1, &geom2, 1, &geom));
+ OK(scad_geometry_is_empty(geom, &e));
+ CHK(e == 0);
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom));
+ OK(scad_add_sphere(p3, 0.1, &geom1));
+ OK(scad_geometries_intersect(&geom, 1, &geom1, 1, &geom2));
+ OK(scad_geometry_is_empty(geom2, &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+
+ OK(scad_add_box(p1, d0, geoms+0));
+ OK(scad_add_box(p2, d0, geoms+1));
+ BAD(scad_geometries_partition(NULL, 0, 9, NULL));
+ BAD(scad_geometries_partition(NULL, 0, 9, out_geoms));
+ BAD(scad_geometries_partition(NULL, 0, 0, NULL));
+ BAD(scad_geometries_partition(NULL, 2, 9, NULL));
+ BAD(scad_geometries_partition(geoms, 0, 9, NULL));
+ BAD(scad_geometries_partition(NULL, 0, 0, out_geoms));
+ BAD(scad_geometries_partition(NULL, 2, 9, out_geoms));
+ BAD(scad_geometries_partition(geoms, 0, 9, out_geoms));
+ BAD(scad_geometries_partition(NULL, 2, 0, NULL));
+ BAD(scad_geometries_partition(geoms, 0, 0, NULL));
+ BAD(scad_geometries_partition(geoms, 2, 9, NULL));
+ BAD(scad_geometries_partition(geoms, 2, 0, NULL));
+ BAD(scad_geometries_partition(geoms, 2, 9, out_geoms));
+ BAD(scad_geometries_partition(geoms, 0, 0, out_geoms));
+ BAD(scad_geometries_partition(NULL, 2, 0, out_geoms));
+ OK(scad_geometries_partition(geoms, 2, SCAD_ALLOW_OVERLAPPING, out_geoms));
+ OK(scad_geometry_equal(geoms[0], out_geoms[0], &e));
+ CHK(e == 1);
+ OK(scad_geometry_equal(geoms[1], out_geoms[1], &e));
+ CHK(e == 1);
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
OK(scad_geometry_ref_put(out_geoms[0]));
OK(scad_geometry_ref_put(out_geoms[1]));
- 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_ref_put(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_ref_put(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, NULL, NULL, NULL));
- BAD(scad_geometry_translate(NULL, NULL, NULL, &geom));
- BAD(scad_geometry_translate(NULL, d1, NULL, NULL));
- BAD(scad_geometry_translate(NULL, d1, NULL, &geom));
- BAD(scad_geometry_translate(geom1, NULL, NULL, NULL));
- BAD(scad_geometry_translate(geom1, NULL, NULL, &geom));
- BAD(scad_geometry_translate(geom1, d1, NULL, NULL));
- OK(scad_geometry_translate(geom1, d1, NULL, &geom));
- OK(scad_geometry_ref_put(geom));
-
- BAD(scad_geometry_rotate(NULL, NULL, NULL, 1, NULL, NULL));
- BAD(scad_geometry_rotate(NULL, NULL, NULL, 1, NULL, &geom));
- BAD(scad_geometry_rotate(NULL, NULL, d1, 1, NULL, NULL));
- BAD(scad_geometry_rotate(NULL, NULL, d1, 1, NULL, &geom));
- BAD(scad_geometry_rotate(NULL, p1, NULL, 1, NULL, NULL));
- BAD(scad_geometry_rotate(NULL, p1, NULL, 1, NULL, &geom));
- BAD(scad_geometry_rotate(NULL, p1, d1, 1, NULL, NULL));
- BAD(scad_geometry_rotate(NULL, p1, d1, 1, NULL, &geom));
- BAD(scad_geometry_rotate(geom1, NULL, NULL, 1, NULL, NULL));
- BAD(scad_geometry_rotate(geom1, NULL, NULL, 1, NULL, &geom));
- BAD(scad_geometry_rotate(geom1, NULL, d1, 1, NULL, NULL));
- BAD(scad_geometry_rotate(geom1, NULL, d1, 1, NULL, &geom));
- BAD(scad_geometry_rotate(geom1, p1, NULL, 1, NULL, NULL));
- BAD(scad_geometry_rotate(geom1, p1, NULL, 1, NULL, &geom));
- BAD(scad_geometry_rotate(geom1, p1, d1, 1, NULL, NULL));
- OK(scad_geometry_rotate(geom1, p1, d1, 1, NULL, &geom));
-
- BAD(scad_geometry_extrude(NULL, NULL, d1, &geom));
- BAD(scad_geometry_extrude(poly, NULL, NULL, &geom));
- BAD(scad_geometry_extrude(poly, NULL, d1, NULL));
- OK(scad_geometry_extrude(poly, NULL, d1, &geom));
- OK(scad_geometry_ref_put(poly));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, geoms+0));
+ OK(scad_add_box(p2, d1, geoms+1));
+ BAD(scad_geometries_partition(geoms, 2, SCAD_DUMP_ON_OVERLAPPING_ERROR, out_geoms));
+ OK(scad_geometries_partition(geoms, 2, SCAD_ALLOW_OVERLAPPING, out_geoms));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+ OK(scad_geometry_ref_put(out_geoms[0]));
+ OK(scad_geometry_ref_put(out_geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geoms[0]));
+ OK(scad_add_sphere(p3, 0.1, &geoms[1]));
+ OK(scad_geometries_partition(geoms, 2, SCAD_ALLOW_OVERLAPPING, out_geoms));
+ OK(scad_geometries_swap(geoms, out_geoms, 2, SCAD_SWAP_GEOMETRY));
+ OK(scad_geometry_ref_put(out_geoms[0]));
+ OK(scad_geometry_ref_put(out_geoms[1]));
+ BAD(scad_geometries_common_boundaries(geoms, 2, NULL, 0, &geom_array, &c));
+ BAD(scad_geometries_common_boundaries(NULL, 1, geoms+1, 1, &geom_array, &c));
+ BAD(scad_geometries_common_boundaries(geoms, 1, NULL, 1, &geom_array, &c));
+ BAD(scad_geometries_common_boundaries(geoms, 1, geoms+1, 1, &geom_array, NULL));
+ BAD(scad_geometries_common_boundaries(geoms, 1, geoms+1, 1, NULL, &c));
+ OK(scad_geometries_common_boundaries(geoms, 1, geoms+1, 1, &geom_array, &c));
+ CHK(c == 0);
+ MEM_RM(&allocator, geom_array);
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geoms[0]));
+ OK(scad_add_box(p3, d1, &geoms[1]));
+ OK(scad_geometries_partition(geoms, 2, SCAD_ALLOW_OVERLAPPING, out_geoms));
+ OK(scad_geometries_swap(geoms, out_geoms, 2, SCAD_SWAP_GEOMETRY));
+ OK(scad_geometry_ref_put(out_geoms[0]));
+ OK(scad_geometry_ref_put(out_geoms[1]));
+ OK(scad_geometries_common_boundaries(geoms+0, 1, geoms+1, 1, &geom_array, &c));
+ CHK(c == 4);
+ for(i = 0; i < c; i++) {
+ OK(scad_geometry_ref_put(geom_array[i]));
+ }
+ MEM_RM(&allocator, geom_array);
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geoms[0]));
+ OK(scad_add_box(p4, d1, &geoms[1]));
+ OK(scad_geometries_partition(geoms, 2, SCAD_ALLOW_OVERLAPPING, out_geoms));
+ OK(scad_geometries_swap(geoms, out_geoms, 2, SCAD_SWAP_GEOMETRY));
+ OK(scad_geometry_ref_put(out_geoms[0]));
+ OK(scad_geometry_ref_put(out_geoms[1]));
+ OK(scad_geometries_common_boundaries(geoms+0, 1, geoms+1, 1, &geom_array, &c));
+ CHK(c == 1);
+ for(i = 0; i < c; i++) {
+ OK(scad_geometry_ref_put(geom_array[i]));
+ }
+ MEM_RM(&allocator, geom_array);
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom1));
+ BAD(scad_geometries_boundaries(NULL, 0, NULL, NULL));
+ BAD(scad_geometries_boundaries(NULL, 0, NULL, &c));
+ BAD(scad_geometries_boundaries(NULL, 0, &geom_array, NULL));
+ BAD(scad_geometries_boundaries(NULL, 1, NULL, NULL));
+ BAD(scad_geometries_boundaries(&geom1, 0, NULL, NULL));
+ BAD(scad_geometries_boundaries(NULL, 0, &geom_array, &c));
+ BAD(scad_geometries_boundaries(NULL, 1, NULL, &c));
+ BAD(scad_geometries_boundaries(&geom1, 0, NULL, &c));
+ BAD(scad_geometries_boundaries(NULL, 1, &geom_array, NULL));
+ BAD(scad_geometries_boundaries(&geom1, 0, &geom_array, NULL));
+ BAD(scad_geometries_boundaries(&geom1, 1, NULL, NULL));
+ BAD(scad_geometries_boundaries(&geom1, 1, &geom_array, NULL));
+ BAD(scad_geometries_boundaries(&geom1, 1, NULL, &c));
+ BAD(scad_geometries_boundaries(&geom1, 0, &geom_array, &c));
+ BAD(scad_geometries_boundaries(NULL, 1, &geom_array, &c));
+ OK(scad_geometries_boundaries(&geom1, 1, &geom_array, &c));
+ for(i = 0; i < c; i++) {
+ OK(scad_geometry_ref_put(geom_array[i]));
+ }
+ MEM_RM(&allocator, geom_array);
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom1));
+ BAD(scad_geometry_copy(NULL, &geom));
+ BAD(scad_geometry_copy(geom1, NULL));
+ OK(scad_geometry_copy(geom1, &geom));
OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom1));
- BAD(scad_scene_write(NULL));
- ERR(scad_scene_write(""));
- OK(scad_scene_write("/tmp/test.step"));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
- BAD(scad_step_import(NULL, "step", &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));
+ OK(scad_add_sphere(p1, 0.1, &geom));
+ BAD(scad_geometry_set_visibility(NULL, 1, 1));
+ OK(scad_geometry_set_visibility(geom, 1, 1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_rectangle(p1, d2, &geom1));
+ OK(scad_add_rectangle(p2, d2, &geom2));
+ BAD(scad_geometries_set_periodic(NULL, 0, NULL, 0, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 0, NULL, 1, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 1, NULL, 0, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 0, NULL, 0, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 1, NULL, 1, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 0, NULL, 1, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 0, &geom2, 0, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 1, NULL, 0, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 1, &geom2, 0, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 1, NULL, 1, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 0, &geom2, 1, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_set_periodic(&geom1, 1, &geom2, 1, NULL));
+ BAD(scad_geometries_set_periodic(NULL, 0, NULL, 0, affine));
+ BAD(scad_geometries_set_periodic(NULL, 0, NULL, 1, affine));
+ BAD(scad_geometries_set_periodic(NULL, 0, &geom2, 0, affine));
+ BAD(scad_geometries_set_periodic(NULL, 1, NULL, 0, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 0, NULL, 0, affine));
+ BAD(scad_geometries_set_periodic(NULL, 0, &geom2, 1, affine));
+ BAD(scad_geometries_set_periodic(NULL, 1, NULL, 1, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 0, NULL, 1, affine));
+ BAD(scad_geometries_set_periodic(NULL, 1, &geom2, 0, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 0, &geom2, 0, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 1, NULL, 0, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 1, &geom2, 0, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 1, NULL, 1, affine));
+ BAD(scad_geometries_set_periodic(&geom1, 0, &geom2, 1, affine));
+ BAD(scad_geometries_set_periodic(NULL, 1, &geom2, 1, affine));
+ OK(scad_geometries_set_periodic(&geom1, 1, &geom2, 1, affine));
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_add_rectangle(p4, d2, &geom2));
+ ERR(scad_geometries_set_periodic(&geom1, 1, &geom2, 1, affine));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom1));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 0, 2, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 0, 2, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 0, SCAD_ABSOLUTE_SIZE, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 1, 2, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 0, 2, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 0, SCAD_ABSOLUTE_SIZE, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 1, 2, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 0, 2, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 1, SCAD_ABSOLUTE_SIZE, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 0, SCAD_ABSOLUTE_SIZE, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 1, 2, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 1, SCAD_ABSOLUTE_SIZE, -1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 1, 2, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(&geom1, 0, SCAD_ABSOLUTE_SIZE, 1.5));
+ BAD(scad_geometries_set_mesh_size_modifier(NULL, 1, SCAD_ABSOLUTE_SIZE, 1.5));
+ OK(scad_geometries_set_mesh_size_modifier(&geom1, 1, SCAD_ABSOLUTE_SIZE, 1.5));
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_sphere(p1, 0.1, &geom1));
+ BAD(scad_geometries_set_mesh_algorithm(NULL, 0, 0));
+ BAD(scad_geometries_set_mesh_algorithm(NULL, 0, SCAD_AUTOMATIC));
+ BAD(scad_geometries_set_mesh_algorithm(NULL, 1, 0));
+ BAD(scad_geometries_set_mesh_algorithm(&geom1, 0, 0));
+ BAD(scad_geometries_set_mesh_algorithm(NULL, 1, SCAD_AUTOMATIC));
+ BAD(scad_geometries_set_mesh_algorithm(&geom1, 0, SCAD_AUTOMATIC));
+ BAD(scad_geometries_set_mesh_algorithm(&geom1, 1, 0));
+ OK(scad_geometries_set_mesh_algorithm(&geom1, 1, SCAD_AUTOMATIC));
+ OK(scad_geometry_ref_put(geom1));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ options.Mesh.MeshSizeFromPoints = 1;
+ options.Mesh.MeshSizeExtendFromBoundary = 1;
+ OK(scad_set_options(&options));
+
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ c = darray_double_size_get(&trg);
+ darray_double_clear(&trg);
+ BAD(scad_geometries_clear_mesh(NULL, 0));
+ BAD(scad_geometries_clear_mesh(NULL, 1));
+ BAD(scad_geometries_clear_mesh(&geom, 0));
+ OK(scad_geometries_clear_mesh(&geom, 1));
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(0 == darray_double_size_get(&trg));
+ OK(scad_geometries_set_mesh_size_modifier(&geom, 1, SCAD_SIZE_FACTOR, 0.5));
+ OK(scad_scene_mesh());
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(c < darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ options.Mesh.MeshSizeFromPoints = 0;
+ options.Mesh.MeshSizeExtendFromBoundary = 0;
+ OK(scad_set_options(&options));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geoms[0]));
+ OK(scad_add_box(p4, d1, &geoms[1]));
+ name = "/tmp/test"LINE_STRING".step";
+ OK(scad_scene_write(name));
+ BAD(scad_step_import(NULL, NULL, NULL));
+ BAD(scad_step_import(NULL, NULL, &c));
+ BAD(scad_step_import(NULL, &geom_array, NULL));
+ BAD(scad_step_import("/tmp/test.step", NULL, NULL));
+ BAD(scad_step_import(NULL, &geom_array, &c));
+ BAD(scad_step_import("/tmp/test.step", NULL, &c));
+ BAD(scad_step_import("/tmp/test.step", &geom_array, NULL));
+ ERR(scad_step_import("dont_exist.step", &geom_array, &c));
+ OK(scad_step_import(name, &geom_array, &c));
+ CHK(c == 2);
+ for(i = 0; i < 2; i++) {
+ OK(scad_geometries_cut(geoms+i, 1, geom_array+i, 1, &geom));
+ OK(scad_geometry_is_empty(geom, &e));
+ OK(scad_geometry_ref_put(geom));
+ CHK(e == 1);
+ }
for(i = 0; i < c; i++) {
OK(scad_geometry_ref_put(geom_array[i]));
}
MEM_RM(&allocator, geom_array);
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom));
+ BAD(scad_stl_export(NULL, NULL, 9, 0));
+ BAD(scad_stl_export(NULL, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export(geom, NULL, 9, 0));
+ BAD(scad_stl_export(geom, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export(geom, "/tmp/test"LINE_STRING, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_set_name(geom, "name"));
+ BAD(scad_stl_export(NULL, NULL, 9, 0));
+ BAD(scad_stl_export(NULL, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export(geom, NULL, 9, 0));
+ OK(scad_stl_export(geom, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export(geom, "/tmp/test"LINE_STRING, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geoms[0]));
+ OK(scad_add_box(p4, d1, &geoms[1]));
+ OK(scad_geometries_collect(geoms, 2, &geom));
+ BAD(scad_stl_export_partial(NULL, geoms, 1, NULL, 9, 0));
+ BAD(scad_stl_export_partial(NULL, geoms, 1, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_partial(geom, geoms, 1, NULL, 9, 0));
+ BAD(scad_stl_export_partial(geom, geoms, 1, NULL, SCAD_FORCE_NORMALS_INWARD, 0));
+ OK(scad_stl_export_partial(geom, geoms, 1, "/tmp/test"LINE_STRING,
+ SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_set_name(geom, "name"));
+ BAD(scad_stl_export_partial(NULL, geoms, 1, NULL, 9, 0));
+ BAD(scad_stl_export_partial(NULL, geoms, 1, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_partial(geom, geoms, 1, NULL, 9, 0));
+ OK(scad_stl_export_partial(geom, geoms, 1, NULL, SCAD_FORCE_NORMALS_INWARD, 0));
+ OK(scad_stl_export_partial(geom, geoms, 1, "/tmp/test"LINE_STRING,
+ SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_stl_export_partial(geom, NULL, 0, "/tmp/test"LINE_STRING,
+ SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom));
+ BAD(scad_stl_export_split(NULL, NULL, 9, 0));
+ BAD(scad_stl_export_split(NULL, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_split(geom, NULL, 9, 0));
+ BAD(scad_stl_export_split(geom, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export_split(geom, "/tmp/test"LINE_STRING, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_set_name(geom, "name"));
+ BAD(scad_stl_export_split(NULL, NULL, 9, 0));
+ BAD(scad_stl_export_split(NULL, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_export_split(geom, NULL, 9, 0));
+ OK(scad_stl_export_split(geom, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export_split(geom, "/tmp/test"LINE_STRING, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom));
darray_double_init(&allocator, &trg);
+ OK(scad_geometries_set_mesh_algorithm(&geom, 1, SCAD_INITIAL_MESH_ONLY));
+ OK(scad_scene_mesh());
BAD(scad_stl_get_data(NULL, NULL));
- BAD(scad_stl_get_data(geom2, NULL));
- OK(scad_stl_get_data(geom2, &trg));
- BAD(scad_stl_data_write(NULL, NULL, Scad_keep_normals_unchanged, 0));
- BAD(scad_stl_data_write(&trg, NULL, Scad_keep_normals_unchanged, 0));
- BAD(scad_stl_data_write(NULL, "/tmp/test", Scad_keep_normals_unchanged, 0));
- OK(scad_stl_data_write(&trg, "/tmp/test", Scad_keep_normals_unchanged, 0));
- OK(scad_stl_data_write(&trg, "/tmp/test", Scad_keep_normals_unchanged, 1));
+ BAD(scad_stl_get_data(NULL, &trg));
+ BAD(scad_stl_get_data(geom, NULL));
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(12 * 9 == darray_double_size_get(&trg));
darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
- BAD(scad_stl_export(NULL, NULL, Scad_keep_normals_unchanged, 0));
- BAD(scad_stl_export(geom2, NULL, Scad_keep_normals_unchanged, 0)); /* geom2 has no name */
- OK(scad_stl_export(geom2, "/tmp/test", Scad_keep_normals_unchanged, 0));
- OK(scad_stl_export(geom2, "/tmp/test", Scad_force_normals_inward, 1));
- OK(scad_stl_export(geom1, NULL, Scad_force_normals_outward, 1));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
- BAD(scad_stl_export_split(NULL, NULL, Scad_keep_normals_unchanged, 0));
- BAD(scad_stl_export_split(geom2, NULL, Scad_keep_normals_unchanged, 0)); /* geom2 has no name */
- OK(scad_stl_export_split(geom2, "/tmp/test", Scad_keep_normals_unchanged, 0));
- OK(scad_stl_export_split(geom2, "/tmp/testb", Scad_keep_normals_unchanged, 1));
- OK(scad_stl_export_split(geom1, NULL, Scad_keep_normals_unchanged, 0));
- OK(scad_stl_export_split(geom1, "different_names", Scad_keep_normals_unchanged, 1));
+ OK(scad_add_box(p1, d1, &geoms[0]));
+ OK(scad_add_box(p4, d1, &geoms[1]));
+ OK(scad_geometries_collect(geoms, 2, &geom));
+ darray_double_init(&allocator, &trg);
+ OK(scad_geometries_set_mesh_algorithm(geoms, 2, SCAD_INITIAL_MESH_ONLY));
+ OK(scad_scene_mesh());
+ BAD(scad_stl_get_data_partial(NULL, NULL, 0, NULL));
+ BAD(scad_stl_get_data_partial(NULL, NULL, 0, &trg));
+ BAD(scad_stl_get_data_partial(geom, NULL, 0, NULL));
+ OK(scad_stl_get_data_partial(geom, NULL, 0, &trg));
+ CHK(2 * 12 * 9 == darray_double_size_get(&trg));
+ darray_double_clear(&trg);
+ OK(scad_stl_get_data_partial(geom, geoms, 1, &trg));
+ CHK(12 * 9 == darray_double_size_get(&trg));
+ darray_double_clear(&trg);
+ OK(scad_stl_get_data_partial(geom, geoms, 2, &trg));
+ CHK(0 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geoms[0]));
+ OK(scad_geometry_ref_put(geoms[1]));
- BAD(scad_geometry_get_name(NULL, &name));
- BAD(scad_geometry_get_name(geom1, NULL));
- OK(scad_geometry_get_name(geom1, &name));
- OK(scad_geometry_get_name(geom2, &name));
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ OK(scad_add_box(p1, d1, &geom));
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(0 == darray_double_size_get(&trg)); /* No call to mesh */
+ BAD(scad_stl_data_write(NULL, NULL, 9, 0));
+ BAD(scad_stl_data_write(NULL, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ BAD(scad_stl_data_write(&trg, NULL, 9, 0));
+ BAD(scad_stl_data_write(&trg, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_data_write(&trg, "/tmp/test"LINE_STRING, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_scene_count(&c));
+ CHK(c == 0);
+
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ONLY_UNDELETED;
+ OK(scad_set_options(&options));
OK(scad_finalize());
diff --git a/src/test_export.c b/src/test_export.c
@@ -35,39 +35,50 @@ main(int argc, char* argv[])
struct scad_geometry* fused = NULL;
struct scad_geometry* geoms[2];
struct mem_allocator allocator;
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
(void)argc; (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
OK(scad_initialize(NULL, &allocator, 3));
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ALL | SCAD_LOG_GEOMETRY;
+ OK(scad_set_options(&options));
- OK(scad_add_rectangle("rectangle", p1, d1, &rectangle));
- OK(scad_add_box("cube", p1, d1, &cube));
- OK(scad_add_cylinder(NULL, p2, d1, 0.5, 2*PI, geoms+1));
+ OK(scad_add_rectangle(p1, d1, &rectangle));
+ OK(scad_geometry_set_name(rectangle, "rectangle"));
+ OK(scad_add_box(p1, d1, &cube));
+ OK(scad_geometry_set_name(cube, "cube"));
+ OK(scad_add_cylinder(p2, d1, 0.5, 2*PI, geoms+1));
geoms[0] = cube;
- OK(scad_fuse_geometries("fused", geoms, 1, geoms+1, 1, &fused));
+ OK(scad_geometries_fuse(geoms, 1, geoms+1, 1, &fused));
+ OK(scad_geometry_set_name(fused, "fused"));
OK(scad_scene_mesh());
/* Do not define a volume */
- BAD(scad_stl_export(rectangle, "not-a-volume.stl", Scad_force_normals_outward, 0));
+ BAD(scad_stl_export(rectangle, "not-a-volume.stl", SCAD_FORCE_NORMALS_OUTWARD, 0));
- OK(scad_stl_export(rectangle, NULL, Scad_keep_normals_unchanged, 0));
- OK(scad_stl_export(rectangle, "bin_rectangle", Scad_keep_normals_unchanged, 1));
+ OK(scad_stl_export(rectangle, NULL, SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export(rectangle, "bin_rectangle", SCAD_KEEP_NORMALS_UNCHANGED, 1));
- OK(scad_stl_export(cube, NULL, Scad_force_normals_outward, 0));
- OK(scad_stl_export(cube, "bin_cube", Scad_force_normals_outward, 1));
+ OK(scad_stl_export(cube, NULL, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(cube, "bin_cube", SCAD_FORCE_NORMALS_OUTWARD, 1));
- OK(scad_stl_export(fused, NULL, Scad_force_normals_outward, 0));
- OK(scad_stl_export(fused, "bin_fused", Scad_force_normals_outward, 1));
+ OK(scad_stl_export(fused, NULL, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(fused, "bin_fused", SCAD_FORCE_NORMALS_OUTWARD, 1));
/* New meshing algorithm */
- OK(scad_geometries_set_mesh_algorithm(geoms, 2, Scad_Quasi_Structured));
+ OK(scad_geometries_set_mesh_algorithm(geoms, 2, SCAD_QUASI_STRUCTURED));
OK(scad_scene_mesh());
- OK(scad_stl_export(rectangle, "rectangle_quasi", Scad_keep_normals_unchanged, 0));
- OK(scad_stl_export(cube, "cube_quasi", Scad_force_normals_outward, 0));
- OK(scad_stl_export(fused, "fused_quasi", Scad_force_normals_outward, 0));
+ OK(scad_stl_export(rectangle, "rectangle_quasi", SCAD_KEEP_NORMALS_UNCHANGED, 0));
+ OK(scad_stl_export(cube, "cube_quasi", SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(fused, "fused_quasi", SCAD_FORCE_NORMALS_OUTWARD, 0));
+
+ OK(scad_geometry_ref_put(rectangle));
+ OK(scad_geometry_ref_put(cube));
+ OK(scad_geometry_ref_put(geoms[1]));
+ OK(scad_geometry_ref_put(fused));
OK(scad_finalize());
diff --git a/src/test_export2.c b/src/test_export2.c
@@ -55,38 +55,44 @@ main(int argc, char* argv[])
struct scad_geometry* cube2 = NULL;
struct scad_geometry* cube3 = NULL;
struct mem_allocator allocator;
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
(void)argc; (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
darray_double_init(&allocator, &array);
OK(scad_initialize(NULL, &allocator, 3));
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ALL | SCAD_LOG_GEOMETRY;
+ OK(scad_set_options(&options));
- OK(scad_add_box("cube1", p1, d1, &cube1));
- OK(scad_add_box("cube2", p2, d2, &cube2));
- OK(scad_add_box("cube3", p3, d3, &cube3));
+ OK(scad_add_box(p1, d1, &cube1));
+ OK(scad_geometry_set_name(cube1, "cube1"));
+ OK(scad_add_box(p2, d2, &cube2));
+ OK(scad_geometry_set_name(cube2, "cube2"));
+ OK(scad_add_box(p3, d3, &cube3));
+ OK(scad_geometry_set_name(cube3, "cube3"));
OK(scad_scene_mesh());
/* Check that all three cubes can be exported whith forced normals */
- OK(scad_stl_export(cube1, NULL, Scad_force_normals_outward, 0));
- OK(scad_stl_export(cube2, NULL, Scad_force_normals_outward, 0));
- OK(scad_stl_export(cube3, "bin_cube3", Scad_force_normals_outward, 1));
+ OK(scad_stl_export(cube1, NULL, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(cube2, NULL, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(cube3, "bin_cube3", SCAD_FORCE_NORMALS_OUTWARD, 1));
/* Check that 2 cubes as a single model can be exported whith forced normals */
OK(scad_stl_get_data(cube1, &array));
OK(scad_stl_get_data(cube2, &array));
- OK(scad_stl_data_write(&array, "2cubes.stl", Scad_force_normals_outward, 0));
+ OK(scad_stl_data_write(&array, "2cubes.stl", SCAD_FORCE_NORMALS_OUTWARD, 0));
/* Check that with 3 cubes as a single model, the model cannot be exported
* whith forced normals... */
OK(scad_stl_get_data(cube3, &array));
- BAD(scad_stl_data_write(&array, "3cubes.stl", Scad_force_normals_outward, 0));
+ BAD(scad_stl_data_write(&array, "3cubes.stl", SCAD_FORCE_NORMALS_OUTWARD, 0));
/* ...but can be exported anyway without forcing normals... */
- OK(scad_stl_data_write(&array, "3cubes.stl", Scad_keep_normals_unchanged, 0));
+ OK(scad_stl_data_write(&array, "3cubes.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
/* ...and can still be exported if some triangles are duplicated */
OK(scad_stl_get_data(cube1, &array));
- OK(scad_stl_data_write(&array, "3cubesd.stl", Scad_keep_normals_unchanged, 0));
+ OK(scad_stl_data_write(&array, "3cubesd.stl", SCAD_KEEP_NORMALS_UNCHANGED, 0));
OK(scad_geometry_ref_put(cube1));
OK(scad_geometry_ref_put(cube2));
diff --git a/src/test_lifetime.c b/src/test_lifetime.c
@@ -36,13 +36,14 @@ alive_and_well
ASSERT(g && allocator);
- OK(scad_geometry_explode(g, "alive_and_well", &geom_array, &c));
+ OK(scad_geometry_explode(g, &geom_array, &c));
+ OK(scad_geometries_set_name(geom_array, c, "alive_and_well", 0));
OK(scad_geometry_ref_put(g));
OK(scad_synchronize());
for(i = 0; i < c; i++) {
double dir1[3] = {0, 0, 1};
struct scad_geometry* gg;
- OK(scad_geometry_extrude(geom_array[i], "a_n_w_extruded", dir1, &gg));
+ OK(scad_geometry_extrude(geom_array[i], dir1, &gg));
OK(scad_geometry_ref_put(geom_array[i]));
OK(scad_geometry_ref_put(gg));
}
@@ -57,13 +58,13 @@ main(int argc, char* argv[])
double diago[] = {1, 1, 1}, diago_[] = {.5, .5, -1}, base[] = {1, 1, 0};
double dir1[3] = {0, 0, 1};
struct scad_geometry* geom1 = NULL;
- struct scad_geometry* geom2 = NULL;
struct scad_geometry* geom = NULL;
struct scad_geometry* geoms[2];
struct scad_geometry* out_geoms[2];
struct mem_allocator allocator;
struct scad_geometry** list = NULL;
- size_t list_n, center_n, i;
+ struct scad_geometry** list2 = NULL;
+ size_t list_n, list_n2, center_n, i;
double center[3], N[3];
struct scad_options options = SCAD_DEFAULT_OPTIONS;
@@ -72,57 +73,72 @@ main(int argc, char* argv[])
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
OK(scad_initialize(NULL, &allocator, 3));
- options.Misc.LogRefCounting = Scad_log_dimTags_all | Scad_log_geometry;
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ALL | SCAD_LOG_GEOMETRY;
OK(scad_set_options(&options));
/* Check that 2D constituants of a deleted 3D object are alive and well */
- OK(scad_add_box("box", p1, diago, &geom));
- OK(scad_geometry_boundary("boundary", &geom, 1, &geom1));
+ OK(scad_add_box(p1, diago, &geom));
+ OK(scad_geometries_boundaries(&geom, 1, &list, &list_n));
+ OK(scad_geometries_set_name(list, list_n, "boundary", 0));
OK(scad_geometry_ref_put(geom));
- alive_and_well(geom1, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ MEM_RM(&allocator, list); list = NULL;
/* Check that a 3D derivative of a deleted 2D object is alive and well */
- OK(scad_add_rectangle("rect", p1, base, &geom));
- OK(scad_geometry_extrude(geom, "cube", dir1, &geom1));
+ OK(scad_add_rectangle(p1, base, &geom));
+ OK(scad_geometry_extrude(geom, dir1, &geom1));
OK(scad_geometry_ref_put(geom));
- OK(scad_geometry_boundary("boundary", &geom1, 1, &geom2));
+ OK(scad_geometries_boundaries(&geom1, 1, &list, &list_n));
+ OK(scad_geometries_set_name(list, list_n, "boundary", 0));
OK(scad_geometry_ref_put(geom1));
- alive_and_well(geom2, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ MEM_RM(&allocator, list); list = NULL;
/* Check that a 2D part of a deleted 3D object is alive and well */
- OK(scad_add_rectangle("rect2", p1, base, &geom));
- OK(scad_geometry_extrude(geom, "cube2", dir1, &geom1));
+ OK(scad_add_rectangle(p1, base, &geom));
+ OK(scad_geometry_extrude(geom, dir1, &geom1));
OK(scad_geometry_ref_put(geom1));
alive_and_well(geom, &allocator);
- OK(scad_add_box("cavity", p1, diago, &geom1));
- OK(scad_geometry_boundary("bcavity", &geom1, 1, &geom2));
- OK(scad_geometry_explode(geom2, "explode", &list, &list_n));
- OK(scad_geometry_ref_put(geom2));
- OK(scad_geometry_get_count(list[0], ¢er_n));
- ASSERT(center_n == 1);
- OK(scad_geometry_get_centerofmass(list[0], center));
- OK(scad_geometry_normal(list[0], center, N, "surface", &geom));
- OK(scad_geometry_ref_put(geom));
+ OK(scad_add_box(p1, diago, &geom1));
+ OK(scad_geometries_boundaries(&geom1, 1, &list, &list_n));
+ OK(scad_geometries_set_name(list, list_n, "bcavity", 0));
+ for(i = 0; i < list_n; i++) {
+ OK(scad_geometry_get_count(list[i], ¢er_n));
+ ASSERT(center_n == 1);
+ OK(scad_geometry_get_centerofmass(list[i], center));
+ OK(scad_geometry_get_normal(list[i], center, N, &geom));
+ OK(scad_geometry_ref_put(geom));
+ }
for(i = 0; i < list_n; i++) {
OK(scad_geometry_ref_put(list[i]));
}
- MEM_RM(&allocator, list);
+ MEM_RM(&allocator, list); list = NULL;
OK(scad_geometry_ref_put(geom1));
/* Check that 2D constituants of a deleted 3D object are alive and well after
* a partition */
- OK(scad_add_box("box1", p1, diago, geoms+0));
- OK(scad_add_box("box2", p1, diago_, geoms+1));
- OK(scad_geometry_boundary(NULL, geoms+0, 1, &geom1));
- OK(scad_geometry_boundary(NULL, geoms+1, 1, &geom2));
+ OK(scad_add_box(p1, diago, geoms+0));
+ OK(scad_add_box(p1, diago_, geoms+1));
+ OK(scad_geometries_boundaries(geoms+0, 1, &list, &list_n));
+ OK(scad_geometries_boundaries(geoms+1, 1, &list2, &list_n2));
OK(scad_geometries_partition(geoms, 2, 0, out_geoms));
OK(scad_geometry_ref_put(geoms[0]));
OK(scad_geometry_ref_put(geoms[1]));
- alive_and_well(geom1, &allocator);
- alive_and_well(geom2, &allocator);
+ for(i = 0; i < list_n; i++) {
+ alive_and_well(list[i], &allocator);
+ }
+ for(i = 0; i < list_n2; i++) {
+ alive_and_well(list2[i], &allocator);
+ }
OK(scad_geometry_ref_put(out_geoms[0]));
OK(scad_geometry_ref_put(out_geoms[1]));
+ MEM_RM(&allocator, list); list = NULL;
+ MEM_RM(&allocator, list2); list = NULL;
OK(scad_finalize());
diff --git a/src/test_normals.c b/src/test_normals.c
@@ -0,0 +1,97 @@
+/* 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/str.h>
+#include <rsys/math.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/dynamic_array_double.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main(int argc, char* argv[])
+{
+ res_T res = RES_OK;
+ double p1[3] = {0, 0, 0};
+ double s1[3] = {1, 1, 0};
+ double c[3] = {0.5, 0.5, 0};
+ double scale[3] = {0.5, 0.5, 0.5};
+ double d1[3] = {0, 0, 1};
+ double d1_[3] = {0, 0, -1};
+ double m1, m2;
+ struct scad_geometry* base = NULL;
+ struct scad_geometry* sbase = NULL;
+ struct scad_geometry* geom1 = NULL;
+ struct scad_geometry* geom2 = NULL;
+ struct scad_geometry* geoms[2];
+ struct scad_geometry* part[2];
+ struct mem_allocator allocator;
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
+ struct darray_double trg;
+
+ (void)argc; (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ darray_double_init(&allocator, &trg);
+ OK(scad_initialize(NULL, &allocator, 3));
+ OK(scad_set_options(NULL));
+ OK(scad_set_options(&options));
+
+ OK(scad_add_rectangle("base", p1, s1, &base));
+ OK(scad_geometry_extrude(base, "top", d1, &geom1));
+ OK(scad_geometry_get_mass(geom1, &m1));
+
+ OK(scad_geometry_dilate(base, c, scale, "small_base", &sbase));
+ OK(scad_geometry_extrude(sbase, "bottom", d1_, &geom2));
+ OK(scad_geometry_get_mass(geom2, &m2));
+
+ geoms[0] = geom1;
+ geoms[1] = geom2;
+ OK(scad_synchronize());
+ OK(scad_geometries_partition(geoms, 2, 0, part));
+ OK(scad_synchronize());
+ OK(scad_scene_mesh());
+ OK(scad_synchronize());
+
+ CHK(eq_eps(m1, 1, 1e-10));
+ CHK(eq_eps(m2, 0.25, 1e-10));
+
+ OK(scad_stl_export(part[0], "/tmp/geom1", SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(part[1], "/tmp/geom2", SCAD_FORCE_NORMALS_OUTWARD, 0));
+
+ OK(scad_stl_get_data(geom2, &trg));
+ OK(scad_stl_data_write(&trg, "/tmp/test", 0, 0));
+ OK(scad_stl_data_write(&trg, "/tmp/test", 1, 1));
+
+ OK(scad_stl_export(geom2, "/tmp/test", SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(geom2, "/tmp/test", SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_stl_export(geom1, NULL, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(geom1, NULL, SCAD_FORCE_NORMALS_OUTWARD, 1));
+
+ OK(scad_finalize());
+ darray_double_release(&trg);
+
+ 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
@@ -46,18 +46,21 @@ two_geoms
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* out_geoms[2];
+ struct scad_geometry* geoms[2] = {NULL, NULL};
+ struct scad_geometry* out_geoms[2] = {NULL, NULL};
char name[64];
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
res_T res;
OK(scad_initialize(NULL, allocator, 3));
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ALL | SCAD_LOG_GEOMETRY;
+ OK(scad_set_options(&options));
/* set position for cube #2 */
d3(p2, x, 0.25, 0.25);
- OK(scad_add_box("cube1", p1, d1, geoms+0));
- OK(scad_add_box("cube2", p2, d2, geoms+1));
+ OK(scad_add_box(p1, d1, geoms+0));
+ OK(scad_add_box(p2, d2, geoms+1));
/* Try to partition.
* Fails if the 2 cubes overlap and overlapping is not allowed. */
@@ -75,26 +78,30 @@ two_geoms
* geometry of both cubes does not define and inside/outside and the
* partitioned geometry cannot have its normals forced */
if(x == 0.9) {
- BAD(scad_stl_export(out_geoms[0], name, Scad_force_normals_outward, 0));
- OK(scad_stl_export(out_geoms[0], name, Scad_keep_normals_unchanged, 0));
+ BAD(scad_stl_export(out_geoms[0], name, SCAD_FORCE_NORMALS_OUTWARD, 0));
+ OK(scad_stl_export(out_geoms[0], name, SCAD_KEEP_NORMALS_UNCHANGED, 0));
} else {
- OK(scad_stl_export(out_geoms[0], name, Scad_force_normals_outward, 1));
+ OK(scad_stl_export(out_geoms[0], name, SCAD_FORCE_NORMALS_OUTWARD, 1));
}
snprintf(name, sizeof(name), "part_%g_2o", x);
if(x == 0.9) {
- BAD(scad_stl_export(out_geoms[1], name, Scad_force_normals_outward, 1));
- OK(scad_stl_export(out_geoms[1], name, Scad_keep_normals_unchanged, 1));
+ BAD(scad_stl_export(out_geoms[1], name, SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_stl_export(out_geoms[1], name, SCAD_KEEP_NORMALS_UNCHANGED, 1));
} else {
- OK(scad_stl_export(out_geoms[1], name, Scad_force_normals_outward, 1));
+ OK(scad_stl_export(out_geoms[1], name, SCAD_FORCE_NORMALS_OUTWARD, 1));
}
} else {
snprintf(name, sizeof(name), "part_%g_1", x);
- OK(scad_stl_export(geoms[0], name, Scad_force_normals_outward, 0));
+ OK(scad_stl_export(geoms[0], name, SCAD_FORCE_NORMALS_OUTWARD, 0));
snprintf(name, sizeof(name), "part_%g_2", x);
- OK(scad_stl_export(geoms[1], name, Scad_force_normals_outward, 1));
+ OK(scad_stl_export(geoms[1], name, SCAD_FORCE_NORMALS_OUTWARD, 1));
}
end:
+ if(geoms[0]) OK(scad_geometry_ref_put(geoms[0]));
+ if(geoms[1]) OK(scad_geometry_ref_put(geoms[1]));
+ if(out_geoms[0]) OK(scad_geometry_ref_put(out_geoms[0]));
+ if(out_geoms[1]) OK(scad_geometry_ref_put(out_geoms[1]));
OK(scad_finalize());
return res;
}
diff --git a/src/test_periodic.c b/src/test_periodic.c
@@ -29,72 +29,74 @@ int
main(int argc, char* argv[])
{
struct mem_allocator allocator;
- struct scad_geometry *cyl1 = NULL, *cyl2 = NULL, *cyl = NULL;
- struct scad_geometry *bound = NULL, **faces = NULL;
- struct scad_geometry * internal = NULL, *external = NULL, *lat[2] = { NULL, NULL};
+ struct scad_geometry *cyl1 = NULL, *cyl2 = NULL, *cyl = NULL;
+ struct scad_geometry** faces = NULL;
+ struct scad_geometry *internal = NULL, *external = NULL, *lat[2] = { NULL, NULL};
double p1[3] = { 0,0,0 }, p2[3], d2[3] = { L,0,0};
double r1 = 1, r2 = r1 * XR, len;
double cyl_affine[16] = { 1, 0, 0, 0, 0, XR, 0, 0, 0, 0, XR, 0, 0, 0, 0, 1 };
size_t i, facesn;
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
(void)argc; (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- scad_initialize(NULL, &allocator, 2);
+ OK(scad_initialize(NULL, &allocator, 2));
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ALL | SCAD_LOG_GEOMETRY;
+ OK(scad_set_options(&options));
+
r2 = r1 * XR;
- scad_add_cylinder(NULL, p1, d2, r1, 2*PI, &cyl1);
- scad_add_cylinder(NULL, p1, d2, r2, 2*PI, &cyl2);
- scad_cut_geometries("cylinder", &cyl2, 1, &cyl1, 1, &cyl);
- scad_geometry_ref_put(cyl1);
- scad_geometry_ref_put(cyl2);
- scad_geometry_boundary(NULL, &cyl, 1, &bound);
- scad_geometry_explode(bound, NULL, &faces, &facesn);
- scad_geometry_ref_put(bound);
+ OK(scad_add_cylinder(p1, d2, r1, 2*PI, &cyl1));
+ OK(scad_add_cylinder(p1, d2, r2, 2*PI, &cyl2));
+ OK(scad_geometries_cut(&cyl2, 1, &cyl1, 1, &cyl));
+ OK(scad_geometry_ref_put(cyl1));
+ OK(scad_geometry_ref_put(cyl2));
+ OK(scad_geometries_boundaries(&cyl, 1, &faces, &facesn));
ASSERT(facesn == 4);
d3_add(p2, p1, d2);
len = d3_len(d2);
for(i = 0; i < facesn; i++) {
struct scad_geometry* f = faces[i];
double center[3], m;
- scad_geometry_get_centerofmass(f, center);
+ OK(scad_geometry_get_centerofmass(f, center));
if(fabs(center[0] - p1[0]) < FLT_EPSILON) {
ASSERT(lat[0] == NULL);
lat[0] = f;
- scad_geometry_rename(f, "left_side");
+ OK(scad_geometry_set_name(f, "left_side"));
continue;
}
if(fabs(center[0] - p2[0]) < FLT_EPSILON) {
ASSERT(lat[1] == NULL);
lat[1] = f;
- scad_geometry_rename(f, "right_side");
+ OK(scad_geometry_set_name(f, "right_side"));
continue;
}
scad_geometry_get_mass(f, &m);
if(fabs(m - len*2*PI*r1) < FLT_EPSILON) {
ASSERT(internal == NULL);
internal = f;
- scad_geometry_rename(f, "internal");
+ OK(scad_geometry_set_name(f, "internal"));
continue;
}
if(fabs(m - len*2*PI*r2) < FLT_EPSILON) {
ASSERT(external == NULL);
external = f;
- scad_geometry_rename(f, "external");
+ OK(scad_geometry_set_name(f, "external"));
continue;
}
}
ASSERT(lat[0] && lat[1] && internal && external);
- scad_geometries_set_periodic(&internal, 1, &external, 1, cyl_affine);
- scad_geometries_set_mesh_algorithm(lat, 1, Scad_Initial_Mesh_Only);
+ OK(scad_geometries_set_periodic(&internal, 1, &external, 1, cyl_affine));
+ OK(scad_geometries_set_mesh_algorithm(lat, 1, SCAD_INITIAL_MESH_ONLY));
for(i = 0; i < facesn; i++) {
- scad_geometry_ref_put(faces[i]);
+ OK(scad_geometry_ref_put(faces[i]));
}
MEM_RM(&allocator, faces);
- scad_scene_mesh();
- scad_stl_export(cyl, "periodic", Scad_force_normals_outward, 1);
- scad_geometry_ref_put(cyl);
- scad_finalize();
+ OK(scad_scene_mesh());
+ OK(scad_stl_export(cyl, "periodic", SCAD_FORCE_NORMALS_OUTWARD, 1));
+ OK(scad_geometry_ref_put(cyl));
+ OK(scad_finalize());
#undef XR
check_memory_allocator(&allocator);
diff --git a/src/test_sync.c b/src/test_sync.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2022-2025 |Méso|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/str.h>
+#include <rsys/math.h>
+#include <rsys/double3.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/dynamic_array_double.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;
+ const double p1[3] = {0, 0, 0};
+ const double p2[3] = {0.25, 0.25, 0.8};
+ const 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* poly = NULL;
+ struct mem_allocator allocator;
+ struct darray_double trg;
+ struct scad_options options = SCAD_DEFAULT_OPTIONS;
+ size_t c;
+
+ (void)argc; (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+
+ OK(scad_initialize(NULL, &allocator, 3));
+ options.Mesh.MeshSizeExtendFromBoundary = 0;
+ options.Mesh.MeshSizeFromPoints = 0;
+ options.Mesh.Algorithm = SCAD_INITIAL_MESH_ONLY;
+ OK(scad_set_options(&options));
+
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(12 * 9 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_add_box(p2, d1, &geom2));
+ OK(scad_geometries_cut(&geom1, 1, &geom2, 1, &geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_geometry_ref_put(geom2));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(24 * 9 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_add_polygon(get_position, coord, 0, 3, &poly));
+ OK(scad_geometry_extrude(poly, d1, &geom));
+ OK(scad_geometry_ref_put(poly));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(8 * 9 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_add_box(p1, d1, &geom1));
+ OK(scad_geometry_translate(geom1, d1, &geom));
+ OK(scad_geometry_ref_put(geom1));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(12 * 9 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_geometry_set_visibility(geom, 0, 1));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(0 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_scene_mesh());
+ OK(scad_geometries_clear_mesh(&geom, 1));
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(0 == darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ options.Mesh.Algorithm = SCAD_MESHADAPT;
+ options.Mesh.MeshSizeFromPoints = 1;
+ options.Mesh.MeshSizeExtendFromBoundary = 1;
+ OK(scad_set_options(&options));
+
+ OK(scad_add_box(p1, d1, &geom));
+ OK(scad_scene_mesh());
+ darray_double_init(&allocator, &trg);
+ OK(scad_stl_get_data(geom, &trg));
+ c = darray_double_size_get(&trg);
+ darray_double_clear(&trg);
+ printf("%ld trg\n", c/9);
+
+ OK(scad_geometries_clear_mesh(&geom, 1));
+ OK(scad_stl_get_data(geom, &trg));
+ CHK(0 == darray_double_size_get(&trg));
+
+ OK(scad_geometries_set_mesh_size_modifier(&geom, 1, SCAD_SIZE_FACTOR, 0.25));
+ OK(scad_scene_mesh());
+ OK(scad_stl_get_data(geom, &trg));
+ printf("%ld trg\n", darray_double_size_get(&trg)/9);
+ CHK(c < darray_double_size_get(&trg));
+ darray_double_release(&trg);
+ OK(scad_geometry_ref_put(geom));
+
+ options.Mesh.MeshSizeExtendFromBoundary = 0;
+ options.Mesh.MeshSizeFromPoints = 0;
+ options.Mesh.Algorithm = SCAD_INITIAL_MESH_ONLY;
+ OK(scad_set_options(&options));
+
+#if 0
+set mesh size cb : besoin de sync ?
+#endif
+
+ options.Misc.LogRefCounting = SCAD_LOG_DIMTAGS_ONLY_UNDELETED;
+ OK(scad_set_options(&options));
+
+ 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_tolerance.c b/src/test_tolerance.c
@@ -0,0 +1,99 @@
+/* Copyright (C) 2022-2024 |Méso|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/double3.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * +-------+ +-------+ +------+
+ * | | +----+ | +----+ | +----+
+ * | | | | | | | | || |
+ * | | +----+ | +----+ | +----+
+ * +-------+ +-------+ +------+
+ * x = 1.1 x = 1 x = 0.9
+ */
+
+static int
+tolerance
+ (double x,
+ double tol,
+ size_t expected_count,
+ struct mem_allocator* allocator)
+{
+ double p1[3] = {0, 0, 0};
+ double d[3] = {1, 1, 1};
+ double p2[3];
+ struct scad_geometry* geoms[2];
+ struct scad_geometry* out_geom;
+ size_t c;
+
+ ASSERT(tol > 0 && (expected_count == 1 || expected_count == 2));
+
+ OK(scad_initialize(NULL, allocator, 3));
+
+ /* set position for cube #2 */
+ d3(p2, x, 0, 0);
+
+ OK(scad_add_box("cube1", p1, d, geoms+0));
+ OK(scad_add_box("cube2", p2, d, geoms+1));
+
+ /* Try to fuse the 2 cubes and count resulting connex components */
+ OK(scad_fuse_geometries("fused", geoms, 1, geoms+1, 1, &out_geom));
+ OK(scad_geometry_get_count(out_geom, &c));
+
+ OK(scad_finalize());
+
+ return (c == expected_count) ? RES_OK : RES_BAD_ARG;
+}
+
+int
+main(int argc, char* argv[])
+{
+ struct mem_allocator allocator;
+ res_T res = RES_OK;
+
+ (void)argc; (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+
+ /* With contacting geometries */
+ OK(tolerance(1, 0.01, 1, &allocator));
+ OK(tolerance(1, 0.1, 1, &allocator));
+
+ /* With overlapping geometries */
+ OK(tolerance(0.9, 0.01, 1, &allocator));
+ OK(tolerance(0.9, 0.1, 1, &allocator));
+
+ /* With distant geometries */
+ OK(tolerance(1.1, 0.01, 2, &allocator));
+ OK(tolerance(1.1, 0.1, 1, &allocator));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+
+ return (res == RES_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
+}