star-mesh

Define and load a binary data format for meshes
git clone git://git.meso-star.fr/star-mesh.git
Log | Files | Refs | README | LICENSE

smsh2vtk.c (8069B)


      1 /* Copyright (C) 2020-2023, 2025 |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 #define _POSIX_C_SOURCE 200112L /* getopt support */
     17 
     18 #include "smsh.h"
     19 
     20 #include <rsys/cstr.h>
     21 #include <rsys/mem_allocator.h>
     22 #include <rsys/text_reader.h>
     23 
     24 #include <errno.h>
     25 #include <string.h> /* strerror */
     26 #include <unistd.h> /* getopt */
     27 
     28 /* Input arguments */
     29 struct args {
     30   const char* mesh; /* Tetrahedral mesh */
     31   const char* output; /* Output file */
     32 };
     33 static const struct args ARGS_DEFAULT = {0};
     34 
     35 /* Command data */
     36 struct cmd {
     37   struct smsh* mesh; /* Tetrahedral mesh */
     38   FILE* output; /* Ouput file */
     39 };
     40 static const struct cmd CMD_NULL = {0};
     41 
     42 /*******************************************************************************
     43  * Helper functions
     44  ******************************************************************************/
     45 static INLINE void
     46 usage(FILE* stream)
     47 {
     48   fprintf(stream,
     49     "usage: smsh2vtk [-o output] mesh\n");
     50 }
     51 
     52 static void
     53 args_release(struct args* args)
     54 {
     55   ASSERT(args);
     56   *args = ARGS_DEFAULT;
     57 }
     58 
     59 static res_T
     60 args_init(struct args* args, const int argc, char** argv)
     61 {
     62   int opt = 0;
     63   res_T res = RES_OK;
     64 
     65   *args = ARGS_DEFAULT;
     66 
     67   while((opt = getopt(argc, argv, "o:")) != -1) {
     68     switch(opt) {
     69       case 'o': args->output = optarg; break;
     70       default: res = RES_BAD_ARG;
     71     }
     72     if(res != RES_OK) goto error;
     73   }
     74 
     75   if(optind < argc) args->mesh = argv[optind];
     76 
     77   if(!args->mesh) {
     78     fprintf(stderr, "mesh is missing\n");
     79     res = RES_BAD_ARG;
     80     goto error;
     81   }
     82 
     83 exit:
     84   return res;
     85 error:
     86   usage(stderr);
     87   args_release(args);
     88   goto exit;
     89 }
     90 
     91 static res_T
     92 check_mem_leaks(void)
     93 {
     94   char buffer[128] = {0};
     95   size_t sz = 0;
     96 
     97   if((sz = mem_allocated_size()) == 0)
     98     return RES_OK; /* No memory leak */
     99 
    100   size_to_cstr(sz, SIZE_ALL, NULL, buffer, sizeof(buffer));
    101   fprintf(stderr, "memory leaks: %s\n", buffer);
    102   return RES_MEM_ERR;
    103 }
    104 
    105 static res_T
    106 write_vtk_header(struct cmd* cmd)
    107 {
    108   res_T res = RES_OK;
    109   ASSERT(cmd);
    110 
    111   #define FPRINTF(Msg) \
    112     { if(fprintf(cmd->output, Msg) < 0) goto error; } (void)0
    113   FPRINTF("# vtk DataFile Version 2.0\n");
    114   FPRINTF("Volumic mesh\n");
    115   FPRINTF("ASCII\n");
    116   #undef FPRINTF
    117 
    118 exit:
    119   return res;
    120 error:
    121   fprintf(stderr, "header write error -- %s\n", strerror(errno));
    122   res = RES_IO_ERR;
    123   goto exit;
    124 }
    125 
    126 static INLINE int
    127 write_nodes(FILE* stream, const struct smsh_desc* desc)
    128 {
    129   int err = 0;
    130   size_t i = 0;
    131   ASSERT(stream && desc && desc->dnode == 3);
    132 
    133   #define FPRINTF(...) \
    134     { if(fprintf(stream, __VA_ARGS__) < 0) goto error; } (void)0
    135   /* Vertices */
    136   FPRINTF("POINTS %zu double\n", desc->nnodes);
    137   FOR_EACH(i, 0, desc->nnodes) FPRINTF("%f %f %f\n", SPLIT3(desc->nodes+i*3));
    138   #undef FPRINTF
    139 
    140 exit:
    141   return err;
    142 error:
    143   err = errno;
    144   goto exit;
    145 }
    146 
    147 static res_T
    148 write_tetrahedra(FILE* stream, const struct smsh_desc* desc)
    149 {
    150   size_t i = 0;
    151   int err = 0;
    152 
    153   ASSERT(stream && desc && desc->dnode == 3 && desc->dcell == 4);
    154 
    155   #define FPRINTF(...) { \
    156     if(fprintf(stream, __VA_ARGS__) < 0) { err = errno; goto error; } \
    157   } (void)0
    158 
    159   FPRINTF("DATASET UNSTRUCTURED_GRID\n");
    160 
    161   /* Vertices */
    162   if((err = write_nodes(stream, desc))) goto error;
    163 
    164   /* Cells */
    165   FPRINTF("CELLS %zu %zu\n", desc->ncells, desc->ncells*(4+1));
    166   FOR_EACH(i, 0, desc->ncells) {
    167     FPRINTF("4 %zu %zu %zu %zu\n", SPLIT4(desc->cells+i*4));
    168   }
    169 
    170   /* Cell types (VTK_TETRA == 10) */
    171   FPRINTF("CELL_TYPES %zu\n", desc->ncells);
    172   FOR_EACH(i, 0, desc->ncells) FPRINTF("10\n");
    173 
    174   #undef FPRINTF
    175 
    176 exit:
    177   return err;
    178 error:
    179   goto exit;
    180 }
    181 
    182 static res_T
    183 write_triangles(FILE* stream, const struct smsh_desc* desc)
    184 {
    185   size_t i = 0;
    186   int err = 0;
    187 
    188   ASSERT(stream && desc && desc->dnode == 3 && desc->dcell == 3);
    189 
    190   #define FPRINTF(...) { \
    191     if(fprintf(stream, __VA_ARGS__) < 0) { err = errno; goto error; } \
    192   } (void)0
    193 
    194   FPRINTF("DATASET POLYDATA\n");
    195 
    196   /* Vertices */
    197   if((err == write_nodes(stream, desc))) goto error;
    198 
    199   /* Triangles */
    200   FPRINTF("POLYGONS %zu %zu\n", desc->ncells, desc->ncells*(3+1));
    201   FOR_EACH(i, 0, desc->ncells) {
    202     FPRINTF("3 %zu %zu %zu\n", SPLIT3(desc->cells+i*3));
    203   }
    204 
    205   #undef FPRINTF
    206 
    207 exit:
    208   return err;
    209 error:
    210   goto exit;
    211 }
    212 
    213 static int
    214 write_mesh(struct cmd* cmd)
    215 {
    216   struct smsh_desc desc = SMSH_DESC_NULL;
    217   int err = 0;
    218   res_T res = RES_OK;
    219   ASSERT(cmd);
    220 
    221   SMSH(get_desc(cmd->mesh, &desc));
    222 
    223   switch(desc.dcell) {
    224     case 3: err = write_triangles(cmd->output, &desc); break;
    225     case 4: err = write_tetrahedra(cmd->output, &desc); break;
    226     default: FATAL("Unreachable code\n");
    227   }
    228   if(err != 0) goto error;
    229 
    230 exit:
    231   return res;
    232 error:
    233   fprintf(stderr, "mesh write error -- %s\n", strerror(err));
    234   res = RES_IO_ERR;
    235   goto exit;
    236 }
    237 
    238 static res_T
    239 setup_mesh(struct cmd* cmd, const struct args* args)
    240 {
    241   struct smsh_create_args create_args = SMSH_CREATE_ARGS_DEFAULT;
    242   struct smsh_load_args load_args = SMSH_LOAD_ARGS_NULL;
    243   struct smsh_desc desc = SMSH_DESC_NULL;
    244   res_T res = RES_OK;
    245   ASSERT(cmd && args);
    246 
    247   create_args.verbose = 1;
    248   if((res = smsh_create(&create_args, &cmd->mesh)) != RES_OK) goto error;
    249 
    250   load_args.path = args->mesh;
    251   if((res = smsh_load(cmd->mesh, &load_args)) != RES_OK) goto error;
    252 
    253   if((res = smsh_get_desc(cmd->mesh, &desc)) != RES_OK) goto error;
    254 
    255   if(desc.dnode != 3 || (desc.dcell != 3 && desc.dcell != 4)) {
    256     fprintf(stderr,
    257       "expecting a tetrahedral mesh or a triangle mesh "
    258       "-- dcell = %u, dnode = %u\n",
    259       desc.dcell, desc.dnode);
    260     res = RES_BAD_ARG;
    261     goto error;
    262   }
    263 
    264 exit:
    265   return res;
    266 error:
    267   if(cmd->mesh) { SMSH(ref_put(cmd->mesh)); cmd->mesh = NULL; }
    268   goto exit;
    269 }
    270 
    271 static res_T
    272 setup_output(struct cmd* cmd, const struct args* args)
    273 {
    274   res_T res = RES_OK;
    275   ASSERT(cmd && args);
    276 
    277   if(!args->output) {
    278     cmd->output = stdout;
    279   } else if((cmd->output = fopen(args->output, "w")) == NULL) {
    280     fprintf(stderr, "error opening output file '%s' -- %s\n",
    281       args->output, strerror(errno));
    282     res = RES_IO_ERR;
    283     goto error;
    284   }
    285 
    286 exit:
    287   return res;
    288 error:
    289   if(cmd->output) { CHK(fclose(cmd->output) == 0); cmd->output = NULL; }
    290   goto exit;
    291 }
    292 
    293 static void
    294 cmd_release(struct cmd* cmd)
    295 {
    296   ASSERT(cmd);
    297   if(cmd->mesh) SMSH(ref_put(cmd->mesh));
    298   if(cmd->output && cmd->output != stdout) CHK(fclose(cmd->output) == 0);
    299 }
    300 
    301 static res_T
    302 cmd_init(struct cmd* cmd, const struct args* args)
    303 {
    304   res_T res = RES_OK;
    305   ASSERT(cmd && args);
    306 
    307   if((res = setup_mesh(cmd, args)) != RES_OK) goto error;
    308   if((res = setup_output(cmd, args)) != RES_OK) goto error;
    309 
    310 exit:
    311   return res;
    312 error:
    313   cmd_release(cmd);
    314   goto exit;
    315 }
    316 
    317 static res_T
    318 cmd_run(struct cmd* cmd)
    319 {
    320   res_T res = RES_OK;
    321   ASSERT(cmd);
    322 
    323   if((res = write_vtk_header(cmd)) != RES_OK) goto error;
    324   if((res = write_mesh(cmd)) != RES_OK) goto error;
    325 
    326 exit:
    327   return res;
    328 error:
    329   goto exit;
    330 }
    331 
    332 /*******************************************************************************
    333  * The program
    334  ******************************************************************************/
    335 int
    336 main(int argc, char** argv)
    337 {
    338   struct args args = ARGS_DEFAULT;
    339   struct cmd cmd = CMD_NULL;
    340   int err = 0;
    341   res_T res = RES_OK;
    342 
    343   if((res = args_init(&args, argc, argv)) != RES_OK) goto error;
    344   if((res = cmd_init(&cmd, &args)) != RES_OK) goto error;
    345   if((res = cmd_run(&cmd)) != RES_OK) goto error;
    346 
    347 exit:
    348   args_release(&args);
    349   cmd_release(&cmd);
    350   if((res = check_mem_leaks()) != RES_OK && !err) err = 1;
    351   return err;
    352 error:
    353   err = 1;
    354   goto exit;
    355 }