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