sg2_geometry.c (30977B)
1 /* Copyright (C) 2019, 2020, 2023 |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 "sg2.h" 17 #include "sg2d_geometry.h" 18 #include "sg2d_device.h" 19 20 #include <rsys/double2.h> 21 22 #include <limits.h> 23 24 /******************************************************************************* 25 * Helper functions 26 ******************************************************************************/ 27 static void 28 geometry_release(ref_T* ref) 29 { 30 struct sg2d_geometry* geom; 31 struct sg2d_device* dev; 32 ASSERT(ref); 33 geom = CONTAINER_OF(ref, struct sg2d_geometry, ref); 34 dev = geom->dev; 35 darray_segment_release(&geom->unique_segments); 36 darray_vertex_release(&geom->unique_vertices); 37 htable_seg_release(&geom->unique_segments_ids); 38 htable_vrtx_release(&geom->unique_vertices_ids); 39 darray_seg_descriptions_release(&geom->seg_descriptions); 40 MEM_RM(dev->allocator, geom); 41 SG2(device_ref_put(dev)); 42 } 43 44 static FINLINE int /* Return 1 if reversed */ 45 seg_make_key(struct unsigned2* k, const unsigned t[2]) 46 { 47 ASSERT(t); 48 ASSERT(t[0] != t[1]); 49 if(t[0] < t[1]) { 50 k->x[0] = t[0]; 51 k->x[1] = t[1]; 52 return 0; 53 } else { 54 k->x[0] = t[1]; 55 k->x[1] = t[0]; 56 return 1; 57 } 58 } 59 60 static void 61 dump_seg_property 62 (const struct sg2d_geometry* geom, 63 FILE* stream, 64 const enum sg2d_property_type type) 65 { 66 size_t i; 67 const struct seg_descriptions* descriptions; 68 ASSERT(geom && stream && type < SG2D_PROP_TYPES_COUNT__); 69 70 descriptions 71 = darray_seg_descriptions_cdata_get(&geom->seg_descriptions); 72 FOR_EACH(i, 0, darray_segment_size_get(&geom->unique_segments)) { 73 unsigned property = SG2D_UNSPECIFIED_PROPERTY; 74 size_t tdefs_count 75 = darray_definition_size_get(&descriptions[i].defs[type]); 76 if(tdefs_count && descriptions[i].property_defined[type]) { 77 const struct definition* tdefs 78 = darray_definition_cdata_get(&descriptions[i].defs[type]); 79 size_t j; 80 FOR_EACH(j, 0, tdefs_count) { 81 if(tdefs->property_value != SG2D_UNSPECIFIED_PROPERTY) { 82 property = tdefs->property_value; 83 break; /* Found the defined value */ 84 } 85 tdefs++; /* Next value */ 86 } 87 } 88 /* In VTK dumps INT_MAX is used for both unspecified and conflict */ 89 fprintf(stream, "%u\n", MMIN(property, INT_MAX)); 90 } 91 } 92 93 /******************************************************************************* 94 * Local functions 95 ******************************************************************************/ 96 res_T 97 geometry_register_segment 98 (struct sg2d_geometry* geom, 99 const struct segment* segment, 100 const unsigned segment_unique_id, 101 const unsigned set_id, 102 const int merge_conflict) 103 { 104 res_T res = RES_OK; 105 struct seg_descriptions* seg_d; 106 int i; 107 char keep_prop_def[SG2D_PROP_TYPES_COUNT__]; 108 109 ASSERT(geom && segment); 110 111 ERR(geometry_enlarge_seg_descriptions(geom, segment_unique_id + 1)); 112 seg_d = (darray_seg_descriptions_data_get(&geom->seg_descriptions) 113 + segment_unique_id); 114 /* Record information */ 115 FOR_EACH(i, 0, SG2D_PROP_TYPES_COUNT__) { 116 struct darray_definition* definitions; 117 struct definition* defs; 118 int done = 0; 119 size_t j; 120 keep_prop_def[i] = seg_d->property_defined[i]; 121 if(segment->properties[i] == SG2D_UNSPECIFIED_PROPERTY) 122 seg_d->defs_include_unspecified = 1; 123 else seg_d->property_defined[i] = 1; 124 definitions = seg_d->defs + i; 125 defs = darray_definition_data_get(definitions); 126 FOR_EACH(j, 0, darray_definition_size_get(definitions)) { 127 if(defs[j].property_value == segment->properties[i]) { 128 /* This property_value is already registered: no conflict */ 129 const unsigned* ids = darray_uint_cdata_get(&defs[j].set_ids); 130 size_t k; 131 /* Search if property_value already includes set_id */ 132 FOR_EACH(k, 0, darray_uint_size_get(&defs[j].set_ids)) { 133 if(ids[k] == set_id) { 134 /* Same value+set_id was there already */ 135 done = 1; 136 break; 137 } 138 } 139 if(!done) { 140 /* Need to add the set_id for this property_value */ 141 ERR(darray_uint_push_back(&defs[j].set_ids, &set_id)); 142 done = 1; 143 } 144 break; 145 } 146 } 147 if(!done) { 148 /* This property_value was not recorded already */ 149 size_t defs_sz = darray_definition_size_get(definitions); 150 struct definition* new_def; 151 ERR(darray_definition_resize(definitions, 1 + defs_sz)); 152 new_def = darray_definition_data_get(definitions) + defs_sz; 153 ERR(darray_uint_push_back(&new_def->set_ids, &set_id)); 154 new_def->property_value = segment->properties[i]; 155 if(!seg_d->merge_conflict && merge_conflict) { 156 /* If more than 1 merge_conflict occur, the first one remains */ 157 seg_d->merge_conflict = merge_conflict; 158 geom->merge_conflict_count++; 159 } 160 } 161 } 162 163 if((!keep_prop_def[SG2D_FRONT] || !keep_prop_def[SG2D_BACK]) 164 && seg_d->property_defined[SG2D_FRONT] && seg_d->property_defined[SG2D_BACK]) 165 { 166 /* Both sides are now defined */ 167 ASSERT(geom->seg_with_unspecified_sides_count > 0); 168 geom->seg_with_unspecified_sides_count--; 169 } 170 171 if(!keep_prop_def[SG2D_INTFACE] && seg_d->property_defined[SG2D_INTFACE]) { 172 /* Interface is now defined */ 173 ASSERT(geom->seg_with_unspecified_intface_count > 0); 174 geom->seg_with_unspecified_intface_count--; 175 } 176 177 exit: 178 return res; 179 error: 180 goto exit; 181 } 182 183 res_T 184 geometry_enlarge_seg_descriptions 185 (struct sg2d_geometry* geom, 186 const seg_id_t sz) 187 { 188 res_T res = RES_OK; 189 size_t old_sz = 190 darray_seg_descriptions_size_get(&geom->seg_descriptions); 191 if(sz <= old_sz) return RES_OK; 192 ERR(darray_seg_descriptions_resize(&geom->seg_descriptions, sz)); 193 ASSERT(geom->seg_with_unspecified_sides_count + sz - old_sz <= SEG_MAX__); 194 ASSERT(geom->seg_with_unspecified_intface_count + sz - old_sz <= SEG_MAX__); 195 geom->seg_with_unspecified_sides_count += (seg_id_t)(sz - old_sz); 196 geom->seg_with_unspecified_intface_count += (seg_id_t)(sz - old_sz); 197 198 exit: 199 return res; 200 error: 201 goto exit; 202 } 203 204 static void 205 dump_partition 206 (const struct sg2d_geometry* geom, 207 FILE* stream, 208 const char* group_name, 209 enum sg2d_obj_dump_content partition) 210 { 211 const struct seg_descriptions* seg_descriptions; 212 const struct segment* segments; 213 size_t sz, i; 214 ASSERT(geom && stream && group_name); 215 ASSERT(partition == SG2D_OBJ_DUMP_MERGE_CONFLICTS 216 || partition == SG2D_OBJ_DUMP_PROPERTY_CONFLICTS 217 || partition == SG2D_OBJ_DUMP_VALID_PRIMITIVE); 218 seg_descriptions 219 = darray_seg_descriptions_cdata_get(&geom->seg_descriptions); 220 sz = darray_seg_descriptions_size_get(&geom->seg_descriptions); 221 segments = darray_segment_cdata_get(&geom->unique_segments); 222 fprintf(stream, "g %s\n", group_name); 223 FOR_EACH(i, 0, sz) { 224 int dump; 225 if(partition == SG2D_OBJ_DUMP_VALID_PRIMITIVE) 226 dump = !(seg_descriptions[i].merge_conflict 227 || seg_descriptions[i].properties_conflict); 228 else if(partition == SG2D_OBJ_DUMP_MERGE_CONFLICTS) 229 dump = seg_descriptions[i].merge_conflict; 230 else { 231 ASSERT(partition == SG2D_OBJ_DUMP_PROPERTY_CONFLICTS); 232 dump = seg_descriptions[i].properties_conflict; 233 } 234 if(!dump) continue; 235 fprintf(stream, "l %u %u\n", 236 /* OBJ indexing starts at 1 */ 237 1 + segments[i].vertex_ids[0], 238 1 + segments[i].vertex_ids[1]); 239 } 240 } 241 242 /******************************************************************************* 243 * Exported functions 244 ******************************************************************************/ 245 res_T 246 sg2d_geometry_create 247 (struct sg2d_device* dev, 248 struct sg2d_geometry** out_geometry) 249 { 250 struct sg2d_geometry* geom = NULL; 251 res_T res = RES_OK; 252 253 if(!dev || !out_geometry) { 254 res = RES_BAD_ARG; 255 goto error; 256 } 257 258 geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct sg2d_geometry)); 259 if(!geom) { 260 log_err(dev, 261 "%s: could not allocate the sg2.\n", FUNC_NAME); 262 res = RES_MEM_ERR; 263 goto error; 264 } 265 266 SG2(device_ref_get(dev)); 267 darray_segment_init(dev->allocator, &geom->unique_segments); 268 darray_vertex_init(dev->allocator, &geom->unique_vertices); 269 htable_seg_init(dev->allocator, &geom->unique_segments_ids); 270 htable_vrtx_init(dev->allocator, &geom->unique_vertices_ids); 271 darray_seg_descriptions_init(dev->allocator, &geom->seg_descriptions); 272 geom->segment_count_including_duplicates = 0; 273 geom->sides_with_defined_medium_count = 0; 274 geom->set_id = 0; 275 geom->seg_with_unspecified_sides_count = 0; 276 geom->seg_with_unspecified_intface_count = 0; 277 geom->merge_conflict_count = 0; 278 geom->properties_conflict_count = 0; 279 geom->dev = dev; 280 281 ref_init(&geom->ref); 282 283 exit: 284 if(out_geometry) *out_geometry = geom; 285 return res; 286 error: 287 if(geom) { 288 SG2(geometry_ref_put(geom)); 289 geom = NULL; 290 } 291 goto exit; 292 } 293 294 res_T 295 sg2d_geometry_reserve 296 (struct sg2d_geometry* geom, 297 const unsigned vertices_count, 298 const unsigned segments_count, 299 const unsigned properties_count) 300 { 301 res_T res = RES_OK; 302 if(!geom) return RES_BAD_ARG; 303 304 ERR(darray_segment_reserve(&geom->unique_segments, segments_count)); 305 ERR(darray_vertex_reserve(&geom->unique_vertices, vertices_count)); 306 ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, vertices_count)); 307 ERR(htable_seg_reserve(&geom->unique_segments_ids, segments_count)); 308 ERR(darray_seg_descriptions_reserve(&geom->seg_descriptions, 309 properties_count)); 310 311 end: 312 return res; 313 error: 314 goto end; 315 } 316 317 res_T 318 sg2d_geometry_add 319 (struct sg2d_geometry* geom, 320 const unsigned nverts, 321 const unsigned nsegs, 322 const struct sg2d_geometry_add_callbacks* callbacks, 323 void* ctx) /* Can be NULL */ 324 { 325 res_T res = RES_OK; 326 struct mem_allocator* alloc; 327 size_t nuseg, nuverts; 328 unsigned i, n_new_uverts = 0, n_new_utris = 0; 329 struct segment* seg; 330 /* Tmp table of IDs to record unique IDs of the currently added vertices */ 331 struct darray_uint unique_vertice_ids; 332 int unique_vertice_ids_initialized = 0; 333 334 if(!geom || !callbacks || !callbacks->get_indices || !callbacks->get_position) 335 { 336 res = RES_BAD_ARG; 337 goto error; 338 } 339 340 alloc = geom->dev->allocator; 341 nuverts = darray_vertex_size_get(&geom->unique_vertices); 342 nuseg = darray_segment_size_get(&geom->unique_segments); 343 344 /* Make room for new geometry; suppose no more duplicates */ 345 darray_uint_init(alloc, &unique_vertice_ids); 346 unique_vertice_ids_initialized = 1; 347 ERR(darray_uint_reserve(&unique_vertice_ids, nverts)); 348 ERR(darray_vertex_reserve(&geom->unique_vertices, nuverts + nverts)); 349 ERR(darray_segment_reserve(&geom->unique_segments, nuseg + nsegs)); 350 ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, nuverts + nverts)); 351 ERR(htable_seg_reserve(&geom->unique_segments_ids, nuseg + nsegs)); 352 ASSERT(nuseg == darray_seg_descriptions_size_get(&geom->seg_descriptions)); 353 ERR(darray_seg_descriptions_reserve(&geom->seg_descriptions, nuseg + nsegs)); 354 /* Get vertices and deduplicate */ 355 FOR_EACH(i, 0, nverts) { 356 unsigned* p_vrtx; 357 struct vertex tmp; 358 unsigned v_idx; 359 callbacks->get_position(i, tmp.coord, ctx); 360 p_vrtx = htable_vrtx_find(&geom->unique_vertices_ids, &tmp); 361 if(p_vrtx) { 362 /* Duplicate vertex */ 363 v_idx = *p_vrtx; 364 } else { 365 /* New vertex */ 366 ASSERT(nuverts + n_new_uverts <= UINT_MAX); 367 v_idx = (unsigned)(nuverts + n_new_uverts); 368 ASSERT(v_idx == htable_vrtx_size_get(&geom->unique_vertices_ids)); 369 ERR(darray_vertex_push_back(&geom->unique_vertices, &tmp)); 370 ERR(htable_vrtx_set(&geom->unique_vertices_ids, &tmp, &v_idx)); 371 ++n_new_uverts; 372 } 373 /* Keep the unique ID for vertex i */ 374 ERR(darray_uint_push_back(&unique_vertice_ids, &v_idx)); 375 } 376 377 /* Get segments and deduplicate */ 378 seg = darray_segment_data_get(&geom->unique_segments); 379 FOR_EACH(i, 0, nsegs) { 380 int j, reversed; 381 struct unsigned2 seg_key; 382 struct segment tmp = SEG_UNDEF__; 383 unsigned* p_seg; 384 struct seg_descriptions* seg_descriptions = NULL; 385 unsigned unique_id; 386 387 callbacks->get_indices(i, tmp.vertex_ids, ctx); 388 FOR_EACH(j, 0, 2) { 389 if(tmp.vertex_ids[j] >= nverts) { 390 res = RES_BAD_ARG; 391 goto error; 392 } 393 /* Replace the vertex ID by its the unique ID */ 394 tmp.vertex_ids[j] 395 = darray_uint_cdata_get(&unique_vertice_ids)[tmp.vertex_ids[j]]; 396 } 397 if(tmp.vertex_ids[0] == tmp.vertex_ids[1]) { 398 int abort = 0; 399 if(callbacks->degenerated_segment) { 400 /* Let the client app rule. */ 401 ERR(callbacks->degenerated_segment(i, ctx, &abort)); 402 } else { 403 log_warn(geom->dev, "%s: segment %u is degenerated.\n", 404 FUNC_NAME, i); 405 } 406 if(abort) { 407 res = RES_BAD_ARG; 408 goto error; 409 } 410 else continue; 411 } 412 /* Get properties */ 413 if(callbacks->get_properties) 414 callbacks->get_properties(i, tmp.properties, ctx); 415 /* Find duplicate segments */ 416 reversed = seg_make_key(&seg_key, tmp.vertex_ids); 417 p_seg = htable_seg_find(&geom->unique_segments_ids, &seg_key); 418 if(p_seg) { 419 /* Duplicate segment. Need to check duplicate validity */ 420 struct unsigned2 useg_key; 421 int ureversed = seg_make_key(&useg_key, seg[*p_seg].vertex_ids); 422 int same = (reversed == ureversed); 423 int already_conflict; 424 ASSERT(seg_key_eq(&seg_key, &useg_key)); 425 unique_id = *p_seg; 426 ERR(geometry_enlarge_seg_descriptions(geom, 1 + unique_id)); 427 seg_descriptions 428 = darray_seg_descriptions_data_get(&geom->seg_descriptions); 429 if(!same) 430 SWAP(unsigned, tmp.properties[SG2D_FRONT], tmp.properties[SG2D_BACK]); 431 already_conflict = seg_descriptions[i].merge_conflict; 432 if(callbacks->merge_segment) { 433 /* Let the client app rule. */ 434 ERR(callbacks->merge_segment(*p_seg, i, !same, seg[*p_seg].properties, 435 tmp.properties, ctx, &seg_descriptions[i].merge_conflict)); 436 } else { 437 FOR_EACH(j, 0, SG2D_PROP_TYPES_COUNT__) { 438 if(!sg2d_compatible_property(seg[*p_seg].properties[j], 439 tmp.properties[j])) 440 { 441 seg_descriptions[i].merge_conflict = 1; 442 break; 443 } 444 } 445 } 446 if(seg_descriptions[i].merge_conflict && !already_conflict) 447 geom->merge_conflict_count++; 448 /* Replace SG2D_UNSPECIFIED_PROPERTY properties */ 449 FOR_EACH(j, 0, SG2D_PROP_TYPES_COUNT__) { 450 if(seg[*p_seg].properties[j] == SG2D_UNSPECIFIED_PROPERTY 451 && tmp.properties[j] != SG2D_UNSPECIFIED_PROPERTY) { 452 seg[*p_seg].properties[j] = tmp.properties[j]; 453 if(j == SG2D_FRONT || j == SG2D_BACK) 454 geom->sides_with_defined_medium_count++; 455 } 456 } 457 } else { 458 /* New segment */ 459 ASSERT(nuseg + n_new_utris <= UINT_MAX); 460 unique_id = (unsigned)(nuseg + n_new_utris); 461 tmp.user_id = geom->segment_count_including_duplicates + i; 462 if(callbacks->add_segment) 463 ERR(callbacks->add_segment(unique_id, i, ctx)); 464 ERR(geometry_enlarge_seg_descriptions(geom, 1 + unique_id)); 465 seg_descriptions 466 = darray_seg_descriptions_data_get(&geom->seg_descriptions); 467 ERR(darray_segment_push_back(&geom->unique_segments, &tmp)); 468 FOR_EACH(j, 0, SG2D_PROP_TYPES_COUNT__) { 469 if((j == SG2D_FRONT || j == SG2D_BACK) 470 && tmp.properties[j] != SG2D_UNSPECIFIED_PROPERTY) 471 geom->sides_with_defined_medium_count++; 472 } 473 ASSERT(unique_id == htable_seg_size_get(&geom->unique_segments_ids)); 474 ERR(htable_seg_set(&geom->unique_segments_ids, &seg_key, &unique_id)); 475 n_new_utris++; 476 } 477 ERR(geometry_register_segment(geom, &tmp, unique_id, geom->set_id, 478 seg_descriptions[i].properties_conflict)); 479 if(seg_descriptions[i].properties_conflict) 480 geom->merge_conflict_count++; 481 } 482 483 ASSERT(nuverts + n_new_uverts 484 == htable_vrtx_size_get(&geom->unique_vertices_ids)); 485 ASSERT(nuseg + n_new_utris 486 == htable_seg_size_get(&geom->unique_segments_ids)); 487 exit: 488 if(geom) { 489 geom->set_id++; 490 geom->segment_count_including_duplicates += nsegs; 491 } 492 if(unique_vertice_ids_initialized) 493 darray_uint_release(&unique_vertice_ids); 494 return res; 495 error: 496 goto exit; 497 } 498 499 res_T 500 sg2d_geometry_validate_properties 501 (struct sg2d_geometry* geom, 502 res_T(*validate)(const unsigned, const unsigned*, void*, int*), 503 void* ctx) 504 { 505 size_t sz__; 506 unsigned i, sz; 507 struct seg_descriptions* seg_descriptions; 508 res_T res = RES_OK; 509 510 if(!geom || !validate) { 511 res = RES_BAD_ARG; 512 goto error; 513 } 514 515 sz__ = darray_seg_descriptions_size_get(&geom->seg_descriptions); 516 ASSERT(sz__ <= UINT_MAX); 517 sz = (unsigned)sz__; 518 seg_descriptions 519 = darray_seg_descriptions_data_get(&geom->seg_descriptions); 520 geom->properties_conflict_count = 0; /* Reset count */ 521 FOR_EACH(i, 0, sz) { 522 unsigned p, j; 523 unsigned props[SG2D_PROP_TYPES_COUNT__]; 524 struct seg_descriptions* segd = seg_descriptions + i; 525 /* Validate only segment not flagged with merge_conflict */ 526 if(segd->merge_conflict) { 527 segd->properties_conflict = 0; 528 continue; 529 } 530 /* Get properties for non-conflict segments */ 531 FOR_EACH(p, 0, SG2D_PROP_TYPES_COUNT__) { 532 const struct definition* defs = darray_definition_cdata_get(segd->defs + p); 533 props[p] = SG2D_UNSPECIFIED_PROPERTY; 534 FOR_EACH(j, 0, darray_definition_size_get(segd->defs + p)) { 535 if(defs[j].property_value != SG2D_UNSPECIFIED_PROPERTY) { 536 props[p] = defs[j].property_value; 537 break; 538 } 539 } 540 } 541 /* Call validation */ 542 ERR(validate(i, props, ctx, &segd->properties_conflict)); 543 if(segd->properties_conflict) 544 geom->properties_conflict_count++; 545 } 546 547 exit: 548 return res; 549 error: 550 goto exit; 551 } 552 553 res_T 554 sg2d_geometry_get_unique_vertices_count 555 (const struct sg2d_geometry* geom, 556 unsigned* count) 557 { 558 res_T res = RES_OK; 559 size_t sz; 560 if(!geom || !count) { 561 res = RES_BAD_ARG; 562 goto error; 563 } 564 sz = darray_vertex_size_get(&geom->unique_vertices); 565 ASSERT(sz <= UINT_MAX); 566 *count = (unsigned)sz; 567 exit: 568 return res; 569 error: 570 goto exit; 571 } 572 573 res_T 574 sg2d_geometry_get_unique_vertex 575 (const struct sg2d_geometry* geom, 576 const unsigned ivtx, 577 double coord[2]) 578 { 579 res_T res = RES_OK; 580 const struct vertex* vertices; 581 if(!geom || !coord 582 || ivtx >= darray_vertex_size_get(&geom->unique_vertices)) 583 { 584 res = RES_BAD_ARG; 585 goto error; 586 } 587 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 588 d2_set(coord, vertices[ivtx].coord); 589 exit: 590 return res; 591 error: 592 goto exit; 593 } 594 595 res_T 596 sg2d_geometry_get_added_segments_count 597 (const struct sg2d_geometry* geom, 598 unsigned* count) 599 { 600 res_T res = RES_OK; 601 if (!geom || !count) { 602 res = RES_BAD_ARG; 603 goto error; 604 } 605 *count = geom->segment_count_including_duplicates; 606 exit: 607 return res; 608 error: 609 goto exit; 610 } 611 612 res_T 613 sg2d_geometry_get_unique_segments_count 614 (const struct sg2d_geometry* geom, 615 unsigned* count) 616 { 617 res_T res = RES_OK; 618 size_t sz; 619 if(!geom || !count) { 620 res = RES_BAD_ARG; 621 goto error; 622 } 623 sz = darray_segment_size_get(&geom->unique_segments); 624 ASSERT(sz <= UINT_MAX); 625 *count = (unsigned)sz; 626 exit: 627 return res; 628 error: 629 goto exit; 630 } 631 632 res_T 633 sg2d_geometry_get_unique_segment_vertices 634 (const struct sg2d_geometry* geom, 635 const unsigned iseg, 636 unsigned indices[2]) 637 { 638 res_T res = RES_OK; 639 const struct segment* segments; 640 size_t i; 641 if(!geom || !indices 642 || iseg >= darray_segment_size_get(&geom->unique_segments)) 643 { 644 res = RES_BAD_ARG; 645 goto error; 646 } 647 segments = darray_segment_cdata_get(&geom->unique_segments); 648 FOR_EACH(i, 0, 2) indices[i] = segments[iseg].vertex_ids[i]; 649 exit: 650 return res; 651 error: 652 goto exit; 653 } 654 655 res_T 656 sg2d_geometry_get_unique_segment_properties 657 (const struct sg2d_geometry* geom, 658 const unsigned iseg, 659 unsigned properties[SG2D_PROP_TYPES_COUNT__]) 660 { 661 res_T res = RES_OK; 662 const struct segment* segments; 663 size_t i; 664 if(!geom || !properties 665 || iseg >= darray_segment_size_get(&geom->unique_segments)) 666 { 667 res = RES_BAD_ARG; 668 goto error; 669 } 670 segments = darray_segment_cdata_get(&geom->unique_segments); 671 FOR_EACH(i, 0, SG2D_PROP_TYPES_COUNT__) 672 properties[i] = segments[iseg].properties[i]; 673 exit: 674 return res; 675 error: 676 goto exit; 677 } 678 679 res_T 680 sg2d_geometry_get_unique_segment_user_id 681 (const struct sg2d_geometry* geom, 682 const unsigned iseg, 683 unsigned* user_id) 684 { 685 res_T res = RES_OK; 686 const struct segment* segments; 687 if(!geom || !user_id 688 || iseg >= darray_segment_size_get(&geom->unique_segments)) 689 { 690 res = RES_BAD_ARG; 691 goto error; 692 } 693 segments = darray_segment_cdata_get(&geom->unique_segments); 694 *user_id = segments[iseg].user_id; 695 exit: 696 return res; 697 error: 698 goto exit; 699 } 700 701 res_T 702 sg2d_geometry_get_unique_segments_with_unspecified_side_count 703 (const struct sg2d_geometry* geom, 704 unsigned* count) 705 { 706 res_T res = RES_OK; 707 if(!geom || !count) { 708 res = RES_BAD_ARG; 709 goto error; 710 } 711 *count = geom->seg_with_unspecified_sides_count; 712 exit: 713 return res; 714 error: 715 goto exit; 716 } 717 718 res_T 719 sg2d_geometry_get_unique_segments_with_unspecified_interface_count 720 (const struct sg2d_geometry* geom, 721 unsigned* count) 722 { 723 res_T res = RES_OK; 724 if(!geom || !count) { 725 res = RES_BAD_ARG; 726 goto error; 727 } 728 *count = geom->seg_with_unspecified_intface_count; 729 exit: 730 return res; 731 error: 732 goto exit; 733 } 734 735 res_T 736 sg2d_geometry_get_unique_segments_with_merge_conflict_count 737 (const struct sg2d_geometry* geom, 738 unsigned* count) 739 { 740 res_T res = RES_OK; 741 if(!geom || !count) { 742 res = RES_BAD_ARG; 743 goto error; 744 } 745 *count = geom->merge_conflict_count; 746 exit: 747 return res; 748 error: 749 goto exit; 750 } 751 752 res_T 753 sg2d_geometry_get_unique_segments_with_properties_conflict_count 754 (const struct sg2d_geometry* geom, 755 unsigned* count) 756 { 757 res_T res = RES_OK; 758 if(!geom || !count) { 759 res = RES_BAD_ARG; 760 goto error; 761 } 762 *count = geom->properties_conflict_count; 763 exit: 764 return res; 765 error: 766 goto exit; 767 } 768 769 res_T 770 sg2d_geometry_dump_as_obj 771 (const struct sg2d_geometry* geom, 772 FILE* stream, 773 const int flags) 774 { 775 res_T res = RES_OK; 776 const struct vertex* vertices; 777 size_t vsz, tsz, i; 778 if(!geom || !stream || !flags 779 || !geom->segment_count_including_duplicates) 780 { 781 if(geom && !geom->segment_count_including_duplicates) 782 log_err(geom->dev, 783 "%s: cannot dump empty geometries as OBJ\n", 784 FUNC_NAME); 785 res = RES_BAD_ARG; 786 goto error; 787 } 788 /* Headers */ 789 fprintf(stream, "# Dump of star-geometry-2D\n"); 790 fprintf(stream, "# Geometry counts:\n"); 791 vsz = darray_vertex_size_get(&geom->unique_vertices); 792 ASSERT(vsz <= UINT_MAX); 793 fprintf(stream, "# . %u vertices\n", (unsigned)vsz); 794 tsz = darray_segment_size_get(&geom->unique_segments); 795 ASSERT(tsz <= UINT_MAX); 796 fprintf(stream, "# . %u segments\n", (unsigned)tsz); 797 fprintf(stream, 798 "# . %u segments flagged with a merge conflict\n", 799 geom->merge_conflict_count); 800 fprintf(stream, 801 "# . %u segments flagged with a property conflict\n", 802 geom->merge_conflict_count); 803 804 /* Dump vertices */ 805 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 806 FOR_EACH(i, 0, vsz) 807 fprintf(stream, "v %g %g 0\n", SPLIT2(vertices[i].coord)); 808 809 /* Dump segments by groups */ 810 dump_partition(geom, stream, "Valid_segments", SG2D_OBJ_DUMP_VALID_PRIMITIVE); 811 dump_partition(geom, stream, "Merge_conflicts", SG2D_OBJ_DUMP_MERGE_CONFLICTS); 812 dump_partition(geom, stream, "Property_conflicts", SG2D_OBJ_DUMP_PROPERTY_CONFLICTS); 813 814 exit: 815 return res; 816 error: 817 goto exit; 818 } 819 820 res_T 821 sg2d_geometry_dump_as_vtk 822 (const struct sg2d_geometry* geom, 823 FILE* stream) 824 { 825 res_T res = RES_OK; 826 const struct vertex* vertices; 827 const struct segment* segments; 828 const struct seg_descriptions* descriptions; 829 size_t vsz, tsz, i; 830 if(!geom || !stream || !geom->segment_count_including_duplicates) { 831 if(geom && !geom->segment_count_including_duplicates) 832 log_err(geom->dev, 833 "%s: cannot dump empty geometries as VTK\n", 834 FUNC_NAME); 835 res = RES_BAD_ARG; 836 goto error; 837 } 838 /* Headers */ 839 fprintf(stream, "# vtk DataFile Version 3.0\n"); 840 fprintf(stream, "Dump of star-geometry-2D geometry\n"); 841 fprintf(stream, "ASCII\n"); 842 fprintf(stream, "DATASET POLYDATA\n"); 843 844 /* Dump vertices */ 845 vsz = darray_vertex_size_get(&geom->unique_vertices); 846 ASSERT(vsz <= UINT_MAX); 847 fprintf(stream, "POINTS %u double\n", (unsigned)vsz); 848 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 849 FOR_EACH(i, 0, vsz) 850 fprintf(stream, "%g %g 0\n", SPLIT2(vertices[i].coord)); 851 852 /* Dump segments */ 853 tsz = darray_segment_size_get(&geom->unique_segments); 854 ASSERT(4 * tsz <= UINT_MAX); 855 fprintf(stream, "LINES %u %u\n", (unsigned)tsz, (unsigned)(3 * tsz)); 856 segments = darray_segment_cdata_get(&geom->unique_segments); 857 FOR_EACH(i, 0, tsz) 858 fprintf(stream, "2 %u %u\n", SPLIT2(segments[i].vertex_ids)); 859 860 /* Start segments properties */ 861 fprintf(stream, "CELL_DATA %u\n", (unsigned)tsz); 862 descriptions = darray_seg_descriptions_cdata_get(&geom->seg_descriptions); 863 864 /* Dump front medium */ 865 fprintf(stream, "SCALARS Front_medium int\n"); 866 fprintf(stream, "LOOKUP_TABLE default\n"); 867 dump_seg_property(geom, stream, SG2D_FRONT); 868 869 /* Dump back medium */ 870 fprintf(stream, "SCALARS Back_medium int\n"); 871 fprintf(stream, "LOOKUP_TABLE default\n"); 872 dump_seg_property(geom, stream, SG2D_BACK); 873 874 /* Dump interface */ 875 fprintf(stream, "SCALARS Interface int\n"); 876 fprintf(stream, "LOOKUP_TABLE default\n"); 877 dump_seg_property(geom, stream, SG2D_INTFACE); 878 879 /* Dump user_id */ 880 fprintf(stream, "SCALARS User_ID int\n"); 881 fprintf(stream, "LOOKUP_TABLE default\n"); 882 FOR_EACH(i, 0, tsz) 883 fprintf(stream, "%u\n", segments[i].user_id); 884 885 /* Dump merge conflict status */ 886 fprintf(stream, "SCALARS Merge_conflict int\n"); 887 fprintf(stream, "LOOKUP_TABLE default\n"); 888 FOR_EACH(i, 0, tsz) 889 fprintf(stream, "%d\n", descriptions[i].merge_conflict); 890 891 /* Dump property conflict status */ 892 fprintf(stream, "SCALARS Property_conflict int\n"); 893 fprintf(stream, "LOOKUP_TABLE default\n"); 894 FOR_EACH(i, 0, tsz) 895 fprintf(stream, "%d\n", descriptions[i].properties_conflict); 896 897 /* Dump rank of the sg2d_geometry_add that created the segment */ 898 fprintf(stream, "SCALARS Created_at_sg2d_geometry_add int\n"); 899 fprintf(stream, "LOOKUP_TABLE default\n"); 900 FOR_EACH(i, 0, tsz) { 901 const struct definition* tdefs; 902 const unsigned* ranks; 903 ASSERT(darray_definition_size_get(&descriptions[i].defs[SG2D_FRONT]) > 0); 904 /* Rank is the first set_id of the first definition of any property */ 905 tdefs = darray_definition_cdata_get(&descriptions[i].defs[SG2D_FRONT]); 906 ranks = darray_uint_cdata_get(&tdefs[0].set_ids); 907 fprintf(stream, "%u\n", ranks[0]); 908 } 909 910 exit: 911 return res; 912 error: 913 goto exit; 914 } 915 916 res_T 917 sg2d_geometry_dump_as_c_code 918 (const struct sg2d_geometry* geom, 919 FILE* stream, 920 const char* name_prefix, 921 const int flags) 922 { 923 res_T res = RES_OK; 924 const struct vertex* vertices; 925 const struct segment* segments; 926 const char* qualifiers; 927 size_t vsz, tsz, i; 928 if(!geom || !stream 929 || geom->merge_conflict_count 930 || geom->properties_conflict_count 931 || !geom->segment_count_including_duplicates) 932 { 933 if(geom 934 && (geom->merge_conflict_count 935 || geom->properties_conflict_count)) 936 log_err(geom->dev, 937 "%s: cannot dump geometries with conflict as C code\n", 938 FUNC_NAME); 939 if(geom && !geom->segment_count_including_duplicates) 940 log_err(geom->dev, 941 "%s: cannot dump empty geometries as C code\n", 942 FUNC_NAME); 943 res = RES_BAD_ARG; 944 goto error; 945 } 946 if(!name_prefix) name_prefix = ""; 947 /* Headers */ 948 if(name_prefix && name_prefix[0] != '\0') 949 fprintf(stream, "/* Dump of star-geometry-2D '%s'. */\n", name_prefix); 950 else 951 fprintf(stream, "/* Dump of star-geometry-2D. */\n"); 952 vsz = darray_vertex_size_get(&geom->unique_vertices); 953 ASSERT(3 * vsz <= UINT_MAX); 954 tsz = darray_segment_size_get(&geom->unique_segments); 955 ASSERT(3 * tsz <= UINT_MAX); 956 957 if(vsz == 0 || tsz == 0) { 958 log_err(geom->dev, 959 "%s: no geometry to dump\n", 960 FUNC_NAME); 961 res = RES_BAD_ARG; 962 goto error; 963 } 964 965 if(flags & SG2D_C_DUMP_CONST && flags & SG2D_C_DUMP_STATIC) 966 qualifiers = "static const "; 967 else if(flags & SG2D_C_DUMP_CONST) 968 qualifiers = "const "; 969 else if(flags & SG2D_C_DUMP_STATIC) 970 qualifiers = "static "; 971 else qualifiers = ""; 972 973 /* Dump vertices */ 974 fprintf(stream, "%sunsigned %s_vertices_count = %u;\n", 975 qualifiers, name_prefix, (unsigned)vsz); 976 977 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 978 fprintf(stream, 979 "%sdouble %s_vertices[%u] =\n" 980 "{\n", 981 qualifiers, name_prefix, (unsigned)(2 * vsz)); 982 FOR_EACH(i, 0, vsz - 1) 983 fprintf(stream, 984 " %g, %g,\n", SPLIT2(vertices[i].coord)); 985 fprintf(stream, 986 " %g, %g\n", SPLIT2(vertices[vsz - 1].coord)); 987 fprintf(stream, 988 "};\n"); 989 990 /* Dump segments */ 991 fprintf(stream, "%sunsigned %s_segments_count = %u;\n", 992 qualifiers, name_prefix, (unsigned)tsz); 993 994 segments = darray_segment_cdata_get(&geom->unique_segments); 995 fprintf(stream, 996 "%sunsigned %s_segments[%u] =\n" 997 "{\n", 998 qualifiers, name_prefix, (unsigned)(2 * tsz)); 999 FOR_EACH(i, 0, tsz - 1) 1000 fprintf(stream, 1001 " %u, %u,\n", SPLIT2(segments[i].vertex_ids)); 1002 fprintf(stream, 1003 " %u, %u\n", SPLIT2(segments[tsz - 1].vertex_ids)); 1004 fprintf(stream, 1005 "};\n"); 1006 1007 /* Dump properties */ 1008 fprintf(stream, 1009 "%sunsigned %s_properties[%u] =\n" 1010 "{\n", 1011 qualifiers, name_prefix, (unsigned)(SG2D_PROP_TYPES_COUNT__ * tsz)); 1012 FOR_EACH(i, 0, tsz) { 1013 int p; 1014 fprintf(stream, " "); 1015 FOR_EACH(p, 0, SG2D_PROP_TYPES_COUNT__) { 1016 if(segments[i].properties[p] == SG2D_UNSPECIFIED_PROPERTY) 1017 fprintf(stream, " SG2D_UNSPECIFIED_PROPERTY"); 1018 else fprintf(stream," %u", segments[i].properties[p]); 1019 if(i < tsz-1 || p < 2) fprintf(stream, ","); 1020 if(p == 2) fprintf(stream, "\n"); 1021 } 1022 } 1023 fprintf(stream, 1024 "};\n"); 1025 1026 exit: 1027 return res; 1028 error: 1029 goto exit; 1030 } 1031 1032 res_T 1033 sg2d_geometry_ref_get(struct sg2d_geometry* geom) 1034 { 1035 if(!geom) return RES_BAD_ARG; 1036 ref_get(&geom->ref); 1037 return RES_OK; 1038 } 1039 1040 res_T 1041 sg2d_geometry_ref_put(struct sg2d_geometry* geom) 1042 { 1043 if(!geom) return RES_BAD_ARG; 1044 ref_put(&geom->ref, geometry_release); 1045 return RES_OK; 1046 }