commit b192356b48a4ee7bab9b6e21bc4316dfc0f8c9e9
parent 57db410e881295c3fbfa1846ece9ce0a5364067a
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Mon, 9 Oct 2017 16:01:39 +0200
Add and test s3dut_create_thick_truncated_sphere function.
Diffstat:
5 files changed, 266 insertions(+), 31 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -86,6 +86,7 @@ if(NOT NO_TEST)
new_test(test_s3dut_hemisphere)
new_test(test_s3dut_sphere)
new_test(test_s3dut_truncated_sphere)
+ new_test(test_s3dut_thick_truncated_sphere)
rcmake_copy_runtime_libraries(test_s3dut_cuboid)
endif()
diff --git a/src/s3dut.h b/src/s3dut.h
@@ -157,4 +157,26 @@ s3dut_create_truncated_sphere
Meaningless if no truncation. */
struct s3dut_mesh** sphere);
+/* Create a triangulated thick UV sphere 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 sphere can be truncated at some
+ * specified z, according to the `z_range' parameter. If truncated, the top and
+ * the bottom of the sphere can be closed or not, according to the `close_ends'
+ * argument bit mask. Closed ends are closed by a wall of thickness `thickness'
+ * 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_truncated_sphere
+ (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
+ const double radius, /* In ]thickness, INF); exterior radius */
+ const double thickness, /* In ]0, INF) */
+ const unsigned nslices, /* # subdivisions around Z axis in [3, INF) */
+ const unsigned nstacks, /* # subdivisions along Z axis in [2, INF) */
+ const double z_range[2], /* Mesh only the sphere in the z_range range;
+ can be NULL => keep the whole sphere */
+ const unsigned close_ends, /* Close truncated ends of the sphere?
+ Meaningless if no truncation. */
+ struct s3dut_mesh** sphere);
+
#endif /* S3DUT_H */
diff --git a/src/s3dut_mesh.h b/src/s3dut_mesh.h
@@ -25,7 +25,8 @@ enum s3dut_mesh_type {
S3DUT_MESH_CYLINDER,
S3DUT_MESH_THICK_CYLINDER,
S3DUT_MESH_HEMISPHERE,
- S3DUT_MESH_SPHERE
+ S3DUT_MESH_SPHERE,
+ S3DUT_MESH_THICK_SPHERE
};
struct s3dut_mesh {
diff --git a/src/s3dut_sphere.c b/src/s3dut_sphere.c
@@ -22,7 +22,7 @@
static res_T
setup_sphere_coords
(struct mem_allocator* allocator,
- double* coords,
+ double** coords_ptr,
const double radius,
const double z_range[2],
const unsigned nslices, /* # subdivisions around the Z axis */
@@ -30,15 +30,16 @@ setup_sphere_coords
const unsigned close_ends)
{
enum { SIN, COS };
+ double* coords;
struct darray_double sincos_theta;
struct darray_double sincos_phi;
double step_theta;
const int top_truncated = z_range && z_range[1] < +radius;
const int bottom_truncated = z_range && z_range[0] > -radius;
- const int nb_truncated = top_truncated + bottom_truncated;
+ const unsigned nb_truncated = top_truncated + bottom_truncated;
const int close_top = top_truncated && (close_ends & S3DUT_END_TOP);
const int close_bottom = bottom_truncated && (close_ends & S3DUT_END_BOTTOM);
- const int nrings = nstacks - 1 + nb_truncated;
+ const unsigned nrings = nstacks - 1 + nb_truncated;
const double phi_z_min
= bottom_truncated ? asin(CLAMP(z_range[0] / radius, -1, 1)) : -PI / 2;
const double phi_z_max
@@ -47,10 +48,11 @@ setup_sphere_coords
= (phi_z_max - phi_z_min) / (double)(nrings + 1 - nb_truncated);
size_t itheta;
size_t iphi;
- size_t i;
+ size_t i = 0;
res_T res = RES_OK;
- ASSERT(coords && radius > 0);
+ ASSERT(coords_ptr && *coords_ptr && radius > 0);
+ coords = *coords_ptr;
darray_double_init(allocator, &sincos_theta);
darray_double_init(allocator, &sincos_phi);
@@ -102,25 +104,29 @@ setup_sphere_coords
exit:
darray_double_release(&sincos_theta);
darray_double_release(&sincos_phi);
+ *coords_ptr = coords + i;
return res;
error:
goto exit;
}
-static void
+static size_t*
setup_sphere_indices
(size_t* ids,
+ const size_t offset,
const unsigned nslices, /* # subdivisions around the Z axis */
const unsigned nstacks, /* # subdivisions along the Z axis */
- const int top_truncated,
- const int bottom_truncated,
+ const double radius,
+ const double z_range[2],
const unsigned close_ends,
const int cw_out)
{
- const int nb_truncated = top_truncated + bottom_truncated;
+ const int top_truncated = z_range && z_range[1] < +radius;
+ const int bottom_truncated = z_range && z_range[0] > -radius;
+ const unsigned nb_truncated = top_truncated + bottom_truncated;
const int close_top = top_truncated && (close_ends & S3DUT_END_TOP);
const int close_bottom = bottom_truncated && (close_ends & S3DUT_END_BOTTOM);
- const int nrings = nstacks - 1 + nb_truncated;
+ const unsigned nrings = nstacks - 1 + nb_truncated;
size_t ibottom;
size_t itop;
size_t i, itheta, iphi;
@@ -129,8 +135,8 @@ setup_sphere_indices
/* Define the indices of the contour primitives */
i = 0;
FOR_EACH(itheta, 0, nslices) {
- const size_t itheta0 = itheta * nrings;
- const size_t itheta1 = ((itheta + 1) % nslices) * nrings;
+ const size_t itheta0 = offset + itheta * nrings;
+ const size_t itheta1 = offset + ((itheta + 1) % nslices) * nrings;
FOR_EACH(iphi, 0, nrings-1) {
const size_t iphi0 = iphi + 0;
const size_t iphi1 = iphi + 1;
@@ -149,12 +155,12 @@ setup_sphere_indices
/* Define the indices of the polar primitives */
FOR_EACH(itheta, 0, nslices) {
- const size_t itheta0 = itheta * nrings;
- const size_t itheta1 = ((itheta + 1) % nslices) * nrings;
+ const size_t itheta0 = offset + itheta * nrings;
+ const size_t itheta1 = offset + ((itheta + 1) % nslices) * nrings;
if(close_bottom || !bottom_truncated) {
ibottom = nslices * nrings;
- ids[i] = ibottom;
+ ids[i] = offset + ibottom;
ids[cw_out?i+1:i+2] = itheta0;
ids[cw_out?i+2:i+1] = itheta1;
i += 3;
@@ -163,12 +169,66 @@ setup_sphere_indices
if(close_top || !top_truncated) {
itop = (close_bottom || !bottom_truncated)
? nslices * nrings + 1 : nslices * nrings;
- ids[i] = itop;
+ ids[i] = offset + itop;
ids[cw_out?i+1:i+2] = itheta1 + (nrings - 1);
ids[cw_out?i+2:i+1] = itheta0 + (nrings - 1);
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 external_nrings,
+ const unsigned internal_nrings,
+ const int bottom)
+{
+ size_t islice;
+ size_t i = 0;
+ ASSERT(ids && nslices >= 3 && external_nrings >= 1 && internal_nrings >= 1);
+
+ FOR_EACH(islice, 0, nslices) {
+ ids[i] = fst_id_out + islice * external_nrings;
+ ids[bottom?i+1:i+2] = fst_id_in + ((islice+1) % nslices) * internal_nrings;
+ ids[bottom?i+2:i+1] = fst_id_in + islice * internal_nrings;
+ i += 3;
+
+ ids[i] = fst_id_out + islice * external_nrings;
+ ids[bottom?i+1:i+2] = fst_id_out + ((islice+1) % nslices) * external_nrings;
+ ids[bottom?i+2:i+1] = fst_id_in + ((islice+1) % nslices) * internal_nrings;
+ i += 3;
+ }
+ return ids + i;
+}
+
+static void
+sphere_accum_counts
+ (const double radius,
+ const unsigned nslices,
+ const unsigned nstacks,
+ const double z_range[2],
+ const unsigned close_ends,
+ unsigned* nrings,
+ size_t* ntris,
+ size_t* nverts)
+{
+ const int top_truncated = z_range && z_range[1] < +radius;
+ const int bottom_truncated = z_range && z_range[0] > -radius;
+ const unsigned nb_truncated = top_truncated + bottom_truncated;
+ const int close_top = top_truncated && (close_ends & S3DUT_END_TOP);
+ const int close_bottom = bottom_truncated && (close_ends & S3DUT_END_BOTTOM);
+ const unsigned nb_closed_ends = (close_top ? 1 : 0) + (close_bottom ? 1 : 0);
+ const unsigned nb_pole_vrtx = nb_closed_ends + (2 - nb_truncated);
+ ASSERT(z_range && nrings && ntris && nverts);
+ *nrings = nstacks - 1 + nb_truncated;;
+ *nverts += nslices*(*nrings) /* #contour verts*/ + nb_pole_vrtx; /*polar verts*/
+ *ntris += 2 * nslices * (*nrings -1) /* #contour tris */
+ + (2 - nb_truncated + nb_closed_ends) * nslices; /* #polar tris */
}
/*******************************************************************************
@@ -188,17 +248,17 @@ s3dut_create_sphere
res_T
s3dut_create_hemisphere
-(struct mem_allocator* allocator,
- const double radius,
- const unsigned nslices,
- const unsigned nstacks,
- struct s3dut_mesh** mesh)
+ (struct mem_allocator* allocator,
+ const double radius,
+ const unsigned nslices,
+ const unsigned nstacks,
+ struct s3dut_mesh** mesh)
{
double z_range[2];
z_range[0] = 0;
z_range[1] = +radius;
return s3dut_create_truncated_sphere
- (allocator, radius, nslices, nstacks, z_range, 0, mesh);
+ (allocator, radius, nslices, nstacks, z_range, 0, mesh);
}
res_T
@@ -214,16 +274,17 @@ s3dut_create_truncated_sphere
struct s3dut_mesh* sphere = NULL;
const int top_truncated = z_range && z_range[1] < +radius;
const int bottom_truncated = z_range && z_range[0] > -radius;
- const int nb_truncated = top_truncated + bottom_truncated;
+ const unsigned nb_truncated = top_truncated + bottom_truncated;
const int close_top = top_truncated && (close_ends & S3DUT_END_TOP);
const int close_bottom = bottom_truncated && (close_ends & S3DUT_END_BOTTOM);
- const int nb_closed_ends = (close_top ? 1 : 0) + (close_bottom ? 1 : 0);
- const int nb_pole_vrtx = nb_closed_ends + (2 - nb_truncated);
- const int nrings = nstacks - 1 + nb_truncated;
+ const unsigned nb_closed_ends = (close_top ? 1 : 0) + (close_bottom ? 1 : 0);
+ const unsigned nb_pole_vrtx = nb_closed_ends + (2 - nb_truncated);
+ const unsigned nrings = nstacks - 1 + nb_truncated;
const size_t nverts = nslices*nrings/* #contour verts*/
+ nb_pole_vrtx/*polar verts*/;
const size_t ntris = 2 * nslices*(nrings - 1)/* #contour tris*/
+ nb_pole_vrtx*nslices/* #polar tris*/;
+ double* coords;
res_T res = RES_OK;
ASSERT(0 <= nb_truncated && nb_truncated <= 2);
@@ -236,12 +297,13 @@ s3dut_create_truncated_sphere
res = mesh_create(allocator, S3DUT_MESH_SPHERE, nverts, ntris, &sphere);
if(res != RES_OK) goto error;
- res = setup_sphere_coords(allocator, darray_double_data_get(&sphere->coords),
- radius, z_range, nslices, nstacks, close_ends);
+ coords = darray_double_data_get(&sphere->coords);
+ res = setup_sphere_coords(allocator, &coords, radius, z_range, nslices,
+ nstacks, close_ends);
if(res != RES_OK) goto error;
- setup_sphere_indices(darray_size_t_data_get(&sphere->ids),
- nslices, nstacks, top_truncated, bottom_truncated, close_ends, 1);
+ setup_sphere_indices(darray_size_t_data_get(&sphere->ids), 0,
+ nslices, nstacks, radius, z_range, close_ends, 1);
exit:
if(mesh) *mesh = sphere;
@@ -253,3 +315,98 @@ error:
}
goto exit;
}
+
+res_T
+s3dut_create_thick_truncated_sphere
+ (struct mem_allocator* allocator,
+ const double radius,
+ const double thickness,
+ const unsigned nslices,
+ const unsigned nstacks,
+ const double z_range[2],
+ const unsigned c_e,
+ struct s3dut_mesh** mesh)
+{
+ struct s3dut_mesh* sphere = NULL;
+ unsigned close_ends = c_e;
+ double* coords = NULL;
+ double* prev_coords;
+ size_t* ids_out = NULL;
+ size_t* ids_in = NULL;
+ size_t* ids_walls = NULL;
+ size_t id_offset;
+ const double internal_radius = radius - thickness;
+ const int top_truncated = z_range && (z_range[1] < +radius);
+ const int bottom_truncated = z_range && (z_range[0] > -radius);
+ const int close_top = top_truncated && (close_ends & S3DUT_END_TOP);
+ const int close_bottom = bottom_truncated && (close_ends & S3DUT_END_BOTTOM);
+ const int top_seam = z_range && (z_range[1] < internal_radius) && !close_top;
+ const int bottom_seam
+ = z_range && (z_range[0] > -internal_radius) && ! close_bottom;
+ unsigned external_nrings;
+ unsigned internal_nrings;
+ const unsigned nb_seams = top_seam + bottom_seam;
+ size_t nverts = 0;
+ size_t ntris = 0;
+ double z_internal_range[2];
+ res_T res = RES_OK;
+
+ if(radius <= thickness || thickness <= 0 || nslices < 3 || nstacks < 2
+ || !mesh || (z_range && z_range[0] >= z_range[1])) {
+ return RES_BAD_ARG;
+ }
+
+ /* Special case when a single sphere is truncated */
+ if (top_truncated && (z_range[1] >= internal_radius)) {
+ close_ends |= S3DUT_END_TOP; /* close the external sphere's top end */
+ }
+ if (bottom_truncated && (z_range[0] <= -internal_radius)) {
+ close_ends |= S3DUT_END_BOTTOM; /* close the external sphere's bottom end */
+ }
+ z_internal_range[0]
+ = (bottom_truncated && !close_bottom) ? z_range[0] : z_range[0] + thickness;
+ z_internal_range[1]
+ = (top_truncated && !close_top) ? z_range[1] : z_range[1] - thickness;
+ sphere_accum_counts(radius, nslices, nstacks, z_range, close_ends,
+ &external_nrings, &ntris, &nverts);
+ sphere_accum_counts(radius-thickness, nslices, nstacks, z_internal_range,
+ close_ends, &internal_nrings, &ntris, &nverts);
+ ntris += 2 * nb_seams * nslices; /* # seam tris */
+ res = mesh_create(allocator, S3DUT_MESH_THICK_SPHERE, nverts, ntris, &sphere);
+ if (res != RES_OK) goto error;
+
+ coords = darray_double_data_get(&sphere->coords);
+ ids_out = darray_size_t_data_get(&sphere->ids);
+ /* External sphere */
+ prev_coords = coords;
+ setup_sphere_coords
+ (allocator, &coords, radius, z_range, nslices, nstacks, close_ends);
+ ids_in = setup_sphere_indices(ids_out, 0, nslices, nstacks, radius, z_range,
+ close_ends, 1);
+ /* Internal sphere */
+ id_offset = coords - prev_coords;
+ ASSERT(id_offset % 3 == 0);
+ id_offset /= 3;
+ setup_sphere_coords(allocator, &coords, radius - thickness, z_internal_range,
+ nslices, nstacks, close_ends);
+ ids_walls = setup_sphere_indices (ids_in, id_offset, nslices,
+ nstacks, radius - thickness, z_internal_range, close_ends, 0);
+ if(bottom_seam) {
+ ids_walls = close_wall(ids_walls, 0, id_offset, nslices, external_nrings,
+ internal_nrings, 1);
+ }
+ if(top_seam) {
+ ids_walls = close_wall(ids_walls, nstacks, id_offset + nstacks, nslices,
+ external_nrings, internal_nrings, 0);
+ }
+
+exit:
+ if(mesh) *mesh = sphere;
+ return res;
+error:
+ if(sphere) {
+ S3DUT(mesh_ref_put(sphere));
+ sphere = NULL;
+ }
+ goto exit;
+}
+\ No newline at end of file
diff --git a/src/test_s3dut_thick_truncated_sphere.c b/src/test_s3dut_thick_truncated_sphere.c
@@ -0,0 +1,53 @@
+/* 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"
+
+#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;
+ double z_range[2];
+ (void)argc, (void)argv;
+
+ CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK);
+
+ #define CR_TS s3dut_create_thick_truncated_sphere
+
+ z_range[0] = 0;
+ z_range[1] = 0.8;
+ CHECK(CR_TS(&allocator, 1, 0.1, 16, 8, z_range, S3DUT_END_BOTTOM, &msh), RES_OK);
+
+ CHECK(s3dut_mesh_get_data(msh, &data), RES_OK);
+ NCHECK(data.positions, NULL);
+ NCHECK(data.indices, NULL);
+ #undef CR_TS
+
+ 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;
+}
+