scad_device.c (21326B)
1 /* Copyright (C) 2022-2024 |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 "rsys/str.h" 17 #include "scad.h" 18 #include "scad_c.h" 19 #include "scad_device.h" 20 #include "scad_geometry.h" 21 22 #include <rsys/logger.h> 23 #include <rsys/mem_allocator.h> 24 #include <rsys/ref_count.h> 25 #include <rsys/cstr.h> 26 27 #include <gmsh/gmshc.h> 28 #include <rsys/rsys.h> 29 30 /******************************************************************************* 31 * The unique device in scad-cad 32 ******************************************************************************/ 33 static struct scad_device* g_device = NULL; 34 35 /******************************************************************************* 36 * Local functions 37 ******************************************************************************/ 38 static res_T 39 device_release(void) 40 { 41 res_T res = RES_OK; 42 int log, empty; 43 enum scad_log_refcounting option_ref; 44 int option_dec; 45 enum log_type log_type; 46 struct mem_allocator* allocator; 47 48 ASSERT(g_device); 49 50 allocator = g_device->allocator; 51 option_ref = g_device->options.Misc.LogRefCounting; 52 option_dec = g_device->options.Misc.DebugEmptyContext; 53 empty = htable_geometries_is_empty(&g_device->allgeom); 54 log_type = empty ? LOG_OUTPUT : LOG_WARNING; 55 log = (option_ref & SCAD_LOG_DIMTAGS_ALL) 56 || (!empty && (option_ref & SCAD_LOG_DIMTAGS_ONLY_UNDELETED)); 57 g_device->log = log; 58 g_device->log_type = log_type; 59 60 if(empty) { 61 if(log) logger_print(g_device->logger, log_type, "No scad geometry.\n"); 62 } else { 63 struct htable_geometries tmp; 64 struct htable_geometries_iterator it, end; 65 /* Duplicate the htable we iterate on as dev->allgeom will be altered during 66 * the process (through calls to geometry_release) */ 67 htable_geometries_init(allocator, &tmp); 68 CHK(RES_OK == htable_geometries_copy(&tmp, &g_device->allgeom)); 69 htable_geometries_begin(&tmp, &it); 70 htable_geometries_end(&tmp, &end); 71 while(!htable_geometries_iterator_eq(&it, &end)) { 72 struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it); 73 long cpt = geom->ref; 74 while(cpt-- > 0) { 75 SCAD(geometry_ref_put(geom)); 76 } 77 htable_geometries_iterator_next(&it); 78 } 79 htable_geometries_release(&tmp); 80 } 81 htable_names_release(&g_device->geometry_names); 82 htable_geometries_release(&g_device->allgeom); 83 htable_tags2desc_release(g_device->tags2desc); 84 htable_tags2desc_release(g_device->tags2desc+1); 85 htable_size_modifiers_release(&g_device->size_modifiers_by_dim[0]); 86 htable_size_modifiers_release(&g_device->size_modifiers_by_dim[1]); 87 htable_size_modifiers_release(&g_device->size_modifiers_by_dim[2]); 88 htable_size_modifiers_release(&g_device->size_modifiers_by_dim[3]); 89 if(log) { 90 logger_print(g_device->logger, log_type, "End finalizing scad.\n"); 91 } 92 93 if(option_dec) { 94 /* After releasing all star-cad stuff, gmsh and OCC contexts must be empty */ 95 res = check_empty_gmsh_occ(g_device); 96 } 97 98 MEM_RM(allocator, g_device); 99 g_device = NULL; 100 101 return res; 102 } 103 104 void 105 log_error(struct scad_device* dev, const char* msg, ...) 106 { 107 va_list vargs_list; 108 ASSERT(dev && msg); 109 if(dev->verbose < 1) return; 110 va_start(vargs_list, msg); 111 log_msg(dev, LOG_ERROR, msg, vargs_list); 112 va_end(vargs_list); 113 } 114 115 void 116 log_warning(struct scad_device* dev, const char* msg, ...) 117 { 118 va_list vargs_list; 119 ASSERT(dev && msg); 120 if(dev->verbose < 2) return; 121 va_start(vargs_list, msg); 122 log_msg(dev, LOG_WARNING, msg, vargs_list); 123 va_end(vargs_list); 124 } 125 126 127 void 128 log_message(struct scad_device* dev, const char* msg, ...) 129 { 130 va_list vargs_list; 131 ASSERT(dev && msg); 132 if(dev->verbose < 3) return; 133 va_start(vargs_list, msg); 134 log_msg(dev, LOG_OUTPUT, msg, vargs_list); 135 va_end(vargs_list); 136 } 137 138 /******************************************************************************* 139 * Exported scad_device functions 140 ******************************************************************************/ 141 res_T 142 check_device 143 (const char* function_name) 144 { 145 res_T res = RES_OK; 146 ASSERT(function_name); 147 148 if(!g_device) { 149 /* No logger available for a message */ 150 fprintf(stderr, 151 "%s: cannot call API functions if star-cad is not initialized.\n", 152 function_name); 153 res = RES_BAD_ARG; 154 goto error; 155 } 156 157 if(g_device->options.Misc.RunUIAtEachStep) { 158 ERR(scad_run_ui()); 159 } 160 161 if(g_device->options.Misc.DebugEmptyContext 162 && htable_geometries_size_get(&g_device->allgeom) == 0) 163 { 164 ERR(check_empty_gmsh_occ(g_device)); 165 } 166 167 exit: 168 return res; 169 error: 170 goto exit; 171 } 172 173 res_T 174 sync_device(void) 175 { 176 res_T res = RES_OK; 177 178 if(g_device->need_synchro) { 179 ERR(scad_synchronize()); /* Reset need_synchro according to options */ 180 } 181 182 exit: 183 return res; 184 error: 185 goto exit; 186 } 187 188 struct scad_device* 189 get_device 190 (void) 191 { 192 return g_device; 193 } 194 195 res_T 196 device_register_tags 197 (struct scad_geometry* geom) 198 { 199 res_T res = RES_OK; 200 struct scad_device* dev = get_device(); 201 int log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL); 202 203 ASSERT(geom); 204 205 if(geom->gmsh_dimTags_n) { 206 if(log) { 207 if(str_is_empty(&geom->name)) { 208 log_message(dev, "Registering tags for unnamed geometry %p.\n", 209 (void*)geom); 210 } else { 211 log_message(dev, "Registering tags for geometry '%s'.\n", 212 str_cget(&geom->name)); 213 } 214 } 215 ERR(do_device_tags_ref_get(geom->gmsh_dimTags, geom->gmsh_dimTags_n)); 216 } 217 218 exit: 219 return res; 220 error: 221 goto exit; 222 } 223 224 struct tag_desc* 225 device_get_description 226 (const int dim, 227 const int tag) 228 { 229 struct scad_device* dev = get_device(); 230 struct htable_tags2desc* t2d; 231 struct tag_desc* desc; 232 CHK(dim == 2 || dim == 3); /* other dims not managed yet */ 233 234 t2d = g_device->tags2desc + (dim-2); 235 desc = htable_tags2desc_find(t2d, &tag); 236 if(!desc || desc->refcount == 0) { 237 logger_print(dev->logger, LOG_ERROR, 238 "SCAD internal error: tag %d.%d not registered.\n", dim, tag); 239 } 240 return desc; 241 } 242 243 res_T 244 scad_dump_geometry 245 (const struct scad_geometry* geom) 246 { 247 res_T res = RES_OK; 248 size_t i; 249 250 if(!geom) { 251 res = RES_BAD_ARG; 252 goto error; 253 } 254 255 ERR(check_device(FUNC_NAME)); 256 if(str_is_empty(&geom->name)) { 257 printf("Unnamed geometry %p (count is %lu), tags: ", 258 (void*)geom, (long unsigned)geom->ref); 259 } else { 260 printf("Geometry '%s' (%p, count is %lu), tags: ", 261 str_cget(&geom->name), (void*)geom, (long unsigned)geom->ref); 262 } 263 for(i = 0; i < geom->gmsh_dimTags_n; i += 2) { 264 int dim = geom->gmsh_dimTags[i]; 265 int tag = geom->gmsh_dimTags[i+1]; 266 printf((i ? ", %d.%d" : "%d.%d"), dim, tag); 267 } 268 printf(".\n"); 269 270 exit: 271 return res; 272 error: 273 goto exit; 274 } 275 276 res_T 277 scad_dump_geometries 278 (void) 279 { 280 res_T res = RES_OK; 281 struct scad_device* dev = get_device(); 282 struct htable_geometries_iterator it, end; 283 size_t cpt = 0; 284 285 ERR(check_device(FUNC_NAME)); 286 287 if(htable_geometries_is_empty(&dev->allgeom)) { 288 printf("No geometry defined.\n"); 289 goto exit; /* Not an error */ 290 } 291 htable_geometries_begin(&dev->allgeom, &it); 292 htable_geometries_end(&dev->allgeom, &end); 293 while(!htable_geometries_iterator_eq(&it, &end)) { 294 struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it); 295 ERR(scad_dump_geometry(geom)); 296 cpt++; 297 htable_geometries_iterator_next(&it); 298 } 299 printf("Counted %ld geometries.\n", cpt); 300 301 exit: 302 return res; 303 error: 304 goto exit; 305 } 306 307 static void 308 device_remove_description 309 (const int dim, 310 const int tag) 311 { 312 struct scad_device* dev = get_device(); 313 struct htable_tags2desc* t2d; 314 struct tag_desc* desc; 315 CHK(dim == 2 || dim == 3); /* other dims not managed yet */ 316 317 t2d = g_device->tags2desc + (dim-2); 318 desc = htable_tags2desc_find(t2d, &tag); 319 if(!desc) { 320 logger_print(dev->logger, LOG_ERROR, 321 "SCAD internal error: tag %d.%d not registered.\n", dim, tag); 322 } 323 if(desc->refcount != 0) { 324 logger_print(dev->logger, LOG_ERROR, 325 "SCAD internal error: erasing tag %d.%d that still has references.\n", 326 dim, tag); 327 } 328 CHK(1 == htable_tags2desc_erase(t2d, &tag)); 329 } 330 331 res_T 332 do_device_tags_ref_get 333 (const int* dimTags, 334 const size_t count) 335 { 336 res_T res = RES_OK; 337 size_t i; 338 struct scad_device* dev = get_device(); 339 int log = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL); 340 enum log_type log_type = dev->log_type; 341 342 ASSERT(dimTags || count == 0); 343 344 for(i = 0; i < count; i += 2) { 345 int dim = dimTags[i]; 346 int tag = dimTags[i+1]; 347 struct htable_tags2desc* t2d; 348 struct tag_desc* desc; 349 CHK(dim == 2 || dim == 3); /* other dims not managed yet */ 350 351 t2d = dev->tags2desc + (dim-2); 352 desc = htable_tags2desc_find(t2d, &tag); 353 if(!desc) { 354 /* First ref to dim.tag: create the description */ 355 struct tag_desc d; 356 tag_desc_init(dev->allocator, &d); 357 ERR(htable_tags2desc_set(t2d, &tag, &d)); 358 dev->need_synchro = 1; 359 if(log) { 360 logger_print(dev->logger, log_type, "New tag %d.%d (count set to 1).\n", 361 dim, tag); 362 } 363 } else { 364 desc->refcount++; 365 if(log) { 366 if(desc->refcount > 1) { 367 logger_print(dev->logger, log_type, "Tag %d.%d (count increased to %lu).\n", 368 dim, tag, desc->refcount); 369 } else { 370 logger_print(dev->logger, log_type, "Reuse tag %d.%d (count set to 1).\n", 371 dim, tag); 372 } 373 } 374 } 375 } 376 377 exit: 378 return res; 379 error: 380 goto exit; 381 } 382 383 res_T 384 do_device_tags_ref_put 385 (const int log, 386 const enum log_type log_type, 387 int* dimTags, 388 size_t count) 389 { 390 res_T res = RES_OK; 391 size_t i; 392 struct scad_device* dev = get_device(); 393 struct str msg; 394 395 ASSERT(dimTags || count == 0); 396 397 if(log) str_init(dev->allocator, &msg); 398 for(i = 0; i < count; i += 2) { 399 int dim = dimTags[i]; 400 int tag = dimTags[i+1]; 401 int ierr; 402 struct tag_desc* desc = device_get_description(dim, tag); 403 404 if(!desc) { 405 res = RES_BAD_OP; 406 goto error; 407 } 408 409 /* Check if still in use after this unregistration */ 410 desc->refcount--; 411 if(desc->refcount > 0) { 412 if(log) { 413 logger_print(dev->logger, log_type, 414 "Tag %d.%d (count decreased to %lu).\n", 415 dim, tag, (unsigned long)desc->refcount); 416 } 417 continue; 418 } 419 420 /* The gmsh geometry with tag 'tag' is not in use anymore: release it */ 421 switch(desc->delete_policy) { 422 case Scad_do_not_delete: 423 if(log) { 424 logger_print(dev->logger, log_type, 425 "Tag %d.%d not deleted due to policy.\n", 426 dim, tag); 427 } 428 break; 429 case Scad_delete_non_recursive: 430 if(log) { 431 logger_print(dev->logger, log_type, 432 "Tag %d.%d non-recursively deleted due to policy.\n", 433 dim, tag); 434 } 435 gmshModelOccRemove(dimTags+i, 2, 0, &ierr); 436 dev->need_synchro = 1; 437 ERR(gmsh_err_to_res_T(ierr)); 438 break; 439 case Scad_delete_recursive: 440 if(log) { 441 logger_print(dev->logger, log_type, "Tag %d.%d recursively deleted.\n", 442 dim, tag); 443 } 444 gmshModelOccRemove(dimTags+i, 2, 1, &ierr); 445 dev->need_synchro = 1; 446 ERR(gmsh_err_to_res_T(ierr)); 447 break; 448 default: FATAL("Invalid enum value"); 449 } 450 /* Release associated tags in tags_to_refput */ 451 if(darray_int_size_get(&desc->tags_to_refput)) { 452 size_t j; 453 const int* dt = darray_int_cdata_get(&desc->tags_to_refput); 454 if(log) { 455 ERR(str_set(&msg, "Putting a reference to tags: ")); 456 for(j = 0; j < darray_int_size_get(&desc->tags_to_refput); j += 2) { 457 int d = dt[j]; 458 int t = dt[j+1]; 459 ERR(str_append_printf(&msg, (j ? ", %d.%d" : "%d.%d"), d, t)); 460 } 461 logger_print(dev->logger, log_type, "%s\n", str_cget(&msg)); 462 } 463 ERR(do_device_tags_ref_put(log, log_type, 464 darray_int_data_get(&desc->tags_to_refput), 465 darray_int_size_get(&desc->tags_to_refput))); 466 } 467 device_remove_description(dim, tag); 468 } 469 470 exit: 471 if(log) str_release(&msg); 472 return res; 473 error: 474 goto exit; 475 } 476 477 res_T 478 device_register_ref_to_tags 479 (const int dim, 480 const int tag, 481 const int* dimTags, 482 const size_t count) 483 { 484 res_T res = RES_OK; 485 struct tag_desc* desc = device_get_description(dim, tag); 486 size_t i, prev_count, c = 0; 487 const int* dt; 488 ASSERT(dimTags); 489 490 if(!desc) { 491 res = RES_BAD_OP; 492 goto error; 493 } 494 495 prev_count = darray_int_size_get(&desc->tags_to_refput); 496 ERR(darray_int_reserve(&desc->tags_to_refput, count + prev_count)); 497 for(i = 0; i < count; i += 2) { 498 int d = dimTags[i]; 499 int t = dimTags[i+1]; 500 if(d == dim && t == tag) 501 continue; 502 ERR(darray_int_push_back(&desc->tags_to_refput, &d)); 503 ERR(darray_int_push_back(&desc->tags_to_refput, &t)); 504 c += 2; 505 } 506 /* As refences will be put, need to get them now */ 507 dt = darray_int_cdata_get(&desc->tags_to_refput); 508 ERR(do_device_tags_ref_get(dt + prev_count, c)); 509 510 exit: 511 return res; 512 error: 513 goto exit; 514 } 515 516 res_T 517 device_unregister_tags 518 (const int log, 519 const enum log_type log_type, 520 struct scad_geometry* geom) 521 { 522 res_T res = RES_OK; 523 struct scad_device* dev = get_device(); 524 ASSERT(geom); 525 526 if(log) { 527 if(str_is_empty(&geom->name)) { 528 logger_print(dev->logger, log_type, 529 "Unregistering tags for unnamed geometry %p.\n", (void*)geom); 530 } else { 531 logger_print(dev->logger, log_type, 532 "Unregistering tags for geometry '%s'.\n", str_cget(&geom->name)); 533 } 534 } 535 536 ERR(do_device_tags_ref_put(log, log_type, geom->gmsh_dimTags, 537 geom->gmsh_dimTags_n)); 538 539 exit: 540 return res; 541 error: 542 goto exit; 543 } 544 545 res_T 546 check_empty_gmsh_occ(struct scad_device* dev) 547 { 548 int* dimTags = NULL; 549 size_t dimTags_n, i; 550 int ierr, found, d; 551 struct str msg; 552 int msg_initialized = 0; 553 res_T res = RES_OK; 554 555 found = 0; 556 for(d = 3; d >= 0; d--) { 557 gmshFree(dimTags); 558 dimTags = NULL; 559 gmshModelOccGetEntities(&dimTags, &dimTags_n, d, &ierr); 560 ASSERT(dimTags_n % 2 == 0); 561 if(dimTags_n == 0) 562 continue; 563 found = 1; 564 log_error(dev, 565 "There are %ld unreferenced Open-Cascade entities of dim %d from an empty star-cad context%c\n", 566 dimTags_n / 2, d, (d > 1 ? ':' : '.')); 567 if(d < 2) continue; 568 if(!msg_initialized) str_init(dev->allocator, &msg); 569 for(i = 0; i < dimTags_n; i += 2) { 570 const int dim = dimTags[i]; 571 const int tag = dimTags[i+1]; 572 ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag)); 573 } 574 log_error(dev," tags [%s]\n", str_cget(&msg)); 575 } 576 if(found) { 577 res = RES_BAD_ARG; 578 goto error; 579 } 580 581 ERR(sync_device()); 582 583 found = 0; 584 for(d = 3; d >= 0; d--) { 585 gmshFree(dimTags); 586 dimTags = NULL; 587 gmshModelGetEntities(&dimTags, &dimTags_n, d, &ierr); 588 ASSERT(dimTags_n % 2 == 0); 589 if(dimTags_n == 0) 590 continue; 591 found = 1; 592 log_error(dev, 593 "There are %ld unreferenced gmsh entities of dim %d from an empty star-cad context%c\n", 594 dimTags_n / 2, d, (d > 1 ? ':' : '.')); 595 if(d < 2) continue; 596 if(!msg_initialized) str_init(dev->allocator, &msg); 597 for(i = 0; i < dimTags_n; i += 2) { 598 const int dim = dimTags[i]; 599 const int tag = dimTags[i+1]; 600 ERR(str_append_printf(&msg, (i ? ", %d.%d" : "%d.%d"), dim, tag)); 601 } 602 log_error(dev," tags [%s]\n", str_cget(&msg)); 603 } 604 if(found) { 605 res = RES_BAD_ARG; 606 goto error; 607 } 608 609 exit: 610 gmshFree(dimTags); 611 if(msg_initialized) str_release(&msg); 612 return res; 613 error: 614 goto exit; 615 } 616 617 /******************************************************************************* 618 * API scad_device functions 619 ******************************************************************************/ 620 res_T 621 scad_initialize 622 (struct logger* logger, 623 struct mem_allocator* mem_allocator, 624 const int verbose) 625 { 626 struct mem_allocator* allocator; 627 res_T res = RES_OK; 628 int ierr; 629 630 if(g_device != NULL) { 631 log_error(g_device, "scad-star is already initialized.\n"); 632 res = RES_BAD_ARG; 633 goto error; 634 } 635 636 if(0 > verbose || verbose > 3) { 637 res = RES_BAD_ARG; 638 goto error; 639 } 640 641 gmshInitialize(0, NULL, 1, 0, &ierr); 642 ERR(gmsh_err_to_res_T(ierr)); 643 644 allocator = mem_allocator ? mem_allocator : &mem_default_allocator; 645 g_device 646 = (struct scad_device*)MEM_CALLOC(allocator, 1, sizeof(struct scad_device)); 647 if(!g_device) { 648 res = RES_MEM_ERR; 649 goto error; 650 } 651 g_device->logger = logger ? logger : LOGGER_DEFAULT; 652 g_device->allocator = allocator; 653 g_device->need_synchro = g_device->options.Misc.DebugAutoSync; 654 g_device->verbose = verbose; 655 g_device->log_type = LOG_OUTPUT; 656 g_device->log = (g_device->options.Misc.LogRefCounting != SCAD_LOG_NONE); 657 htable_names_init(allocator, &g_device->geometry_names); 658 htable_geometries_init(allocator, &g_device->allgeom); 659 htable_tags2desc_init(allocator, &g_device->tags2desc[0]); 660 htable_tags2desc_init(allocator, &g_device->tags2desc[1]); 661 htable_size_modifiers_init(allocator, &g_device->size_modifiers_by_dim[0]); 662 htable_size_modifiers_init(allocator, &g_device->size_modifiers_by_dim[1]); 663 htable_size_modifiers_init(allocator, &g_device->size_modifiers_by_dim[2]); 664 htable_size_modifiers_init(allocator, &g_device->size_modifiers_by_dim[3]); 665 /* Init to default */ 666 scad_set_options(NULL); 667 668 exit: 669 return res; 670 error: 671 if(g_device) { 672 device_release(); 673 } 674 goto exit; 675 } 676 677 res_T 678 scad_finalize 679 (void) 680 { 681 res_T tmp_res = RES_OK, res = RES_OK; 682 int ierr; 683 struct scad_device* dev = get_device(); 684 int log, empty; 685 enum scad_log_refcounting option; 686 enum log_type log_type; 687 688 ERR(check_device(FUNC_NAME)); 689 option = dev->options.Misc.LogRefCounting; 690 691 empty = htable_geometries_is_empty(&dev->allgeom); 692 log_type = empty ? LOG_OUTPUT : LOG_WARNING; 693 log = (option & SCAD_LOG_DIMTAGS_ALL) 694 || (!empty && (option & SCAD_LOG_DIMTAGS_ONLY_UNDELETED)); 695 if(log) { 696 logger_print(dev->logger, log_type, 697 "Finalizing scad; undeleted tags will be automatically unregistered.\n"); 698 } 699 700 tmp_res = device_release(); 701 gmshFinalize(&ierr); 702 ERR(gmsh_err_to_res_T(ierr)); 703 704 exit: 705 if(tmp_res != RES_OK) res = tmp_res; 706 return res; 707 error: 708 goto exit; 709 } 710 711 #define SET_GMSH_OPTION_INT(Option) \ 712 gmshOptionSetNumber((#Option), (actual_options->Option), &ierr);\ 713 if(ierr) {\ 714 log_error(dev, "Could not set option %s to %d.\n",\ 715 (#Option), (actual_options->Option));\ 716 res = RES_BAD_ARG;\ 717 goto error;\ 718 } 719 720 #define SET_GMSH_OPTION_DOUBLE(Option) \ 721 gmshOptionSetNumber((#Option), (actual_options->Option), &ierr);\ 722 if(ierr) {\ 723 log_error(dev, "Could not set option %s to %g.\n",\ 724 (#Option), (actual_options->Option));\ 725 res = RES_BAD_ARG;\ 726 goto error;\ 727 } 728 729 res_T 730 scad_set_options 731 (const struct scad_options* options) 732 { 733 res_T res = RES_OK; 734 const struct scad_options* actual_options 735 = options ? options : &SCAD_DEFAULT_OPTIONS; 736 int ierr = 0; 737 struct scad_options keep; 738 struct scad_device* dev = NULL; 739 740 ERR(check_device(FUNC_NAME)); 741 742 dev = get_device(); 743 keep = dev->options; 744 745 SET_GMSH_OPTION_DOUBLE(Mesh.MeshSizeFactor); 746 SET_GMSH_OPTION_DOUBLE(Mesh.MeshSizeFromCurvature); 747 SET_GMSH_OPTION_DOUBLE(Mesh.MeshSizeMax); 748 SET_GMSH_OPTION_DOUBLE(Mesh.MeshSizeMin); 749 SET_GMSH_OPTION_DOUBLE(Mesh.Smoothing); 750 SET_GMSH_OPTION_INT(Mesh.StlOneSolidPerSurface); 751 SET_GMSH_OPTION_INT(Mesh.MeshOnlyVisible); 752 SET_GMSH_OPTION_INT(Mesh.Algorithm); 753 SET_GMSH_OPTION_INT(Mesh.MeshSizeExtendFromBoundary); 754 SET_GMSH_OPTION_INT(Mesh.MeshSizeFromPoints); 755 756 SET_GMSH_OPTION_INT(General.Verbosity); 757 SET_GMSH_OPTION_INT(General.ExpertMode); 758 759 SET_GMSH_OPTION_INT(Geometry.OCCParallel); 760 761 if(options) { 762 /* Check non-gmsh option validity if user-provided */ 763 (void)actual_options->Misc.RunUIAtEachStep; /* int boolean: always OK */ 764 (void)actual_options->Misc.SynchronizeOnRunUI; /* int boolean: always OK */ 765 (void)actual_options->Misc.LogRefCounting; /* int boolean: always OK */ 766 (void)actual_options->Misc.DebugAutoSync; /* int boolean: always OK */ 767 (void)actual_options->Misc.DebugEmptyContext; /* int boolean: always OK */ 768 } 769 770 dev->options = *actual_options; 771 772 /* Update logging policy */ 773 dev->log 774 = (dev->options.Misc.LogRefCounting & SCAD_LOG_DIMTAGS_ALL); 775 776 exit: 777 return res; 778 error: 779 if(dev) dev->options = keep; 780 goto exit; 781 } 782 783 #undef SET_GMSH_OPTION_INT 784 #undef SET_GMSH_OPTION_DOUBLE 785 786 res_T 787 scad_get_options 788 (struct scad_options* options) 789 { 790 res_T res = RES_OK; 791 struct scad_device* dev = NULL; 792 793 if(! options) { 794 res = RES_BAD_ARG; 795 goto error; 796 } 797 798 ERR(check_device(FUNC_NAME)); 799 800 dev = get_device(); 801 802 *options = dev->options; 803 804 exit: 805 return res; 806 error: 807 goto exit; 808 }