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