star-3dut

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

s3dut_super_shape.c (4492B)


      1 /* Copyright (C) 2016, 2017, 2020, 2021, 2023 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "s3dut.h"
     17 #include "s3dut_mesh.h"
     18 
     19 #include <rsys/double2.h>
     20 #include <rsys/double3.h>
     21 #include <math.h>
     22 
     23 struct spherical {
     24   double r;
     25   double theta;
     26   double phi;
     27 };
     28 
     29 /*******************************************************************************
     30  * Helper functions
     31  ******************************************************************************/
     32 static FINLINE void
     33 cartesian_to_spherical(const double* xyz, struct spherical* spherical)
     34 {
     35   ASSERT(spherical && xyz);
     36   spherical->r = d3_len(xyz);
     37   spherical->phi = asin(xyz[2]/spherical->r);
     38   /* Map the atan results in [-PI, PI] to ensure that theta lies in [-PI,2PI]
     39    * rather than [-PI/2, 3PI/2] that would violate the super formula
     40    * constraints */
     41   spherical->theta = xyz[0] == 0 ? PI/2 : atan(xyz[1]/xyz[0]) - PI/2;
     42   if(xyz[0] < 0) spherical->theta += PI;
     43 }
     44 
     45 static FINLINE double
     46 super_formula_eval(const struct s3dut_super_formula* form, const double angle)
     47 {
     48   double m, k, g;
     49   ASSERT(form);
     50   m = fabs(cos(form->M * angle / 4.0)) / form->A;
     51   k = fabs(sin(form->M * angle / 4.0)) / form->B;
     52   g = pow(m, form->N1) + pow(k, form->N2);
     53   return pow(g, (-1.0/form->N0));
     54 }
     55 
     56 /*******************************************************************************
     57  * Exported functions
     58  ******************************************************************************/
     59 res_T
     60 s3dut_create_super_shape
     61   (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
     62    const struct s3dut_super_formula* formula0,
     63    const struct s3dut_super_formula* formula1,
     64    const double radius, /* In [0, INF) */
     65    const unsigned nslices, /* # subdivisions around Z axis in [3, INF) */
     66    const unsigned nstacks, /* # subdivisions along Z axis in [2, INF) */
     67    struct s3dut_mesh** super_shape)
     68 {
     69   return s3dut_create_thick_truncated_super_shape(allocator, formula0,
     70     formula1, radius, 0, nslices, nstacks, NULL, 0, super_shape);
     71 }
     72 
     73 res_T
     74 s3dut_create_thick_truncated_super_shape
     75   (struct mem_allocator* allocator,
     76    const struct s3dut_super_formula* formula0,
     77    const struct s3dut_super_formula* formula1,
     78    const double radius,
     79    const double thickness,
     80    const unsigned nslices,
     81    const unsigned nstacks,
     82    const double z_range[2],
     83    const int cap_mask,
     84    struct s3dut_mesh** mesh)
     85 {
     86   struct s3dut_mesh* sshape = NULL;
     87   size_t nverts;
     88   size_t ivert;
     89   res_T res = RES_OK;
     90 
     91   if(!formula0 || !formula1 || !mesh) {
     92     res = RES_BAD_ARG;
     93     goto error;
     94   }
     95 
     96   if(thickness == 0) {
     97     res = s3dut_create_truncated_sphere(allocator, radius, nslices, nstacks,
     98       z_range, cap_mask, &sshape);
     99   } else {
    100     res = s3dut_create_thick_truncated_sphere(allocator, radius, thickness,
    101       nslices, nstacks, z_range, cap_mask, &sshape);
    102   }
    103   if(res != RES_OK) goto error;
    104 
    105   /* Positioned the sphere vertices wrt to the super formulas */
    106   nverts = darray_double_size_get(&sshape->coords) / 3u;
    107   FOR_EACH(ivert, 0, nverts) {
    108     double* pos = darray_double_data_get(&sshape->coords) + ivert*3;
    109     struct spherical spherical;
    110     double uv[2];
    111     double cos_theta, cos_phi;
    112     double sin_theta, sin_phi;
    113 
    114     cartesian_to_spherical(pos, &spherical);
    115 
    116     uv[0] = super_formula_eval(formula0, spherical.theta);
    117     uv[1] = super_formula_eval(formula1, spherical.phi);
    118 
    119     cos_theta = cos(spherical.theta);
    120     sin_theta = sin(spherical.theta);
    121     cos_phi = cos(spherical.phi);
    122     sin_phi = sin(spherical.phi);
    123 
    124     pos[0] = uv[0] * cos_theta * uv[1] * cos_phi * spherical.r;
    125     pos[1] = uv[0] * sin_theta * uv[1] * cos_phi * spherical.r;
    126     pos[2] = uv[1] * sin_phi * spherical.r;
    127   }
    128 
    129   sshape->type = S3DUT_MESH_SUPER_SHAPE;
    130 
    131 exit:
    132   if(mesh) *mesh = sshape;
    133   return res;
    134 error:
    135   if(sshape) { S3DUT(mesh_ref_put(sshape)); sshape = NULL; }
    136   goto exit;
    137 }
    138