star-3dut

Generate meshes of simple geometric shapes
git clone git://git.meso-star.fr/star-3dut.git
Log | Files | Refs | README | LICENSE

commit 06d3b6f5ae95ca50a3af874b31ea5226846740bc
parent 896ed1f6c4f437c753922cc3f40cdfa7325152c1
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu,  5 Oct 2017 17:57:21 +0200

Add an test the s3dut_create_thick_cylinder function.

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/s3dut.h | 19+++++++++++++++++++
Msrc/s3dut_cylinder.c | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/s3dut_mesh.h | 1+
Asrc/test_s3dut_thick_cylinder.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 288 insertions(+), 25 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -83,6 +83,7 @@ if(NOT NO_TEST) new_test(test_s3dut_cuboid) new_test(test_s3dut_cylinder) + new_test(test_s3dut_thick_cylinder) new_test(test_s3dut_hemisphere) new_test(test_s3dut_sphere) diff --git a/src/s3dut.h b/src/s3dut.h @@ -94,6 +94,25 @@ s3dut_create_cylinder const unsigned close_ends, /* Close ends of the cylinder? */ struct s3dut_mesh** cylinder); +/* Create a triangulated thick cylinder centered in 0 discretized in `nslices' + * around the Z axis and `nstacks' along the Z axis, with walls of thickness + * `thickness'. The top and the bottom of the cylinder can be closed or not, + * according to the `close_ends' argument bit mask. Closed ends are made of 2 + * triangle fans centered on the Z axis. Face vertices are CCW ordered with + * respect to the walls' inside, i.e. they are CW ordered from any point of + * view outside of the walls. */ +S3DUT_API res_T +s3dut_create_thick_cylinder + (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ + const double radius, /* In ]thickness, INF) */ + const double height, /* In ]min_height, INF); + min_height = 0, tickness or 2*thickness according to close_ends */ + const double thickness, /* In ]0, INF) */ + const unsigned nslices, /* # subdivisions around Z axis in [3, INF) */ + const unsigned nstacks, /* # subdivision along Z axis in [1, INF) */ + const unsigned close_ends, /* Close ends of the cylinder? */ + struct s3dut_mesh** cylinder); + /* Create a triangulated cuboid centered in 0. Face vertices are CCW ordered * with respect to the cylinder center, i.e. they are CW ordered from the * outside point of view. */ diff --git a/src/s3dut_cylinder.c b/src/s3dut_cylinder.c @@ -19,11 +19,12 @@ /******************************************************************************* * Helper functions ******************************************************************************/ -static void +static double* setup_cylinder_coords (double* coords, const double radius, - const double height, + const double z_bottom, + const double z_top, const unsigned nslices, const unsigned nstacks, const int close_bottom, @@ -31,6 +32,7 @@ setup_cylinder_coords { double step_theta; double step_z; + const double height = z_top - z_bottom; size_t itheta, istack; size_t i = 0; ASSERT(coords && radius > 0 && height > 0 && nslices >= 3 && nstacks >= 1); @@ -42,13 +44,13 @@ setup_cylinder_coords const double theta = (double)itheta * step_theta; const double x = cos(theta); const double y = sin(theta); - double z = -height * 0.5; + double z = z_bottom; FOR_EACH(istack, 0, nstacks+1) { coords[i++] = x*radius; coords[i++] = y*radius; coords[i++] = z; - z += step_z; + z = (istack==nstacks) ? z_top : z+step_z; /* No rounding error! */ } } @@ -56,24 +58,27 @@ setup_cylinder_coords if(close_bottom) { coords[i++] = 0; coords[i++] = 0; - coords[i++] = -height * 0.5; + coords[i++] = z_bottom; } /* Top polar vertex */ if(close_top) { coords[i++] = 0; coords[i++] = 0; - coords[i++] = height * 0.5; + coords[i++] = z_top; } + return coords + i; } -static void +static size_t* setup_cylinder_indices (size_t* ids, + const unsigned offset, const unsigned nslices, const unsigned nstacks, const int close_bottom, - const int close_top) + const int close_top, + const int cw_out) { size_t islice; size_t istack; @@ -83,39 +88,71 @@ setup_cylinder_indices ASSERT(ids && nslices && nstacks); FOR_EACH(islice, 0, nslices) { - const size_t islice0 = islice * (nstacks + 1); - const size_t islice1 = ((islice + 1) % nslices) * (nstacks + 1); + const size_t islice0 = offset + islice * (nstacks+1); + const size_t islice1 = offset + ((islice+1)%nslices) * (nstacks+1); FOR_EACH(istack, 0, nstacks) { const size_t istack0 = istack + 0; const size_t istack1 = istack + 1; - ids[i++] = islice0 + istack0; - ids[i++] = islice0 + istack1; - ids[i++] = islice1 + istack0; + ids[i] = islice0 + istack0; + ids[cw_out?i+1:i+2] = islice0 + istack1; + ids[cw_out?i+2:i+1] = islice1 + istack0; + i += 3; - ids[i++] = islice1 + istack0; - ids[i++] = islice0 + istack1; - ids[i++] = islice1 + istack1; + ids[i] = islice1 + istack0; + ids[cw_out?i+1:i+2] = islice0 + istack1; + ids[cw_out?i+2:i+1] = islice1 + istack1; + i += 3; } } if(close_bottom) { ibottom = nslices * (nstacks+1); FOR_EACH(islice, 0, nslices) { - ids[i++] = ibottom; - ids[i++] = islice * (nstacks+1); - ids[i++] = ((islice+1)%nslices) * (nstacks+1); + ids[i] = offset + ibottom; + ids[cw_out?i+1:i+2] = offset + islice * (nstacks+1); + ids[cw_out?i+2:i+1] = offset + ((islice+1)%nslices) * (nstacks+1); + i += 3; } } if(close_top) { itop = (close_bottom) ? nslices * (nstacks+1) + 1 : nslices * (nstacks+1); FOR_EACH(islice, 0, nslices) { - ids[i++] = itop; - ids[i++] = ((islice+1)%nslices) * (nstacks+1) + nstacks; - ids[i++] = islice * (nstacks+1) + nstacks; + ids[i] = offset + itop; + ids[cw_out?i+1:i+2] = offset + ((islice+1)%nslices) * (nstacks+1) + nstacks; + ids[cw_out?i+2:i+1] = offset + islice * (nstacks+1) + nstacks; + i += 3; } } + return ids + i; +} + +static size_t* +close_wall + (size_t* ids, + const size_t fst_id_out, + const size_t fst_id_in, + const unsigned nslices, + const unsigned nstacks, + const int bottom) +{ + size_t islice; + size_t i = 0; + ASSERT(ids && nslices >= 3 && nstacks >= 1); + + FOR_EACH(islice, 0, nslices) { + ids[i] = fst_id_out + islice * (nstacks+1); + ids[bottom?i+1:i+2] = fst_id_in + ((islice+1) % nslices) * (nstacks+1); + ids[bottom?i+2:i+1] = fst_id_in + islice * (nstacks+1); + i += 3; + + ids[i] = fst_id_out + islice * (nstacks+1); + ids[bottom?i+1:i+2] = fst_id_out + ((islice+1) % nslices) * (nstacks+1); + ids[bottom?i+2:i+1] = fst_id_in + ((islice+1) % nslices) * (nstacks+1); + i += 3; + } + return ids + i; } /******************************************************************************* @@ -156,9 +193,91 @@ s3dut_create_cylinder coords = darray_double_data_get(&cylinder->coords); ids = darray_size_t_data_get(&cylinder->ids); - setup_cylinder_coords - (coords, radius, height, nslices, nstacks, close_bottom, close_top); - setup_cylinder_indices(ids, nslices, nstacks, close_bottom, close_top); + setup_cylinder_coords(coords, radius, -0.5*height, +0.5*height, + nslices, nstacks, close_bottom, close_top); + setup_cylinder_indices(ids, 0, nslices, nstacks, close_bottom, close_top, 1); + +exit: + if(mesh) *mesh = cylinder; + return res; +error: + if(cylinder) { + S3DUT(mesh_ref_put(cylinder)); + cylinder = NULL; + } + goto exit; +} + +res_T +s3dut_create_thick_cylinder + (struct mem_allocator* allocator, + const double radius, + const double height, + const double thickness, + const unsigned nslices, + const unsigned nstacks, + const unsigned close_ends, + struct s3dut_mesh** mesh) +{ + struct s3dut_mesh* cylinder = NULL; + double* coords_out = NULL; + double* coords_in = NULL; + size_t* ids_out = NULL; + size_t* ids_in = NULL; + size_t* ids_walls = NULL; + size_t nverts; + size_t ntris; + size_t id_offset; + const int close_bottom = close_ends & S3DUT_END_BOTTOM; + const int close_top = close_ends & S3DUT_END_TOP; + const int nb_closed_ends = (close_bottom ? 1 : 0) + (close_top ? 1 : 0); + res_T res = RES_OK; + + if(radius <= 0 || height <= 0 || thickness <= 0 + || radius <= thickness || height <= (double)nb_closed_ends * thickness + || nslices < 3 || nstacks < 1 || !mesh) { + res = RES_BAD_ARG; + goto error; + } + + nverts = 2 * (nslices * (nstacks+1) /*#contour verts*/ + + nb_closed_ends); /*#polar verts*/ + ntris = 2 * (2 * nslices*nstacks /*#contour tris*/ + + 2 * nslices); /*#trg fans tris, regardless of closedness*/ + + res = mesh_create + (allocator, S3DUT_MESH_THICK_CYLINDER, nverts, ntris, &cylinder); + if(res != RES_OK) goto error; + + coords_out = darray_double_data_get(&cylinder->coords); + ids_out = darray_size_t_data_get(&cylinder->ids); + /* External cylinder */ + coords_in = setup_cylinder_coords(coords_out, radius, -0.5*height, +0.5*height, + nslices, nstacks, close_bottom, close_top); + ids_in = setup_cylinder_indices + (ids_out, 0, nslices, nstacks, close_bottom, close_top, 1); + /* Internal cylinder */ + id_offset = coords_in - coords_out; + ASSERT(id_offset % 3 == 0); + id_offset /= 3; + ASSERT(id_offset <= UINT_MAX); + setup_cylinder_coords(coords_in, + radius - thickness, + close_bottom ? -0.5*height + thickness : -0.5*height, + close_top ? +0.5*height -thickness : +0.5*height, + nslices, nstacks, close_bottom, close_top); + ids_walls = setup_cylinder_indices + (ids_in, (unsigned)id_offset, nslices, nstacks, close_bottom, close_top, 0); + /* Close walls where the cylinder is open */ + ASSERT((coords_in - coords_out) % 3 == 0); + if(!close_bottom) { + ids_walls = close_wall(ids_walls, 0, (coords_in - coords_out) / 3, + nslices, nstacks, 1); + } + if(!close_top) { + close_wall(ids_walls, nstacks, (coords_in - coords_out) / 3 + nstacks, + nslices, nstacks, 0); + } exit: if(mesh) *mesh = cylinder; diff --git a/src/s3dut_mesh.h b/src/s3dut_mesh.h @@ -23,6 +23,7 @@ enum s3dut_mesh_type { S3DUT_MESH_CUBOID, S3DUT_MESH_CYLINDER, + S3DUT_MESH_THICK_CYLINDER, S3DUT_MESH_HEMISPHERE, S3DUT_MESH_SPHERE }; diff --git a/src/test_s3dut_thick_cylinder.c b/src/test_s3dut_thick_cylinder.c @@ -0,0 +1,123 @@ +/* Copyright (C) |Meso|Star> 2016-2017 (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 "s3dut.h" +#include "test_s3dut_utils.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct s3dut_mesh* msh; + struct s3dut_mesh_data data; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + #define CR_CYL s3dut_create_thick_cylinder + CHECK(CR_CYL(NULL, 0, 0, 0, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 3, 0, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 0, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 3, 1, 0, NULL), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 0, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 0, 0.1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 0, 0.1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 0, 1, 0.1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(NULL, 1, 1, 0.1, 3, 1, 0, &msh), RES_OK); + + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + + CHECK(CR_CYL(&allocator, 1, 1, 0.1, 3, 1, 0, &msh), RES_OK); + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + + CHECK(CR_CYL(&allocator,-1, 1, 0.1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 1,-1, 0.1, 3, 1, 0, &msh), RES_BAD_ARG); + + CHECK(CR_CYL(&allocator, 1, 1, -0.1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 1, 1, 1, 3, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 2, 1, 0.5, 3, 1, + S3DUT_END_TOP| S3DUT_END_BOTTOM, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 2, 0.5, 0.5, 3, 1, S3DUT_END_TOP, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 2, 0.5, 0.5, 3, 1, S3DUT_END_BOTTOM, &msh), RES_BAD_ARG); + + CHECK(CR_CYL(&allocator, 1, 1, 0.1, 2, 1, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 1, 1, 0.1, 3, 0, 0, &msh), RES_BAD_ARG); + CHECK(CR_CYL(&allocator, 1, 2, 0.1, 16, 4, S3DUT_END_TOP, &msh), RES_OK); + #undef CR_CYL + + CHECK(s3dut_mesh_get_data(msh, &data), RES_OK); + dump_mesh_data(stdout, &data); + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} +