star-3dut

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

commit d3f06f911e594df5299ee341f29c9e2c111ff23c
parent fe12da245401d7d14622f64f81fdeb72252ddbe2
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  5 Apr 2017 21:11:16 +0200

Add and test the s3dut_create_hemisphere function

Diffstat:
Mcmake/CMakeLists.txt | 2++
Msrc/s3dut.h | 30+++++++++++++++++++++++-------
Asrc/s3dut_hemisphere.c | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/s3dut_mesh.h | 1+
Asrc/test_s3dut_hemisphere.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 287 insertions(+), 7 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -44,6 +44,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(S3DUT_FILES_SRC s3dut_cuboid.c s3dut_cylinder.c + s3dut_hemisphere.c s3dut_mesh.c s3dut_sphere.c) set(S3DUT_FILES_INC s3dut_mesh.h) @@ -82,6 +83,7 @@ if(NOT NO_TEST) new_test(test_s3dut_cuboid) new_test(test_s3dut_cylinder) + new_test(test_s3dut_hemisphere) new_test(test_s3dut_sphere) rcmake_copy_runtime_libraries(test_s3dut_cuboid) diff --git a/src/s3dut.h b/src/s3dut.h @@ -61,10 +61,10 @@ s3dut_mesh_get_data (const struct s3dut_mesh* mesh, struct s3dut_mesh_data* data); -/* Create a triangulated UV sphere discretized in `nslices' around the Z axis - * and `nstacks' along the Z axis. Face vertices are CCW ordered with respect - * to the sphere center, i.e. they are CW ordered from the outside point of - * view. */ +/* Create a triangulated UV sphere centered in 0 discretized in `nslices' + * around the Z axis and `nstacks' along the Z axis. Face vertices are CCW + * ordered with respect to the sphere center, i.e. they are CW ordered from the + * outside point of view. */ S3DUT_API res_T s3dut_create_sphere (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ @@ -74,9 +74,11 @@ s3dut_create_sphere struct s3dut_mesh** sphere); /* Create a triangulated cylinder centered in 0 discretized in `nslices' around - * the Z axis and `nstacks' along the Z axis. Face vertices are CCW ordered - * with respect to the cylinder center, i.e. they are CW ordered from the - * outside point of view. */ + * the Z axis and `nstacks' along the Z axis. The top and the bottom of the + * cylinder is closed with a triangle fan whose center is on the Z axis. Face + * vertices are CCW ordered with respect to the cylinder center, i.e. they are + * CW ordered from the outside + * point of view. */ S3DUT_API res_T s3dut_create_cylinder (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ @@ -97,5 +99,19 @@ s3dut_create_cuboid const double depth, struct s3dut_mesh** cuboid); +/* Create a triangulated UV hemisphere oriented wrt Z axis. It discretized in + * `nslices' around the Z axis and `nstacks' along the Z axis. The back of the + * hemisphere is not triangulated. Face vertices are CCW ordered with respect + * to the hemisphere center, i.e. they are CW ordered from the outside point of + * view. */ +S3DUT_API res_T +s3dut_create_hemisphere + (struct mem_allocator* allocator, + const double radius, + const unsigned nslices, /* # subdivisions around Z axis in [2, INF) */ + const unsigned nstacks, /* # subdivisions along Z axis int [2, INF) */ + struct s3dut_mesh** hemisphere); + + #endif /* S3DUT_H */ diff --git a/src/s3dut_hemisphere.c b/src/s3dut_hemisphere.c @@ -0,0 +1,172 @@ +/* Copyright (C) |Meso|Star> 2016 (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 "s3dut_mesh.h" + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +setup_hemisphere_coords + (struct mem_allocator* allocator, + double* coords, + const double radius, + const unsigned nslices, /* # subdivisions around the Z axis */ + const unsigned nstacks) /* # subdivisions along the Z axis */ +{ + enum { SIN, COS }; + struct darray_double sincos_theta; + struct darray_double sincos_phi; + double step_theta; + double step_phi; + size_t itheta; + size_t iphi; + size_t i; + res_T res = RES_OK; + ASSERT(coords && radius > 0 && nslices >= 2 && nstacks >= 2); + + darray_double_init(allocator, &sincos_theta); + darray_double_init(allocator, &sincos_phi); + + res = darray_double_resize(&sincos_theta, nslices*2/*sin & cos*/); + if(res != RES_OK) goto error; + res = darray_double_resize(&sincos_phi, (nstacks-1)*2/*sin & cos*/); + if(res != RES_OK) goto error; + + /* Precompute the sinus/cosine of the theta/phi angles */ + step_theta = 2*PI / (double)nslices; + FOR_EACH(itheta, 0, nslices) { + const double theta = -PI + (double)itheta * step_theta; + darray_double_data_get(&sincos_theta)[itheta*2 + SIN] = sin(theta); + darray_double_data_get(&sincos_theta)[itheta*2 + COS] = cos(theta); + } + step_phi = PI/((double)nstacks * 2.0); + FOR_EACH(iphi, 0, nstacks-1) { + const double phi = (double)(iphi) * step_phi; + darray_double_data_get(&sincos_phi)[iphi*2 + SIN] = sin(phi); + darray_double_data_get(&sincos_phi)[iphi*2 + COS] = cos(phi); + } + + /* Setup the contour vertices */ + i = 0; + FOR_EACH(itheta, 0, nslices) { + const double* theta = darray_double_cdata_get(&sincos_theta) + itheta*2; + FOR_EACH(iphi, 0, nstacks-1) { + const double* phi = darray_double_cdata_get(&sincos_phi) + iphi*2; + coords[i++] = radius * COS[theta] * COS[phi]; + coords[i++] = radius * SIN[theta] * COS[phi]; + coords[i++] = radius * SIN[phi]; + } + } + + /* Setup the top polar vertex */ + coords[i++] = 0; + coords[i++] = 0; + coords[i++] = radius; + +exit: + darray_double_release(&sincos_theta); + darray_double_release(&sincos_phi); + return res; +error: + goto exit; +} + +static void +setup_hemisphere_indices + (size_t* ids, + const unsigned nslices, /* # subdivisions around the Z axis */ + const unsigned nstacks) /* # subdivisions along the Z axis */ +{ + size_t i, itheta, iphi; + ASSERT(ids && nslices && nstacks); + + /* Define the indices of the contour primitives */ + i = 0; + FOR_EACH(itheta, 0, nslices) { + const size_t itheta0 = itheta * (nstacks - 1); + const size_t itheta1 = ((itheta + 1) % nslices) * (nstacks - 1); + FOR_EACH(iphi, 0, nstacks-2) { + const size_t iphi0 = iphi + 0; + const size_t iphi1 = iphi + 1; + + ids[i++] = itheta0 + iphi0; + ids[i++] = itheta0 + iphi1; + ids[i++] = itheta1 + iphi0; + + ids[i++] = itheta1 + iphi0; + ids[i++] = itheta0 + iphi1; + ids[i++] = itheta1 + iphi1; + } + } + + /* Define the indices of the polar primitives */ + FOR_EACH(itheta, 0, nslices) { + const size_t itheta0 = itheta * (nstacks - 1); + const size_t itheta1 = ((itheta + 1) % nslices) * (nstacks - 1); + + ids[i++] = nslices * (nstacks - 1); + ids[i++] = itheta1 + (nstacks - 2); + ids[i++] = itheta0 + (nstacks - 2); + } +} + + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +s3dut_create_hemisphere + (struct mem_allocator* allocator, + const double radius, + const unsigned nslices, /* # subdivisions around the Z axis */ + const unsigned nstacks, /* # subdivisions along the Z axis */ + struct s3dut_mesh** mesh) +{ + struct s3dut_mesh* hemisphere = NULL; + size_t nverts; + size_t ntris; + res_T res = RES_OK; + + if(radius <= 0 || nslices < 2 || nstacks < 2 || !mesh) { + res = RES_BAD_ARG; + goto error; + } + + nverts = nslices*(nstacks-1)/* #contour verts*/ + 1/*polar vertex*/; + ntris = 2*nslices*(nstacks-2)/* #contour tris*/ + nslices/* #polar tris*/; + + res = mesh_create(allocator, S3DUT_MESH_HEMISPHERE, nverts, ntris, &hemisphere); + if(res != RES_OK) goto error; + + res = setup_hemisphere_coords(allocator, + darray_double_data_get(&hemisphere->coords), radius, nslices, nstacks); + if(res != RES_OK) goto error; + + setup_hemisphere_indices + (darray_size_t_data_get(&hemisphere->ids), nslices, nstacks); + +exit: + if(mesh) *mesh = hemisphere; + return res; +error: + if(hemisphere) { + S3DUT(mesh_ref_put(hemisphere)); + hemisphere = NULL; + } + goto exit; +} + 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_HEMISPHERE, S3DUT_MESH_SPHERE }; diff --git a/src/test_s3dut_hemisphere.c b/src/test_s3dut_hemisphere.c @@ -0,0 +1,89 @@ +/* Copyright (C) |Meso|Star> 2016 (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" + +#include <rsys/double3.h> +#include <rsys/math.h> + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct s3dut_mesh* msh; + struct s3dut_mesh_data data; + size_t i; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + + CHECK(s3dut_create_hemisphere(NULL, 0, 0, 0, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 0, 0, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 2, 0, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 2, 0, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 0, 2, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 0, 2, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 2, 2, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 2, 2, NULL), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 0, 0, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 0, 0, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 2, 0, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 2, 0, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 0, 2, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 0, 2, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 0, 2, 2, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(NULL, 1, 2, 2, &msh), RES_OK); + + CHECK(s3dut_mesh_ref_get(NULL), RES_BAD_ARG); + CHECK(s3dut_mesh_ref_get(msh), RES_OK); + CHECK(s3dut_mesh_ref_put(NULL), RES_BAD_ARG); + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + + CHECK(s3dut_create_hemisphere(&allocator, 1, 2, 2, &msh), RES_OK); + CHECK(s3dut_mesh_ref_put(msh), RES_OK); + + CHECK(s3dut_create_hemisphere(&allocator, 1, 1, 2, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(&allocator, 1, 2, 1, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(&allocator,-1, 2, 2, &msh), RES_BAD_ARG); + CHECK(s3dut_create_hemisphere(&allocator, 1, 32, 16, &msh), RES_OK); + + CHECK(s3dut_mesh_get_data(NULL, NULL), RES_BAD_ARG); + CHECK(s3dut_mesh_get_data(msh, NULL), RES_BAD_ARG); + CHECK(s3dut_mesh_get_data(NULL, &data), RES_BAD_ARG); + CHECK(s3dut_mesh_get_data(msh, &data), RES_OK); + NCHECK(data.positions, NULL); + NCHECK(data.indices, NULL); + CHECK(data.nvertices >= (32*(16-1)+1), 1); + CHECK(data.nprimitives, (32*(16-2)*2) + 32); + + FOR_EACH(i, 0, data.nvertices) { + double v[3]; + d3_set(v, data.positions + i*3); + v[2] = sqrt(MMAX(0, 1 - v[0]*v[0] - v[1]*v[1])); + CHECK(d3_eq_eps(v, data.positions + i*3, 1.e-6), 1); + } + + 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; +} +