commit f55f1b6436f282848a2227b81558af7f4f220a98
parent 2e35463ed59d3d4c7babc0764786c602d66f3ed5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 12 Oct 2017 11:09:01 +0200
Add the s3dut_create_super_shape function
Diffstat:
5 files changed, 145 insertions(+), 10 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -45,7 +45,8 @@ set(S3DUT_FILES_SRC
s3dut_cuboid.c
s3dut_cylinder.c
s3dut_mesh.c
- s3dut_sphere.c)
+ s3dut_sphere.c
+ s3dut_super_shape.c)
set(S3DUT_FILES_INC s3dut_mesh.h)
set(S3DUT_FILES_INC_API s3dut.h)
set(S3DUT_FILES_DOC COPYING README.md)
diff --git a/src/s3dut.h b/src/s3dut.h
@@ -45,6 +45,18 @@ struct s3dut_mesh_data {
size_t nprimitives; /* # primitives */
};
+struct s3dut_super_formula {
+ double A;
+ double B;
+ double M;
+ double N0;
+ double N1;
+ double N2;
+};
+#define S3DUT_SUPER_FORMULA_NULL__ {0, 0, 0, 0, 0, 0}
+static const struct s3dut_super_formula S3DUT_SUPER_FORMULA_NULL =
+ S3DUT_SUPER_FORMULA_NULL__;
+
enum s3dut_cap_flag {
S3DUT_CAP_NEG_Z = BIT(0),
S3DUT_CAP_POS_Z = BIT(1)
@@ -190,4 +202,15 @@ s3dut_create_thick_truncated_sphere
const int cap_mask, /* Combination of s3dut_cap_flag. Ignored if no clamp */
struct s3dut_mesh** sphere);
+/* TODO comment */
+S3DUT_API res_T
+s3dut_create_super_shape
+ (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
+ const struct s3dut_super_formula* formula0,
+ const struct s3dut_super_formula* formula1,
+ const double radius, /* In [0, INF) */
+ const unsigned nslices, /* # subdivisions around Z axis in [3, INF) */
+ const unsigned nstacks, /* # subdivisions along Z axis in [2, INF) */
+ struct s3dut_mesh** super_shape);
+
#endif /* S3DUT_H */
diff --git a/src/s3dut_mesh.h b/src/s3dut_mesh.h
@@ -26,7 +26,8 @@ enum s3dut_mesh_type {
S3DUT_MESH_THICK_CYLINDER,
S3DUT_MESH_HEMISPHERE,
S3DUT_MESH_SPHERE,
- S3DUT_MESH_THICK_SPHERE
+ S3DUT_MESH_THICK_SPHERE,
+ S3DUT_MESH_SUPER_SHAPE
};
struct s3dut_mesh {
diff --git a/src/s3dut_sphere.c b/src/s3dut_sphere.c
@@ -258,18 +258,18 @@ s3dut_create_hemisphere
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
s3dut_create_truncated_sphere
-(struct mem_allocator* allocator,
- const double radius,
- const unsigned nslices,
- const unsigned nstacks,
- const double z_range[2],
- const int close_ends,
- struct s3dut_mesh** mesh)
+ (struct mem_allocator* allocator,
+ const double radius,
+ const unsigned nslices,
+ const unsigned nstacks,
+ const double z_range[2],
+ const int close_ends,
+ struct s3dut_mesh** mesh)
{
struct s3dut_mesh* sphere = NULL;
const int top_truncated = z_range && z_range[1] < +radius;
diff --git a/src/s3dut_super_shape.c b/src/s3dut_super_shape.c
@@ -0,0 +1,110 @@
+/* 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 "s3dut_mesh.h"
+
+#include <rsys/double3.h>
+#include <math.h>
+
+struct spherical {
+ double r;
+ double theta;
+ double phi;
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static FINLINE void
+cartesian_to_spherical(const double* xyz, struct spherical* spherical)
+{
+ ASSERT(spherical && xyz);
+ spherical->r = d3_dot(xyz, xyz);
+ spherical->theta = acos(xyz[2]/spherical->r);
+ spherical->phi = atan(xyz[1]/xyz[0]);
+}
+
+static FINLINE double
+super_formula_eval(const struct s3dut_super_formula* form, const double angle)
+{
+ double m, k, g;
+ ASSERT(form);
+ m = fabs(cos(form->M * angle / 4.0)) / form->A;
+ k = fabs(sin(form->M * angle / 4.0)) / form->B;
+ g = pow(m, form->N1) + pow(k, form->N2);
+ return pow(g, (-1.0/form->N0));
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+s3dut_create_super_shape
+ (struct mem_allocator* allocator,
+ const struct s3dut_super_formula* formula0,
+ const struct s3dut_super_formula* formula1,
+ const double radius,
+ const unsigned nslices,
+ const unsigned nstacks,
+ struct s3dut_mesh** mesh)
+{
+ struct s3dut_mesh* sshape = NULL;
+ size_t nverts;
+ size_t ivert;
+ res_T res = RES_OK;
+
+ if(radius<=0 || !formula0 || !formula1 || nslices<3 || nstacks<2 || !mesh) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = s3dut_create_sphere(allocator, radius, nslices, nstacks, &sshape);
+ if(res != RES_OK) goto error;
+
+ /* Positionned the sphere vertices wrt to the super formulas */
+ nverts = darray_double_size_get(&sshape->coords) / 3u;
+ FOR_EACH(ivert, 0, nverts) {
+ double* pos = darray_double_data_get(&sshape->coords) + ivert*3;
+ struct spherical spherical;
+ double uv[2];
+ double cos_theta, cos_phi;
+ double sin_theta, sin_phi;
+
+ cartesian_to_spherical(pos, &spherical);
+
+ uv[0] = super_formula_eval(formula0, spherical.theta);
+ uv[1] = super_formula_eval(formula1, spherical.phi);
+
+ cos_theta = cos(spherical.theta);
+ sin_theta = sin(spherical.theta);
+ cos_phi = cos(spherical.phi);
+ sin_phi = sin(spherical.phi);
+
+ pos[0] = uv[0] * cos_theta * uv[1] * cos_phi;
+ pos[1] = uv[0] * sin_theta * uv[1] * cos_phi;
+ pos[2] = uv[1] * sin_phi;
+ }
+
+ sshape->type = S3DUT_MESH_SUPER_SHAPE;
+
+exit:
+ if(mesh) *mesh = sshape;
+ return res;
+error:
+ if(sshape) { S3DUT(mesh_ref_put(sshape)); sshape = NULL; }
+ goto exit;
+}
+