solparser_geometry.c (47207B)
1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016-2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #define _POSIX_C_SOURCE 200112L /* nextafter support */ 18 19 #include "solparser_c.h" 20 #include <rsys/double2.h> 21 #include <math.h> /* nextafter */ 22 23 /******************************************************************************* 24 * Helper functions 25 ******************************************************************************/ 26 static res_T 27 parse_clip_op 28 (struct solparser* parser, 29 const yaml_node_t* op, 30 enum solparser_clip_op* clip_op) 31 { 32 res_T res = RES_OK; 33 ASSERT(op && clip_op); 34 35 if(op->type != YAML_SCALAR_NODE) { 36 log_err(parser, op, "expect a clipping operation.\n"); 37 res = RES_BAD_ARG; 38 goto error; 39 } 40 41 if(!strcmp((char*)op->data.scalar.value, "AND")) { 42 *clip_op = SOLPARSER_CLIP_OP_AND; 43 } else if(!strcmp((char*)op->data.scalar.value, "SUB")) { 44 *clip_op = SOLPARSER_CLIP_OP_SUB; 45 } else { 46 log_err(parser, op, "unknown clipping operation `%s'.\n", 47 op->data.scalar.value); 48 res = RES_BAD_ARG; 49 goto error; 50 } 51 52 exit: 53 return res; 54 error: 55 goto exit; 56 } 57 58 static res_T 59 parse_vertices 60 (struct solparser* parser, 61 yaml_document_t* doc, 62 const yaml_node_t* vertices, 63 struct darray_double* coords) 64 { 65 intptr_t i, n; 66 res_T res = RES_OK; 67 ASSERT(doc && vertices && coords); 68 69 if(vertices->type != YAML_SEQUENCE_NODE) { 70 log_err(parser, vertices, "expect a list of vertices.\n"); 71 res = RES_BAD_ARG; 72 goto error; 73 } 74 75 n = vertices->data.sequence.items.top - vertices->data.sequence.items.start; 76 if(n < 3) { 77 log_err(parser, vertices, "expect at least 3 vertices.\n"); 78 res = RES_BAD_ARG; 79 goto error; 80 } 81 82 res = darray_double_resize(coords, (size_t)n*2/*#coords per vertex*/); 83 if(res != RES_OK) { 84 log_err(parser, vertices, "could not allocate the array of vertices.\n"); 85 goto error; 86 } 87 88 FOR_EACH(i, 0, n) { 89 yaml_node_t* vertex; 90 double* real2 = darray_double_data_get(coords) + i*2/*#coords per vertex*/; 91 92 vertex = yaml_document_get_node(doc, vertices->data.sequence.items.start[i]); 93 res = parse_real2(parser, doc, vertex, -DBL_MAX, DBL_MAX, real2); 94 if(res != RES_OK) goto error; 95 } 96 97 exit: 98 return res; 99 error: 100 darray_double_clear(coords); 101 goto exit; 102 } 103 104 static res_T 105 parse_circle 106 (struct solparser* parser, 107 yaml_document_t* doc, 108 const yaml_node_t* circle, 109 struct solparser_circleclip* clip) 110 { 111 enum { RADIUS, CENTER, SEGMENTS }; 112 intptr_t i, n; 113 int mask = 0; /* Register the parsed attributes */ 114 res_T res = RES_OK; 115 ASSERT(doc && circle && clip); 116 117 if(circle->type != YAML_MAPPING_NODE) { 118 log_err(parser, circle, 119 "expect a mapping of clipping circles parameters.\n"); 120 res = RES_BAD_ARG; 121 goto error; 122 } 123 124 n = circle->data.mapping.pairs.top - circle->data.mapping.pairs.start; 125 clip->segments = 64; /* default value */ 126 d2_splat(clip->center, 0); /* default value */ 127 FOR_EACH(i, 0, n) { 128 yaml_node_t* key; 129 yaml_node_t* val; 130 131 key = yaml_document_get_node(doc, circle->data.mapping.pairs.start[i].key); 132 val = yaml_document_get_node(doc, circle->data.mapping.pairs.start[i].value); 133 if (key->type != YAML_SCALAR_NODE) { 134 log_err(parser, key, "expect a clipping circle parameter.\n"); 135 res = RES_BAD_ARG; 136 goto error; 137 } 138 139 #define SETUP_MASK(Flag, Name) { \ 140 if(mask & BIT(Flag)) { \ 141 log_err(parser, key, \ 142 "the clipping circle parameter `"Name"' is already defined.\n"); \ 143 res = RES_BAD_ARG; \ 144 goto error; \ 145 } \ 146 mask |= BIT(Flag); \ 147 } (void)0 148 if(!strcmp((char*)key->data.scalar.value, "radius")) { 149 SETUP_MASK(RADIUS, "radius"); 150 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &clip->radius); 151 } 152 else if(!strcmp((char*)key->data.scalar.value, "center")) { 153 SETUP_MASK(CENTER, "center"); 154 res = parse_real2(parser, doc, val, -DBL_MAX, DBL_MAX, clip->center); 155 } 156 else if(!strcmp((char*)key->data.scalar.value, "segments")) { 157 SETUP_MASK(SEGMENTS, "segments"); 158 res = parse_integer(parser, val, 3, 4096, &clip->segments); 159 } else { 160 log_err(parser, key, "unknown clipping circle parameter `%s'.\n", 161 key->data.scalar.value); 162 res = RES_BAD_ARG; 163 goto error; 164 } 165 if(res != RES_OK) { 166 log_node(parser, key); 167 goto error; 168 } 169 #undef SETUP_MASK 170 } 171 172 #define CHECK_PARAM(Flag, Name) \ 173 if(!(mask & BIT(Flag))) { \ 174 log_err(parser, circle, \ 175 "the clipping circle parameter `"Name"' is missing.\n"); \ 176 res = RES_BAD_ARG; \ 177 goto error; \ 178 } (void)0 179 CHECK_PARAM(RADIUS, "radius"); 180 #undef CHECK_PARAM 181 182 exit: 183 return res; 184 error: 185 goto exit; 186 } 187 188 static res_T 189 parse_polyclip 190 (struct solparser* parser, 191 yaml_document_t* doc, 192 const yaml_node_t* polyclip, 193 struct solparser_polyclip* clip) 194 { 195 enum { OPERATION, CONTOUR }; 196 intptr_t i, n; 197 int mask = 0; /* Register the parsed attributes */ 198 res_T res = RES_OK; 199 ASSERT(doc && polyclip && clip); 200 201 if(polyclip->type != YAML_MAPPING_NODE) { 202 log_err(parser, polyclip, 203 "expect a mapping of clipping polygon parameters.\n"); 204 res = RES_OK; 205 goto error; 206 } 207 208 n = polyclip->data.mapping.pairs.top - polyclip->data.mapping.pairs.start; 209 FOR_EACH(i, 0, n) { 210 yaml_node_t* key; 211 yaml_node_t* val; 212 213 key = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].key); 214 val = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].value); 215 if(key->type != YAML_SCALAR_NODE) { 216 log_err(parser, key, "expect a clipping polygon parameter.\n"); 217 res = RES_BAD_ARG; 218 goto error; 219 } 220 221 #define SETUP_MASK(Flag, Name) { \ 222 if(mask & BIT(Flag)) { \ 223 log_err(parser, key, \ 224 "the clipping polygon parameter `"Name"' is already defined.\n"); \ 225 res = RES_BAD_ARG; \ 226 goto error; \ 227 } \ 228 mask |= BIT(Flag); \ 229 } (void)0 230 if(!strcmp((char*)key->data.scalar.value, "operation")) { 231 SETUP_MASK(OPERATION, "operation"); 232 res = parse_clip_op(parser, val, &clip->op); 233 } else if(!strcmp((char*)key->data.scalar.value, "vertices")) { 234 SETUP_MASK(CONTOUR, "contour"); 235 clip->contour_type = SOLPARSER_CLIP_CONTOUR_POLY; 236 res = parse_vertices(parser, doc, val, &clip->vertices); 237 } 238 else if(!strcmp((char*)key->data.scalar.value, "circle")) { 239 SETUP_MASK(CONTOUR, "contour"); 240 clip->contour_type = SOLPARSER_CLIP_CONTOUR_CIRCLE; 241 res = parse_circle(parser, doc, val, &clip->circle); 242 } else { 243 log_err(parser, key, "unknown clipping polygon parameter `%s'.\n", 244 key->data.scalar.value); 245 res = RES_BAD_ARG; 246 goto error; 247 } 248 if(res != RES_OK) { 249 log_node(parser, key); 250 goto error; 251 } 252 #undef SETUP_MASK 253 } 254 255 #define CHECK_PARAM(Flag, Name) \ 256 if(!(mask & BIT(Flag))) { \ 257 log_err(parser, polyclip, \ 258 "the clipping polygon parameter `"Name"' is missing.\n"); \ 259 res = RES_BAD_ARG; \ 260 goto error; \ 261 } (void)0 262 CHECK_PARAM(OPERATION, "operation"); 263 CHECK_PARAM(CONTOUR, "contour"); 264 #undef CHECK_PARAM 265 266 exit: 267 return res; 268 error: 269 goto exit; 270 } 271 272 static res_T 273 parse_clip 274 (struct solparser* parser, 275 yaml_document_t* doc, 276 const yaml_node_t* clip, 277 struct darray_polyclip* polyclips) 278 { 279 intptr_t i, n; 280 res_T res = RES_OK; 281 ASSERT(doc && clip && polyclips); 282 283 if(clip->type != YAML_SEQUENCE_NODE) { 284 log_err(parser, clip, "expect a list of clipping polygons.\n"); 285 res = RES_BAD_ARG; 286 goto error; 287 } 288 289 n = clip->data.sequence.items.top - clip->data.sequence.items.start; 290 291 /* Allocate the clipping polygons */ 292 res = darray_polyclip_resize(polyclips, (size_t)n); 293 if(res != RES_OK) { 294 log_err(parser, clip, "could not allocate the list of clipping polygons.\n"); 295 goto error; 296 } 297 298 FOR_EACH(i, 0, n) { 299 yaml_node_t* node; 300 struct solparser_polyclip* polyclip = darray_polyclip_data_get(polyclips) + i; 301 302 node = yaml_document_get_node(doc, clip->data.sequence.items.start[i]); 303 res = parse_polyclip(parser, doc, node, polyclip); 304 if(res != RES_OK) goto error; 305 } 306 307 exit: 308 return res; 309 error: 310 goto exit; 311 } 312 313 314 static res_T 315 parse_cuboid 316 (struct solparser* parser, 317 yaml_document_t* doc, 318 const yaml_node_t* cuboid, 319 struct solparser_shape_cuboid_id* out_ishape) 320 { 321 enum { SIZE }; 322 struct solparser_shape_cuboid* shape = NULL; 323 size_t ishape = SIZE_MAX; 324 intptr_t i, n; 325 int mask = 0; /* Register the parsed attributes */ 326 res_T res = RES_OK; 327 ASSERT(doc && cuboid && out_ishape); 328 329 if(cuboid->type != YAML_MAPPING_NODE) { 330 log_err(parser, cuboid, "expect a mapping of cuboid parameters.\n"); 331 res = RES_BAD_ARG; 332 goto error; 333 } 334 335 /* Allocate a cuboid */ 336 ishape = darray_cuboid_size_get(&parser->cuboids); 337 res = darray_cuboid_resize(&parser->cuboids, ishape + 1); 338 if(res != RES_OK) { 339 log_err(parser, cuboid, "could not allocate the cuboid shape.\n"); 340 goto exit; 341 } 342 shape = darray_cuboid_data_get(&parser->cuboids) + ishape; 343 344 n = cuboid->data.mapping.pairs.top - cuboid->data.mapping.pairs.start; 345 FOR_EACH(i, 0, n) { 346 yaml_node_t* key; 347 yaml_node_t* val; 348 349 key = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].key); 350 val = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].value); 351 if(key->type != YAML_SCALAR_NODE) { 352 log_err(parser, key, "expect cuboid parameters.\n"); 353 res = RES_BAD_ARG; 354 goto error; 355 } 356 if(!strcmp((char*)key->data.scalar.value, "size")) { 357 if(mask & BIT(SIZE)) { 358 log_err(parser, key, "the cuboid size is already defined.\n"); 359 res = RES_BAD_ARG; 360 goto error; 361 } 362 mask |= BIT(SIZE); 363 res = parse_real3(parser, doc, val, nextafter(0, 1), DBL_MAX, shape->size); 364 } else { 365 log_err(parser, key, "unknown cuboid parameter `%s'.\n", 366 key->data.scalar.value); 367 res = RES_BAD_ARG; 368 goto error; 369 } 370 if(res != RES_OK) { 371 log_node(parser, key); 372 goto error; 373 } 374 } 375 376 if(!(mask & BIT(SIZE))) { 377 log_err(parser, cuboid, "the size of the cuboid is missing.\n"); 378 res = RES_BAD_ARG; 379 goto error; 380 } 381 382 exit: 383 out_ishape->i = ishape; 384 return res; 385 error: 386 if(shape) { 387 darray_cuboid_pop_back(&parser->cuboids); 388 ishape = SIZE_MAX; 389 } 390 goto exit; 391 } 392 393 static res_T 394 parse_cylinder 395 (struct solparser* parser, 396 yaml_document_t* doc, 397 const yaml_node_t* cylinder, 398 struct solparser_shape_cylinder_id* out_ishape) 399 { 400 enum { HEIGHT, RADIUS, SLICES, STACKS }; 401 struct solparser_shape_cylinder* shape = NULL; 402 size_t ishape = SIZE_MAX; 403 intptr_t i, n; 404 int mask = 0; /* Register the parsed attributes */ 405 res_T res = RES_OK; 406 ASSERT(doc && cylinder && out_ishape); 407 408 if(cylinder->type != YAML_MAPPING_NODE) { 409 log_err(parser, cylinder, "expect a mapping of cylinder parameters.\n"); 410 res = RES_BAD_ARG; 411 goto error; 412 } 413 414 /* Allocate a cylinder */ 415 ishape = darray_cylinder_size_get(&parser->cylinders); 416 res = darray_cylinder_resize(&parser->cylinders, ishape + 1); 417 if(res != RES_OK) { 418 log_err(parser, cylinder, "could not alocate the cylinder shape.\n"); 419 goto exit; 420 } 421 shape = darray_cylinder_data_get(&parser->cylinders) + ishape; 422 423 n = cylinder->data.mapping.pairs.top - cylinder->data.mapping.pairs.start; 424 shape->nslices = 16; /* default value */ 425 shape->nstacks = 1; /* default value */ 426 FOR_EACH(i, 0, n) { 427 yaml_node_t* key; 428 yaml_node_t* val; 429 430 key = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].key); 431 val = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].value); 432 if(key->type != YAML_SCALAR_NODE) { 433 log_err(parser, key, "expect cylinder parameters.\n"); 434 res = RES_BAD_ARG; 435 goto error; 436 } 437 #define SETUP_MASK(Flag, Name) { \ 438 if(mask & BIT(Flag)) { \ 439 log_err(parser, key, \ 440 "the cylinder parameter `"Name"' is already defined.\n"); \ 441 res = RES_BAD_ARG; \ 442 goto error; \ 443 } \ 444 mask |= BIT(Flag); \ 445 } (void)0 446 if(!strcmp((char*)key->data.scalar.value, "height")) { 447 SETUP_MASK(HEIGHT, "height"); 448 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->height); 449 } else if(!strcmp((char*)key->data.scalar.value, "radius")) { 450 SETUP_MASK(RADIUS, "radius"); 451 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->radius); 452 } else if(!strcmp((char*)key->data.scalar.value, "slices")) { 453 SETUP_MASK(SLICES, "slices"); 454 res = parse_integer(parser, val, 4, 4096, &shape->nslices); 455 } 456 else if(!strcmp((char*)key->data.scalar.value, "stacks")) { 457 SETUP_MASK(STACKS, "stacks"); 458 res = parse_integer(parser, val, 1, 4096, &shape->nstacks); 459 } else { 460 log_err(parser, key, "unknown cylinder parameter `%s'.\n", 461 key->data.scalar.value); 462 res = RES_BAD_ARG; 463 goto error; 464 } 465 if(res != RES_OK) { 466 log_node(parser, key); 467 goto error; 468 } 469 #undef SETUP_MASK 470 } 471 472 #define CHECK_PARAM(Flag, Name) \ 473 if(!(mask & BIT(Flag))) { \ 474 log_err(parser, cylinder, \ 475 "the cylinder parameter `"Name"' is missing.\n"); \ 476 res = RES_BAD_ARG; \ 477 goto error; \ 478 } (void)0 479 CHECK_PARAM(HEIGHT, "height"); 480 CHECK_PARAM(RADIUS, "radius"); 481 #undef CHECK_PARAM 482 483 exit: 484 out_ishape->i = ishape; 485 return res; 486 error: 487 if(shape) { 488 darray_cylinder_pop_back(&parser->cylinders); 489 ishape = SIZE_MAX; 490 } 491 goto exit; 492 } 493 494 static res_T 495 parse_imported_geometry 496 (struct solparser* parser, 497 yaml_document_t* doc, 498 const yaml_node_t* geom, 499 const enum solparser_shape_type type, 500 struct solparser_shape_imported_geometry_id* out_ishape) 501 { 502 enum { PATH }; 503 struct solparser_shape_imported_geometry* shape = NULL; 504 size_t ishape = SIZE_MAX; 505 const char* name; 506 struct darray_impgeom* impgeoms; 507 intptr_t i, n; 508 int mask = 0; /* Register the parsed attributes */ 509 res_T res = RES_OK; 510 ASSERT(doc && geom && out_ishape); 511 512 switch(type) { 513 case SOLPARSER_SHAPE_OBJ: name = "obj"; impgeoms = &parser->objs; break; 514 case SOLPARSER_SHAPE_STL: name = "stl"; impgeoms = &parser->stls; break; 515 default: FATAL("Unreachable code.\n"); break; 516 } 517 518 if(geom->type != YAML_MAPPING_NODE) { 519 log_err(parser, geom, "expect a mapping of %s parameters.\n", name); 520 res = RES_BAD_ARG; 521 goto error; 522 } 523 524 /* Allocate an imported geometry */ 525 ishape = darray_impgeom_size_get(impgeoms); 526 res = darray_impgeom_resize(impgeoms, ishape + 1); 527 if(res != RES_OK) { 528 log_err(parser, geom, "could not allocate the %s shape.\n", name); 529 goto error; 530 } 531 shape = darray_impgeom_data_get(impgeoms) + ishape; 532 533 n = geom->data.mapping.pairs.top - geom->data.mapping.pairs.start; 534 FOR_EACH(i, 0, n) { 535 yaml_node_t* key; 536 yaml_node_t* val; 537 538 key = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].key); 539 val = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].value); 540 if(key->type != YAML_SCALAR_NODE) { 541 log_err(parser, key, "expect %s parameters.\n", name); 542 res = RES_BAD_ARG; 543 goto error; 544 } 545 if(!strcmp((char*)key->data.scalar.value, "path")) { 546 if(mask & BIT(PATH)) { 547 log_err(parser, key, "the %s path is already defined.\n", name); 548 res = RES_BAD_ARG; 549 goto error; 550 } 551 mask |= BIT(PATH); 552 res = parse_string(parser, val, &shape->filename); 553 } else { 554 log_err(parser, key, "unknown %s parameter `%s'.\n", 555 name, key->data.scalar.value); 556 res = RES_BAD_ARG; 557 goto error; 558 } 559 if(res != RES_OK) { 560 log_node(parser, key); 561 goto error; 562 } 563 } 564 565 if(!(mask & BIT(PATH))) { 566 log_err(parser, geom, "the path of the %s geometry is missing.\n", name); 567 res = RES_BAD_ARG; 568 goto error; 569 } 570 571 exit: 572 out_ishape->i = ishape; 573 return res; 574 error: 575 if(shape) { 576 darray_impgeom_pop_back(impgeoms); 577 ishape = SIZE_MAX; 578 } 579 goto exit; 580 } 581 582 static res_T 583 parse_paraboloid 584 (struct solparser* parser, 585 yaml_document_t* doc, 586 const yaml_node_t* paraboloid, 587 const enum solparser_shape_type type, 588 struct solparser_shape_paraboloid_id* out_ishape) 589 { 590 enum { CLIP, FOCAL, SLICES }; 591 struct solparser_shape_paraboloid* shape = NULL; 592 struct darray_paraboloid* paraboloids; 593 const char* name; 594 size_t ishape = SIZE_MAX; 595 intptr_t i, n; 596 int mask = 0; /* Register the parsed attributes */ 597 res_T res = RES_OK; 598 ASSERT(doc && paraboloid && out_ishape); 599 600 switch(type) { 601 case SOLPARSER_SHAPE_PARABOL: 602 name = "parabol"; 603 paraboloids = &parser->parabols; 604 break; 605 case SOLPARSER_SHAPE_PARABOLIC_CYLINDER: 606 name = "parabolic cylinder"; 607 paraboloids = &parser->parabolic_cylinders; 608 break; 609 default: FATAL("Unreachable code.\n"); break; 610 } 611 612 if(paraboloid->type != YAML_MAPPING_NODE) { 613 log_err(parser, paraboloid, "expect a mapping of %s parameters.\n", name); 614 res = RES_BAD_ARG; 615 goto error; 616 } 617 618 /* Allocate a paraboloid shape */ 619 ishape = darray_paraboloid_size_get(paraboloids); 620 res = darray_paraboloid_resize(paraboloids, ishape + 1); 621 if(res != RES_OK) { 622 log_err(parser, paraboloid, "could not allocate the %s shape.\n", name); 623 goto error; 624 } 625 shape = darray_paraboloid_data_get(paraboloids) + ishape; 626 627 n = paraboloid->data.mapping.pairs.top - paraboloid->data.mapping.pairs.start; 628 FOR_EACH(i, 0, n) { 629 yaml_node_t* key; 630 yaml_node_t* val; 631 632 key = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].key); 633 val = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].value); 634 if(key->type != YAML_SCALAR_NODE) { 635 log_err(parser, key, "expect %s parameters.\n", name); 636 res = RES_BAD_ARG; 637 goto error; 638 } 639 #define SETUP_MASK(Flag, Name) { \ 640 if(mask & BIT(Flag)) { \ 641 log_err(parser, key, \ 642 "the %s parameter `"Name"' is already defined.\n", name); \ 643 res = RES_BAD_ARG; \ 644 goto error; \ 645 } \ 646 mask |= BIT(Flag); \ 647 } (void)0 648 if(!strcmp((char*)key->data.scalar.value, "clip")) { 649 SETUP_MASK(CLIP, "clip"); 650 res = parse_clip(parser, doc, val, &shape->polyclips); 651 } else if(!strcmp((char*)key->data.scalar.value, "focal")) { 652 SETUP_MASK(FOCAL, "focal"); 653 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->focal); 654 } else if(!strcmp((char*)key->data.scalar.value, "slices")) { 655 SETUP_MASK(SLICES, "slices"); 656 res = parse_integer(parser, val, 4, 4096, &shape->nslices); 657 } else { 658 log_err(parser, key, "unknown %s parameter `%s'.\n", 659 name, key->data.scalar.value); 660 res = RES_BAD_ARG; 661 goto error; 662 } 663 if(res != RES_OK) { 664 log_node(parser, key); 665 goto error; 666 } 667 #undef SETUP_MASK 668 } 669 #define CHECK_PARAM(Flag, Name) \ 670 if(!(mask & BIT(Flag))) { \ 671 log_err(parser, paraboloid, \ 672 "the %s parameter `"Name"' is missing.\n", name); \ 673 res = RES_BAD_ARG; \ 674 goto error; \ 675 } (void)0 676 CHECK_PARAM(CLIP, "clip"); 677 CHECK_PARAM(FOCAL, "focal"); 678 #undef CHECK_PARAM 679 680 exit: 681 out_ishape->i = ishape; 682 return res; 683 error: 684 if(shape) { 685 darray_paraboloid_pop_back(paraboloids); 686 ishape = SIZE_MAX; 687 } 688 goto exit; 689 } 690 691 static res_T 692 parse_hyperboloid 693 (struct solparser* parser, 694 yaml_document_t* doc, 695 const yaml_node_t* hyperboloid, 696 struct solparser_shape_hyperboloid_id* out_ishape) 697 { 698 enum { CLIP, FOCAL, SLICES }; 699 struct solparser_shape_hyperboloid* shape = NULL; 700 size_t ishape = SIZE_MAX; 701 intptr_t i, n; 702 int mask = 0; /* Register the parsed attributes */ 703 res_T res = RES_OK; 704 ASSERT(doc && hyperboloid && out_ishape); 705 706 if(hyperboloid->type != YAML_MAPPING_NODE) { 707 log_err(parser, hyperboloid, "expect a mapping of hyperbol parameters.\n"); 708 res = RES_BAD_ARG; 709 goto error; 710 } 711 712 /* Allocate a hyperboloid shape */ 713 ishape = darray_hyperboloid_size_get(&parser->hyperbols); 714 res = darray_hyperboloid_resize(&parser->hyperbols, ishape + 1); 715 if(res != RES_OK) { 716 log_err(parser, hyperboloid, "could not allocate the hyperbol shape.\n"); 717 goto error; 718 } 719 shape = darray_hyperboloid_data_get(&parser->hyperbols) + ishape; 720 721 n = hyperboloid->data.mapping.pairs.top - hyperboloid->data.mapping.pairs.start; 722 FOR_EACH(i, 0, n) { 723 yaml_node_t* key; 724 yaml_node_t* val; 725 726 key = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].key); 727 val = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].value); 728 if(key->type != YAML_SCALAR_NODE) { 729 log_err(parser, key, "expect hyperbol parameters.\n"); 730 res = RES_BAD_ARG; 731 goto error; 732 } 733 #define SETUP_MASK(Flag, Name) { \ 734 if(mask & BIT(Flag)) { \ 735 log_err(parser, key, \ 736 "the hyperbol parameter `"Name"' is already defined.\n"); \ 737 res = RES_BAD_ARG; \ 738 goto error; \ 739 } \ 740 mask |= BIT(Flag); \ 741 } (void)0 742 if(!strcmp((char*) key->data.scalar.value, "clip")) { 743 SETUP_MASK(CLIP, "clip"); 744 res = parse_clip(parser, doc, val, &shape->polyclips); 745 } else if(!strcmp((char*)key->data.scalar.value, "focals")) { 746 SETUP_MASK(FOCAL, "focals"); 747 res = parse_focals_description(parser, doc, val, &shape->focals); 748 } else if(!strcmp((char*)key->data.scalar.value, "slices")) { 749 SETUP_MASK(SLICES, "slices"); 750 res = parse_integer(parser, val, 4, 4096, &shape->nslices); 751 } else { 752 log_err(parser, key, "unknown hyperbol parameter `%s'.\n", 753 key->data.scalar.value); 754 res = RES_BAD_ARG; 755 goto error; 756 } 757 if(res != RES_OK) { 758 log_node(parser, key); 759 goto error; 760 } 761 #undef SETUP_MASK 762 } 763 #define CHECK_PARAM(Flag, Name) \ 764 if(!(mask & BIT(Flag))) { \ 765 log_err(parser, hyperboloid, \ 766 "the hyperbol parameter `"Name"' is missing.\n"); \ 767 res = RES_BAD_ARG; \ 768 goto error; \ 769 } (void)0 770 CHECK_PARAM(CLIP, "clip"); 771 CHECK_PARAM(FOCAL, "focals"); 772 #undef CHECK_PARAM 773 774 exit : 775 out_ishape->i = ishape; 776 return res; 777 error: 778 if(shape) { 779 darray_hyperboloid_pop_back(&parser->hyperbols); 780 ishape = SIZE_MAX; 781 } 782 goto exit; 783 } 784 785 static res_T 786 parse_hemisphere 787 (struct solparser* parser, 788 yaml_document_t* doc, 789 const yaml_node_t* hemisphere, 790 struct solparser_shape_hemisphere_id* out_ishape) 791 { 792 enum { CLIP, RADIUS, SLICES }; 793 struct solparser_shape_hemisphere* shape = NULL; 794 size_t ishape = SIZE_MAX; 795 intptr_t i, n; 796 int mask = 0; /* Register the parsed attributes */ 797 res_T res = RES_OK; 798 ASSERT(doc && hemisphere && out_ishape); 799 800 if(hemisphere->type != YAML_MAPPING_NODE) { 801 log_err(parser, hemisphere, "expect a mapping of hemisphere parameters.\n"); 802 res = RES_BAD_ARG; 803 goto error; 804 } 805 806 /* Allocate a hemispheric shape */ 807 ishape = darray_hemisphere_size_get(&parser->hemispheres); 808 res = darray_hemisphere_resize(&parser->hemispheres, ishape + 1); 809 if(res != RES_OK) { 810 log_err(parser, hemisphere, "could not allocate the hemisphere shape.\n"); 811 goto error; 812 } 813 shape = darray_hemisphere_data_get(&parser->hemispheres) + ishape; 814 815 n = hemisphere->data.mapping.pairs.top - hemisphere->data.mapping.pairs.start; 816 FOR_EACH(i, 0, n) { 817 yaml_node_t* key; 818 yaml_node_t* val; 819 820 key = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].key); 821 val = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].value); 822 if(key->type != YAML_SCALAR_NODE) { 823 log_err(parser, key, "expect hemisphere parameters.\n"); 824 res = RES_BAD_ARG; 825 goto error; 826 } 827 #define SETUP_MASK(Flag, Name) { \ 828 if(mask & BIT(Flag)) { \ 829 log_err(parser, key, \ 830 "the hemisphere parameter `"Name"' is already defined.\n"); \ 831 res = RES_BAD_ARG; \ 832 goto error; \ 833 } \ 834 mask |= BIT(Flag); \ 835 } (void)0 836 if(!strcmp((char*)key->data.scalar.value, "clip")) { 837 SETUP_MASK(CLIP, "clip"); 838 res = parse_clip(parser, doc, val, &shape->polyclips); 839 } 840 else if(!strcmp((char*)key->data.scalar.value, "radius")) { 841 SETUP_MASK(RADIUS, "radius"); 842 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->radius); 843 } 844 else if(!strcmp((char*)key->data.scalar.value, "slices")) { 845 SETUP_MASK(SLICES, "slices"); 846 res = parse_integer(parser, val, 4, 4096, &shape->nslices); 847 } 848 else { 849 log_err(parser, key, "unknown hemisphere parameter `%s'.\n", 850 key->data.scalar.value); 851 res = RES_BAD_ARG; 852 goto error; 853 } 854 if (res != RES_OK) { 855 log_node(parser, key); 856 goto error; 857 } 858 #undef SETUP_MASK 859 } 860 #define CHECK_PARAM(Flag, Name) \ 861 if(!(mask & BIT(Flag))) { \ 862 log_err(parser, hemisphere, \ 863 "the hemisphere parameter `"Name"' is missing.\n"); \ 864 res = RES_BAD_ARG; \ 865 goto error; \ 866 } (void)0 867 CHECK_PARAM(RADIUS, "radius"); 868 #undef CHECK_PARAM 869 870 exit : 871 out_ishape->i = ishape; 872 return res; 873 error: 874 if(shape) { 875 darray_hemisphere_pop_back(&parser->hemispheres); 876 ishape = SIZE_MAX; 877 } 878 goto exit; 879 } 880 881 static res_T 882 parse_plane 883 (struct solparser* parser, 884 yaml_document_t* doc, 885 const yaml_node_t* plane, 886 struct solparser_shape_plane_id* out_ishape) 887 { 888 enum { CLIP, SLICES }; 889 struct solparser_shape_plane* shape = NULL; 890 size_t ishape = SIZE_MAX; 891 intptr_t i, n; 892 int mask = 0; /* Register the parsed attributes */ 893 res_T res = RES_OK; 894 ASSERT(doc && plane && out_ishape); 895 896 if(plane->type != YAML_MAPPING_NODE) { 897 log_err(parser, plane, "expect a mapping of plane parameters.\n"); 898 res = RES_BAD_ARG; 899 goto error; 900 } 901 902 /* Allocate a plane shape */ 903 ishape = darray_plane_size_get(&parser->planes); 904 res = darray_plane_resize(&parser->planes, ishape + 1); 905 if(res != RES_OK) { 906 log_err(parser, plane, "could not allocate the plane shape.\n"); 907 goto error; 908 } 909 shape = darray_plane_data_get(&parser->planes) + ishape; 910 911 n = plane->data.mapping.pairs.top - plane->data.mapping.pairs.start; 912 shape->nslices = 1; /* default value */ 913 FOR_EACH(i, 0, n) { 914 yaml_node_t* key; 915 yaml_node_t* val; 916 917 key = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].key); 918 val = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].value); 919 if(key->type != YAML_SCALAR_NODE) { 920 log_err(parser, key, "expect plane parameters.\n"); 921 res = RES_BAD_ARG; 922 goto error; 923 } 924 #define SETUP_MASK(Flag, Name) { \ 925 if(mask & BIT(Flag)) { \ 926 log_err(parser, key, \ 927 "the plane parameter `"Name"' is already defined.\n"); \ 928 res = RES_BAD_ARG; \ 929 goto error; \ 930 } \ 931 mask |= BIT(Flag); \ 932 } (void)0 933 934 if(!strcmp((char*)key->data.scalar.value, "clip")) { 935 SETUP_MASK(CLIP, "clip"); 936 res = parse_clip(parser, doc, val, &shape->polyclips); 937 } else if(!strcmp((char*)key->data.scalar.value, "slices")) { 938 SETUP_MASK(SLICES, "slices"); 939 res = parse_integer(parser, val, 1, 4096, &shape->nslices); 940 } else { 941 log_err(parser, key, "unknown plane parameter `%s'.\n", 942 key->data.scalar.value); 943 res = RES_BAD_ARG; 944 goto error; 945 } 946 if(res != RES_OK) { 947 log_node(parser, key); 948 goto error; 949 } 950 #undef SETUP_MASK 951 } 952 if(!(mask & BIT(CLIP))) { 953 log_err(parser, plane, "the plane parameter `clip' is missing.\n"); 954 res = RES_BAD_ARG; 955 goto error; 956 } 957 958 exit: 959 out_ishape->i = ishape; 960 return res; 961 error: 962 if(shape) { 963 darray_plane_pop_back(&parser->planes); 964 ishape = SIZE_MAX; 965 } 966 goto exit; 967 } 968 969 static res_T 970 parse_sphere 971 (struct solparser* parser, 972 yaml_document_t* doc, 973 const yaml_node_t* sphere, 974 struct solparser_shape_sphere_id* out_ishape) 975 { 976 enum { RADIUS, SLICES, STACKS }; 977 struct solparser_shape_sphere* shape = NULL; 978 size_t ishape = SIZE_MAX; 979 intptr_t i, n; 980 int mask = 0; /* Register the parsed attributes */ 981 res_T res = RES_OK; 982 ASSERT(doc && sphere && out_ishape); 983 984 if(sphere->type != YAML_MAPPING_NODE) { 985 log_err(parser, sphere, "expect a mapping of sphere parameters.\n"); 986 res = RES_BAD_ARG; 987 goto error; 988 } 989 990 /* Allocate a shpere shape */ 991 ishape = darray_sphere_size_get(&parser->spheres); 992 res = darray_sphere_resize(&parser->spheres, ishape + 1); 993 if(res != RES_OK) { 994 log_err(parser, sphere, "could not allocate the sphere shape.\n"); 995 goto error; 996 } 997 shape = darray_sphere_data_get(&parser->spheres) + ishape; 998 999 n = sphere->data.mapping.pairs.top - sphere->data.mapping.pairs.start; 1000 shape->nslices = 16; /* default value */ 1001 shape->nstacks = 8; /* initial default value */ 1002 FOR_EACH(i, 0, n) { 1003 yaml_node_t* key; 1004 yaml_node_t* val; 1005 1006 key = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].key); 1007 val = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].value); 1008 if(key->type != YAML_SCALAR_NODE) { 1009 log_err(parser, key, "expect sphere parameters.\n"); 1010 res = RES_BAD_ARG; 1011 goto error; 1012 } 1013 #define SETUP_MASK(Flag, Name) { \ 1014 if(mask & BIT(Flag)) { \ 1015 log_err(parser, key, \ 1016 "the sphere parameter `"Name"' is already defined.\n"); \ 1017 res = RES_BAD_ARG; \ 1018 goto error; \ 1019 } \ 1020 mask |= BIT(Flag); \ 1021 } (void)0 1022 if(!strcmp((char*)key->data.scalar.value, "radius")) { 1023 SETUP_MASK(RADIUS, "radius"); 1024 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->radius); 1025 } else if(!strcmp((char*)key->data.scalar.value, "slices")) { 1026 SETUP_MASK(SLICES, "slices"); 1027 res = parse_integer(parser, val, 4, 4096, &shape->nslices); 1028 if(!(mask & BIT(STACKS))) 1029 shape->nstacks = shape->nslices / 2; /* if unset, new default value */ 1030 } else if(!strcmp((char*)key->data.scalar.value, "stacks")) { 1031 SETUP_MASK(STACKS, "stacks"); 1032 res = parse_integer(parser, val, 2, 4096, &shape->nstacks); 1033 } else { 1034 log_err(parser, key, "unknown sphere parameter `%s'.\n", 1035 key->data.scalar.value); 1036 res = RES_BAD_ARG; 1037 goto error; 1038 } 1039 if(res != RES_OK) { 1040 log_node(parser, key); 1041 goto error; 1042 } 1043 #undef SETUP_MASK 1044 } 1045 1046 #define CHECK_PARAM(Flag, Name) \ 1047 if(!(mask & BIT(Flag))) { \ 1048 log_err(parser, sphere, \ 1049 "the sphere parameter `"Name"' is missing.\n"); \ 1050 res = RES_BAD_ARG; \ 1051 goto error; \ 1052 } (void)0 1053 CHECK_PARAM(RADIUS, "radius"); 1054 #undef CHECK_PARAM 1055 1056 exit: 1057 out_ishape->i = ishape; 1058 return res; 1059 error: 1060 if(shape) { 1061 darray_sphere_pop_back(&parser->spheres); 1062 ishape = SIZE_MAX; 1063 } 1064 goto exit; 1065 } 1066 1067 1068 static res_T 1069 parse_object 1070 (struct solparser* parser, 1071 yaml_document_t* doc, 1072 yaml_node_t* object, 1073 struct solparser_object_id* out_iobj) 1074 { 1075 enum { MATERIAL, SHAPE, TRANSFORM }; 1076 struct solparser_object* obj = NULL; 1077 struct solparser_shape* shape = NULL; 1078 size_t iobj = SIZE_MAX; 1079 size_t ishape = SIZE_MAX; 1080 intptr_t i, n; 1081 int mask = 0; /* Register the parsed attributes */ 1082 res_T res = RES_OK; 1083 ASSERT(doc && object && out_iobj); 1084 1085 if(object->type != YAML_MAPPING_NODE) { 1086 log_err(parser, object, "expect an object definition.\n"); 1087 res = RES_BAD_ARG; 1088 goto error; 1089 } 1090 1091 /* Allocate an object */ 1092 iobj = darray_object_size_get(&parser->objects); 1093 res = darray_object_resize(&parser->objects, iobj + 1); 1094 if(res != RES_OK) { 1095 log_err(parser, object, "could not allocate the object.\n"); 1096 goto error; 1097 } 1098 obj = darray_object_data_get(&parser->objects) + iobj; 1099 1100 /* Allocate a shape */ 1101 ishape = darray_shape_size_get(&parser->shapes); 1102 res = darray_shape_resize(&parser->shapes, ishape + 1); 1103 if(res != RES_OK) { 1104 log_err(parser, object, "could not allocate the object shape.\n"); 1105 goto error; 1106 } 1107 shape = darray_shape_data_get(&parser->shapes) + ishape; 1108 obj->shape.i = ishape; 1109 1110 /* Setup default object transformation */ 1111 d3_splat(obj->translation, 0); 1112 d3_splat(obj->rotation, 0); 1113 1114 n = object->data.mapping.pairs.top - object->data.mapping.pairs.start; 1115 FOR_EACH(i, 0, n) { 1116 yaml_node_t* key; 1117 yaml_node_t* val; 1118 1119 key = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].key); 1120 val = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].value); 1121 if(key->type != YAML_SCALAR_NODE) { 1122 log_err(parser, key, "expect an object parameter.\n"); 1123 res = RES_BAD_ARG; 1124 goto error; 1125 } 1126 1127 #define SETUP_MASK(Flag, Name) { \ 1128 if(mask & BIT(Flag)) { \ 1129 log_err(parser, key, \ 1130 "the object "Name" is already defined.\n"); \ 1131 res = RES_BAD_ARG; \ 1132 goto error; \ 1133 } \ 1134 mask |= BIT(Flag); \ 1135 } (void)0 1136 if(!strcmp((char*)key->data.scalar.value, "material")) { 1137 SETUP_MASK(MATERIAL, "material"); 1138 res = parse_material(parser, doc, val, &obj->mtl2); 1139 } else if(!strcmp((char*)key->data.scalar.value, "cuboid")) { 1140 SETUP_MASK(SHAPE, "shape"); 1141 shape->type = SOLPARSER_SHAPE_CUBOID; 1142 res = parse_cuboid(parser, doc, val, &shape->data.cuboid); 1143 } else if(!strcmp((char*)key->data.scalar.value, "cylinder")) { 1144 SETUP_MASK(SHAPE, "shape"); 1145 shape->type = SOLPARSER_SHAPE_CYLINDER; 1146 res = parse_cylinder(parser, doc, val, &shape->data.cylinder); 1147 } else if(!strcmp((char*)key->data.scalar.value, "obj")) { 1148 SETUP_MASK(SHAPE, "shape"); 1149 shape->type = SOLPARSER_SHAPE_OBJ; 1150 res = parse_imported_geometry 1151 (parser, doc, val, shape->type, &shape->data.obj); 1152 } else if(!strcmp((char*)key->data.scalar.value, "parabol")) { 1153 SETUP_MASK(SHAPE, "shape"); 1154 shape->type = SOLPARSER_SHAPE_PARABOL; 1155 res = parse_paraboloid 1156 (parser, doc, val, shape->type, &shape->data.parabol); 1157 } else if(!strcmp((char*)key->data.scalar.value, "parabolic-cylinder")) { 1158 SETUP_MASK(SHAPE, "shape"); 1159 shape->type = SOLPARSER_SHAPE_PARABOLIC_CYLINDER; 1160 res = parse_paraboloid 1161 (parser, doc, val, shape->type, &shape->data.parabolic_cylinder); 1162 } else if(!strcmp((char*) key->data.scalar.value, "hyperbol")) { 1163 SETUP_MASK(SHAPE, "shape"); 1164 shape->type = SOLPARSER_SHAPE_HYPERBOL; 1165 res = parse_hyperboloid(parser, doc, val, &shape->data.hyperbol); 1166 } 1167 else if(!strcmp((char*)key->data.scalar.value, "hemisphere")) { 1168 SETUP_MASK(SHAPE, "shape"); 1169 shape->type = SOLPARSER_SHAPE_HEMISPHERE; 1170 res = parse_hemisphere(parser, doc, val, &shape->data.hemisphere); 1171 } else if(!strcmp((char*)key->data.scalar.value, "plane")) { 1172 SETUP_MASK(SHAPE, "shape"); 1173 shape->type = SOLPARSER_SHAPE_PLANE; 1174 res = parse_plane(parser, doc, val, &shape->data.plane); 1175 } else if(!strcmp((char*)key->data.scalar.value, "sphere")) { 1176 SETUP_MASK(SHAPE, "shape"); 1177 shape->type = SOLPARSER_SHAPE_SPHERE; 1178 res = parse_sphere(parser, doc, val, &shape->data.sphere); 1179 } else if(!strcmp((char*)key->data.scalar.value, "stl")) { 1180 SETUP_MASK(SHAPE, "shape"); 1181 shape->type = SOLPARSER_SHAPE_STL; 1182 res = parse_imported_geometry 1183 (parser, doc, val, shape->type, &shape->data.stl); 1184 } else if(!strcmp((char*)key->data.scalar.value, "transform")) { 1185 SETUP_MASK(TRANSFORM, "transform"); 1186 res = parse_transform(parser, doc, val, obj->translation, obj->rotation); 1187 } else { 1188 log_err(parser, key, "unknown object parameter `%s'.\n", 1189 key->data.scalar.value); 1190 res = RES_BAD_ARG; 1191 goto error; 1192 } 1193 if(res != RES_OK) { 1194 log_node(parser, key); 1195 goto error; 1196 } 1197 #undef SETUP_MASK 1198 } 1199 1200 #define CHECK_PARAM(Flag, Name) \ 1201 if(!(mask & BIT(Flag))) { \ 1202 log_err(parser, object, "the object "Name" is missing.\n"); \ 1203 res = RES_BAD_ARG; \ 1204 goto error; \ 1205 } (void)0 1206 CHECK_PARAM(MATERIAL, "material"); 1207 CHECK_PARAM(SHAPE, "shape"); 1208 #undef CHECK_PARAM 1209 1210 exit: 1211 out_iobj->i = iobj; 1212 return res; 1213 error: 1214 if(obj) { 1215 if(shape) darray_shape_pop_back(&parser->shapes); 1216 darray_object_pop_back(&parser->objects); 1217 obj = NULL; 1218 } 1219 goto exit; 1220 } 1221 1222 /******************************************************************************* 1223 * Local functions 1224 ******************************************************************************/ 1225 res_T 1226 parse_focals_description 1227 (struct solparser* parser, 1228 yaml_document_t* doc, 1229 const yaml_node_t* desc, 1230 struct solparser_hyperboloid_focals* focals) 1231 { 1232 enum { REAL, IMAGE }; 1233 intptr_t i, n; 1234 int mask = 0; /* Register the parsed attributes */ 1235 res_T res = RES_OK; 1236 ASSERT(doc && desc && focals); 1237 1238 if(desc->type != YAML_MAPPING_NODE) { 1239 log_err(parser, desc, "expect a mapping of focal parameters.\n"); 1240 res = RES_BAD_ARG; 1241 goto error; 1242 } 1243 1244 n = desc->data.mapping.pairs.top - desc->data.mapping.pairs.start; 1245 FOR_EACH(i, 0, n) { 1246 yaml_node_t* key; 1247 yaml_node_t* val; 1248 1249 key = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].key); 1250 val = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].value); 1251 if(key->type != YAML_SCALAR_NODE) { 1252 log_err(parser, key, "expect focal parameters.\n"); 1253 res = RES_BAD_ARG; 1254 goto error; 1255 } 1256 #define SETUP_MASK(Flag, Name) { \ 1257 if(mask & BIT(Flag)) { \ 1258 log_err(parser, key, \ 1259 "the focal parameter `"Name"' is already defined.\n"); \ 1260 res = RES_BAD_ARG; \ 1261 goto error; \ 1262 } \ 1263 mask |= BIT(Flag); \ 1264 } (void)0 1265 if(!strcmp((char*) key->data.scalar.value, "real")) { 1266 SETUP_MASK(REAL, "real"); 1267 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->real); 1268 } else if(!strcmp((char*) key->data.scalar.value, "image")) { 1269 SETUP_MASK(IMAGE, "image"); 1270 res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->image); 1271 } 1272 if(res != RES_OK) { 1273 log_node(parser, key); 1274 goto error; 1275 } 1276 } 1277 #undef SETUP_MASK 1278 #define CHECK_PARAM(Flag, Name) \ 1279 if(!(mask & BIT(Flag))) { \ 1280 log_err(parser, desc, \ 1281 "the focal parameter `"Name"' is missing.\n"); \ 1282 res = RES_BAD_ARG; \ 1283 goto error; \ 1284 } (void)0 1285 CHECK_PARAM(REAL, "real"); 1286 CHECK_PARAM(IMAGE, "image"); 1287 #undef CHECK_PARAM 1288 1289 exit: 1290 return res; 1291 error: 1292 goto exit; 1293 } 1294 1295 res_T 1296 parse_geometry 1297 (struct solparser* parser, 1298 yaml_document_t* doc, 1299 yaml_node_t* geometry, 1300 struct solparser_geometry_id* out_isolgeom) 1301 { 1302 struct solparser_geometry* solgeom = NULL; 1303 size_t* pisolgeom; 1304 size_t isolgeom = SIZE_MAX; 1305 intptr_t i, n; 1306 res_T res = RES_OK; 1307 ASSERT(doc && geometry && out_isolgeom); 1308 1309 if(geometry->type != YAML_SEQUENCE_NODE) { 1310 log_err(parser, geometry, "expect a list of objects.\n"); 1311 res = RES_BAD_ARG; 1312 goto error; 1313 } 1314 1315 /* Check whether or not the YAML descriptor alias an already created Solstice 1316 * geometry */ 1317 pisolgeom = htable_yaml2sols_find(&parser->yaml2geoms, &geometry); 1318 if(pisolgeom) { 1319 isolgeom = *pisolgeom; 1320 goto exit; 1321 } 1322 1323 /* Allocate the geometry */ 1324 isolgeom = darray_geometry_size_get(&parser->geometries); 1325 res = darray_geometry_resize(&parser->geometries, isolgeom + 1); 1326 if(res != RES_OK) { 1327 log_err(parser, geometry, "could not allocate the geometry.\n"); 1328 goto error; 1329 } 1330 solgeom = darray_geometry_data_get(&parser->geometries) + isolgeom; 1331 1332 n = geometry->data.sequence.items.top - geometry->data.sequence.items.start; 1333 res = darray_object_id_resize(&solgeom->objects, (size_t)n); 1334 if(res != RES_OK) { 1335 log_err(parser, geometry, "could not allocate the objects list.\n"); 1336 goto error; 1337 } 1338 1339 FOR_EACH(i, 0, n) { 1340 struct solparser_object_id* obj_id; 1341 yaml_node_t* obj; 1342 1343 obj_id = darray_object_id_data_get(&solgeom->objects) + i; 1344 obj = yaml_document_get_node(doc, geometry->data.sequence.items.start[i]); 1345 res = parse_object(parser, doc, obj, obj_id); 1346 if(res != RES_OK) goto error; 1347 } 1348 1349 /* Cache the geometry */ 1350 res = htable_yaml2sols_set(&parser->yaml2geoms, &geometry, &isolgeom); 1351 if(res != RES_OK) { 1352 log_err(parser, geometry, "could not register the geometry.\n"); 1353 goto error; 1354 } 1355 1356 exit: 1357 out_isolgeom->i = isolgeom; 1358 return res; 1359 error: 1360 if(solgeom) { 1361 darray_geometry_pop_back(&parser->geometries); 1362 isolgeom = SIZE_MAX; 1363 } 1364 goto exit; 1365 } 1366 1367 1368