star-phor-input

File format for describing photoreactor configurations
git clone https://www.edstar.cnrs.fr/git/star-phor-input.git
Log | Files | Refs | README | LICENSE

sphin_geometry.c (9351B)


      1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique
      2  * Copyright (C) 2024-2026 Clermont Auvergne INP
      3  * Copyright (C) 2024-2026 INSA Lyon
      4  * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux
      5  * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse
      6  * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com)
      7  * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com)
      8  * Copyright (C) 2024-2026 Université de Lorraine
      9  * Copyright (C) 2024-2026 Université Paul Sabatier
     10  * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès
     11  *
     12  * This program is free software: you can redistribute it and/or modify
     13  * it under the terms of the GNU General Public License as published by
     14  * the Free Software Foundation, either version 3 of the License, or
     15  * (at your option) any later version.
     16  *
     17  * This program is distributed in the hope that it will be useful,
     18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     20  * GNU General Public License for more details.
     21  *
     22  * You should have received a copy of the GNU General Public License
     23  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     24 #define _POSIX_C_SOURCE 200112L /* for strtok_r support */
     25 
     26 #include "sphin_c.h"
     27 #include "sphin_geometry.h"
     28 
     29 #include <rsys/cstr.h>
     30 #include <rsys/double3.h>
     31 #include <rsys/mem_allocator.h>
     32 #include <rsys/ref_count.h>
     33 #include <rsys/rsys.h>
     34 #include <star/sstl.h>
     35 
     36 /*******************************************************************************
     37  * Helper functions
     38  ******************************************************************************/
     39 static void
     40 release_geometry
     41   (ref_T* address)
     42 {
     43   struct sphin_geometry* geometry = NULL;
     44   struct sphin* sphin = NULL;
     45 
     46   ASSERT(NULL != address);
     47 
     48   geometry = CONTAINER_OF(address, struct sphin_geometry, ref);
     49   str_release(&geometry->stl_filename);
     50   darray_double_release(&geometry->coords);
     51   darray_size_t_release(&geometry->indices);
     52   sphin = geometry->sphin;
     53   MEM_RM(sphin->allocator, geometry);
     54   SPHIN(ref_put(sphin));
     55 }
     56 
     57 static res_T
     58 geometry_create
     59   (struct sphin* sphin,
     60    const char* stl_filename,
     61    struct sphin_geometry** out_geometry)
     62 {
     63   struct sphin_geometry* geom = NULL;
     64   res_T res = RES_OK;
     65 
     66   ASSERT(NULL != sphin);
     67   ASSERT(NULL != out_geometry);
     68   ASSERT(NULL != stl_filename);
     69   ASSERT('\0' != stl_filename[0]); /* Name can't be empty */
     70 
     71   geom = MEM_CALLOC(sphin->allocator, 1, sizeof(struct sphin_geometry));
     72   if (NULL == geom) { res = RES_MEM_ERR; goto error; }
     73 
     74   /* Init geometry ref counter and init member variables */
     75   ref_init(&geom->ref);
     76   SPHIN(ref_get(sphin));
     77   geom->sphin = sphin;
     78   darray_double_init(sphin->allocator, &geom->coords);
     79   darray_size_t_init(sphin->allocator, &geom->indices);
     80 
     81   str_init(sphin->allocator, &geom->stl_filename);
     82   res = str_set(&geom->stl_filename, stl_filename);
     83   if (RES_OK != res) { goto error; }
     84 
     85 exit:
     86   *out_geometry = geom;
     87   return res;
     88 error:
     89   if (NULL != geom) {
     90     SPHIN(geometry_ref_put(geom));
     91     geom = NULL;
     92   }
     93   goto exit;
     94 }
     95 
     96 /*******************************************************************************
     97  * Local functions
     98  ******************************************************************************/
     99 double
    100 geometry_compute_area
    101   (const struct sphin_geometry* geom)
    102 {
    103   const double* pos = NULL;
    104   const size_t* ids = NULL;
    105   double area = 0.0;
    106   size_t id, itri, tri_count;
    107 
    108   ASSERT(NULL != geom);
    109 
    110   pos = darray_double_cdata_get(&geom->coords);
    111   ids = darray_size_t_cdata_get(&geom->indices);
    112   tri_count = darray_size_t_size_get(&geom->indices)/3;
    113   if (0 == tri_count) return 0.;
    114 
    115   FOR_EACH(itri, 0, tri_count) {
    116     /* Retrieve vertex coordinates */
    117     id = itri * 3; /*#ids per vertex*/
    118     const double* v0 = pos + ids[id+0]*3;
    119     const double* v1 = pos + ids[id+1]*3;
    120     const double* v2 = pos + ids[id+2]*3;
    121     double E0[3], E1[3], N[3];
    122 
    123     /* Construct vectors defining the triangle vertices */
    124     d3_sub(E0, v1, v0);
    125     d3_sub(E1, v2, v0);
    126 
    127     /* Increment total area */
    128     area += d3_len(d3_cross(N, E0, E1));
    129   }
    130   return area * 0.5f;
    131 }
    132 
    133 double
    134 geometry_compute_volume
    135   (const struct sphin_geometry* geom,
    136    const enum sphin_side side)
    137 {
    138   const double* pos = NULL;
    139   const size_t* ids = NULL;
    140   double volume = 0.0;
    141   size_t id, itri, tri_count;
    142 
    143   pos = darray_double_cdata_get(&geom->coords);
    144   ids = darray_size_t_cdata_get(&geom->indices);
    145   tri_count = darray_size_t_size_get(&geom->indices)/3;
    146   if (0 == tri_count) return 0.;
    147 
    148   FOR_EACH(itri, 0, tri_count) {
    149     /* Retrieve vertex coordinates */
    150     id = itri * 3; /*#ids per vertex*/
    151     const double* v0 = pos + ids[id+0]*3;
    152     const double* v1 = pos + ids[id+1]*3;
    153     const double* v2 = pos + ids[id+2]*3;
    154     double E0[3], E1[3], N[3];
    155     double b, h;
    156 
    157     /* Construct vectors defining the triangle vertices */
    158     d3_sub(E0, v1, v0);
    159     d3_sub(E1, v2, v0);
    160 
    161     /* Compute triangle normal */
    162     if (SPHIN_SIDE_BACK == side) {
    163       d3_cross(N, E1, E0);
    164     } else {
    165       d3_cross(N, E0, E1);
    166     }
    167     b = d3_normalize(N, N); /* Base area */
    168     h = -d3_dot(N, v0); /* Height from the base to the apex */
    169 
    170     volume += (h*b);
    171   }
    172   return volume / 6.0;
    173 
    174 }
    175 
    176 res_T
    177 geometry_parse
    178   (struct sphin* sphin,
    179    char* value,
    180    struct sphin_geometry** out_geom)
    181 {
    182   size_t i;
    183   char* side = NULL;
    184   char* filename = NULL;
    185   char* token_ptr = NULL;
    186   char* unit = NULL;
    187   struct sphin_geometry* geom = NULL;
    188   struct sstl* sstl = NULL;
    189   struct sstl_desc sstl_desc;
    190   double* coords = NULL;
    191   double scaling_factor;
    192   size_t* indices = NULL;
    193   res_T res = RES_OK;
    194 
    195   ASSERT(NULL != sphin);
    196   ASSERT(NULL != out_geom);
    197 
    198   if (NULL == value) { res = RES_BAD_ARG; goto error; }
    199 
    200   /* Create the SSTL device using the same allocator and logger as the sphin
    201    * handler. We intentionally instantiate and free the SSTL struct for
    202    * each geometry, rather than creating it once at the sphin_config level.
    203    * We argue that the performance loss caused by this strategy is marginal
    204    * compared to the advantage of keeping the effects of this structure
    205    * encapsulated to the scope of this function. */
    206   res = sstl_create(sphin->logger, sphin->allocator, sphin->verbose, &sstl);
    207   if (RES_OK != res) { goto error; }
    208 
    209   /* Parse side */
    210   side = strtok_r(value, " \t", &token_ptr);
    211   if (NULL == side){ res = RES_BAD_ARG; goto error; }
    212 
    213   /* Parse filename */
    214   filename = strtok_r(NULL, " \t", &token_ptr);
    215   if (NULL == filename){ res = RES_BAD_ARG; goto error; }
    216 
    217   /* Parse unit and evaluate scaling factor*/
    218   unit = strtok_r(NULL, " \t", &token_ptr);
    219   if (NULL == unit
    220          || 0 == strcmp(unit, "m")){scaling_factor = 1e+00;}
    221   else if (0 == strcmp(unit, "cm")){scaling_factor = 1e-02;}
    222   else if (0 == strcmp(unit, "mm")){scaling_factor = 1e-03;}
    223   else if (0 == strcmp(unit, "km")){scaling_factor = 1e+03;}
    224   else { res = RES_BAD_ARG; goto error; }
    225 
    226   /* Create geometry */
    227   res = geometry_create(sphin, filename, &geom);
    228   if (RES_OK != res) { goto error; }
    229 
    230   if (0 == strcmp(side, "FRONT")){ geom->side = SPHIN_SIDE_FRONT; }
    231   else if (0 == strcmp(side, "BACK")){ geom->side = SPHIN_SIDE_BACK; }
    232   else { res = RES_BAD_ARG; goto error; }
    233 
    234   /* Load the stl */
    235   res = sstl_load(sstl, filename);
    236   if (RES_OK != res) { goto error; }
    237   res = sstl_get_desc(sstl, &sstl_desc);
    238   if (RES_OK != res) { goto error; }
    239 
    240   /* Parse coordinates and indices */
    241   darray_double_resize(&geom->coords, sstl_desc.vertices_count*3);
    242   darray_size_t_resize(&geom->indices, sstl_desc.triangles_count*3);
    243   coords = darray_double_data_get(&geom->coords);
    244   indices = darray_size_t_data_get(&geom->indices);
    245 
    246   FOR_EACH(i, 0, sstl_desc.vertices_count*3) {
    247     coords[i] = (double)sstl_desc.vertices[i]*scaling_factor;
    248   }
    249   FOR_EACH(i, 0, sstl_desc.triangles_count*3) {
    250     indices[i] = (size_t)sstl_desc.indices[i];
    251   }
    252 
    253 exit:
    254   sstl_ref_put(sstl);
    255   *out_geom = geom;
    256   return res;
    257 error:
    258   if (NULL != geom) {
    259     SPHIN(geometry_ref_put(geom));
    260     geom = NULL;
    261   }
    262   goto exit;
    263 }
    264 
    265 /*******************************************************************************
    266  * Exported functions
    267  ******************************************************************************/
    268 res_T
    269 sphin_geometry_ref_get
    270   (struct sphin_geometry* geometry)
    271 {
    272   if (NULL == geometry) {
    273     return RES_BAD_ARG;
    274   }
    275   ref_get(&geometry->ref);
    276   return RES_OK;
    277 }
    278 
    279 res_T
    280 sphin_geometry_ref_put
    281   (struct sphin_geometry* geometry)
    282 {
    283   if (NULL == geometry) {
    284     return RES_BAD_ARG;
    285   }
    286   ref_put(&geometry->ref, release_geometry);
    287   return RES_OK;
    288 }
    289 
    290 res_T
    291 sphin_geometry_get_desc
    292   (const struct sphin_geometry* geometry,
    293    struct sphin_geometry_descriptor* desc)
    294 {
    295   char* filename = NULL;
    296   struct sphin_mesh mesh = SPHIN_MESH_NULL;
    297 
    298   if (NULL == geometry || NULL == desc) {
    299     return RES_BAD_ARG;
    300   }
    301 
    302   mesh.coords = darray_double_data_get
    303     ((struct darray_double*)&geometry->coords);
    304   mesh.indices = darray_size_t_data_get
    305     ((struct darray_size_t*)&geometry->indices);
    306   mesh.vertex_count = darray_double_size_get(&geometry->coords) / 3;
    307   mesh.triangle_count = darray_size_t_size_get(&geometry->indices) / 3;
    308 
    309   filename = (char*)str_get((struct str*)&geometry->stl_filename);
    310   desc->filename = filename;
    311   desc->side = geometry->side;
    312   desc->mesh = mesh;
    313 
    314   return RES_OK;
    315 }