star-cad

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

commit 15b3a36c563d9851b3e9718bc675bc182880afa0
parent 8d5936d783ab11fa6f293c985753373d345d704a
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 10 Oct 2025 10:16:41 +0200

Rename scad_geometries_boundary API call

New name is scad_geometries_boundaries, to be consistent with
scad_geometries_common_boundaries.

Diffstat:
Msrc/scad.h | 10+++++-----
Msrc/scad_geometry.c | 2+-
Msrc/test_api.c | 36++++++++++++++++++------------------
Msrc/test_lifetime.c | 10+++++-----
Asrc/test_normals.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_periodic.c | 2+-
Asrc/test_tolerance.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 226 insertions(+), 30 deletions(-)

diff --git a/src/scad.h b/src/scad.h @@ -563,7 +563,7 @@ scad_geometries_partition const int flags, struct scad_geometry** out_geometries); -/* compute boundary intersection (the common part) of the geometries in +/* 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 @@ -581,12 +581,12 @@ scad_geometries_common_boundaries struct scad_geometry*** out_boundaries, size_t *out_count); -/* Get the boundary of the geometries in `geometries', considered as a whole. +/* 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_boundary +scad_geometries_boundaries (struct scad_geometry** geometries, const size_t geometries_count, struct scad_geometry*** out_boundaries, @@ -697,8 +697,8 @@ scad_stl_export_partial const int binary); /* Export the geometry `geometry' in as many files than its count. - * The files are named <base>_<rank>.stl, where <base> is either filename (first - * choice) or geom's name, <rank> counting from 0. */ + * The files are named <base>_<rank>.stl, where <base> is either `filename' + * (first choice) or `geometry's name, <rank> counting from 0. */ SCAD_API res_T scad_stl_export_split (struct scad_geometry* geometry, diff --git a/src/scad_geometry.c b/src/scad_geometry.c @@ -2912,7 +2912,7 @@ error: } res_T -scad_geometries_boundary +scad_geometries_boundaries (struct scad_geometry** geometries, const size_t geometries_count, struct scad_geometry*** out_boundaries, diff --git a/src/test_api.c b/src/test_api.c @@ -134,7 +134,7 @@ main(int argc, char* argv[]) 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_boundary(&geom1, 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)); @@ -202,7 +202,7 @@ main(int argc, char* argv[]) 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_boundary(&geom1, 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)); @@ -1316,22 +1316,22 @@ main(int argc, char* argv[]) CHK(c == 0); OK(scad_add_sphere(p1, 0.1, &geom1)); - BAD(scad_geometries_boundary(NULL, 0, NULL, NULL)); - BAD(scad_geometries_boundary(NULL, 0, NULL, &c)); - BAD(scad_geometries_boundary(NULL, 0, &geom_array, NULL)); - BAD(scad_geometries_boundary(NULL, 1, NULL, NULL)); - BAD(scad_geometries_boundary(&geom1, 0, NULL, NULL)); - BAD(scad_geometries_boundary(NULL, 0, &geom_array, &c)); - BAD(scad_geometries_boundary(NULL, 1, NULL, &c)); - BAD(scad_geometries_boundary(&geom1, 0, NULL, &c)); - BAD(scad_geometries_boundary(NULL, 1, &geom_array, NULL)); - BAD(scad_geometries_boundary(&geom1, 0, &geom_array, NULL)); - BAD(scad_geometries_boundary(&geom1, 1, NULL, NULL)); - BAD(scad_geometries_boundary(&geom1, 1, &geom_array, NULL)); - BAD(scad_geometries_boundary(&geom1, 1, NULL, &c)); - BAD(scad_geometries_boundary(&geom1, 0, &geom_array, &c)); - BAD(scad_geometries_boundary(NULL, 1, &geom_array, &c)); - OK(scad_geometries_boundary(&geom1, 1, &geom_array, &c)); + 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])); } diff --git a/src/test_lifetime.c b/src/test_lifetime.c @@ -78,7 +78,7 @@ main(int argc, char* argv[]) /* Check that 2D constituants of a deleted 3D object are alive and well */ OK(scad_add_box(p1, diago, &geom)); - OK(scad_geometries_boundary(&geom, 1, &list, &list_n)); + 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)); for(i = 0; i < list_n; i++) { @@ -90,7 +90,7 @@ main(int argc, char* argv[]) OK(scad_add_rectangle(p1, base, &geom)); OK(scad_geometry_extrude(geom, dir1, &geom1)); OK(scad_geometry_ref_put(geom)); - OK(scad_geometries_boundary(&geom1, 1, &list, &list_n)); + 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)); for(i = 0; i < list_n; i++) { @@ -105,7 +105,7 @@ main(int argc, char* argv[]) alive_and_well(geom, &allocator); OK(scad_add_box(p1, diago, &geom1)); - OK(scad_geometries_boundary(&geom1, 1, &list, &list_n)); + 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], &center_n)); @@ -124,8 +124,8 @@ main(int argc, char* argv[]) * a partition */ OK(scad_add_box(p1, diago, geoms+0)); OK(scad_add_box(p1, diago_, geoms+1)); - OK(scad_geometries_boundary(geoms+0, 1, &list, &list_n)); - OK(scad_geometries_boundary(geoms+1, 1, &list2, &list_n2)); + 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])); 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_periodic.c b/src/test_periodic.c @@ -52,7 +52,7 @@ main(int argc, char* argv[]) OK(scad_geometries_cut(&cyl2, 1, &cyl1, 1, &cyl)); OK(scad_geometry_ref_put(cyl1)); OK(scad_geometry_ref_put(cyl2)); - OK(scad_geometries_boundary(&cyl, 1, &faces, &facesn)); + OK(scad_geometries_boundaries(&cyl, 1, &faces, &facesn)); ASSERT(facesn == 4); d3_add(p2, p1, d2); len = d3_len(d2); 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; +}