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 }