sg3d_geometry.c (33990B)
1 /* Copyright (C) 2019, 2020, 2023, 2024 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "sg3d.h" 17 #include "sg3d_geometry.h" 18 #include "sg3d_device.h" 19 20 #include <rsys/double3.h> 21 22 #include <limits.h> 23 24 /****************************************************************************** 25 * Helper functions 26 *****************************************************************************/ 27 static void 28 geometry_release(ref_T* ref) 29 { 30 struct sg3d_geometry* geom; 31 struct sg3d_device* dev; 32 ASSERT(ref); 33 geom = CONTAINER_OF(ref, struct sg3d_geometry, ref); 34 dev = geom->dev; 35 darray_triangle_release(&geom->unique_triangles); 36 darray_vertex_release(&geom->unique_vertices); 37 htable_trg_release(&geom->unique_triangles_ids); 38 htable_vrtx_release(&geom->unique_vertices_ids); 39 darray_trg_descriptions_release(&geom->trg_descriptions); 40 MEM_RM(dev->allocator, geom); 41 SG3D(device_ref_put(dev)); 42 } 43 44 static FINLINE int /* Return 1 if reversed */ 45 trg_make_key(struct vrtx_id3* k, const vrtx_id_t t[3]) 46 { 47 ASSERT(t); 48 ASSERT(t[0] != t[1] && t[0] != t[2] && t[1] != t[2]); 49 if(t[0] < t[2]) { 50 if(t[0] < t[1]) { 51 k->x[0] = t[0]; 52 if(t[1] < t[2]) { 53 k->x[1] = t[1]; 54 k->x[2] = t[2]; 55 return 0; 56 } else { 57 k->x[1] = t[2]; 58 k->x[2] = t[1]; 59 return 1; 60 } 61 } else { 62 k->x[0] = t[1]; 63 if(t[0] < t[2]) { 64 k->x[1] = t[0]; 65 k->x[2] = t[2]; 66 return 1; 67 } else { 68 k->x[1] = t[2]; 69 k->x[2] = t[0]; 70 return 0; 71 } 72 } 73 } 74 else if(t[2] < t[1]) { 75 k->x[0] = t[2]; 76 if(t[0] < t[1]) { 77 k->x[1] = t[0]; 78 k->x[2] = t[1]; 79 return 0; 80 } else { 81 k->x[1] = t[1]; 82 k->x[2] = t[0]; 83 return 1; 84 } 85 } else { 86 k->x[0] = t[1]; 87 if(t[0] < t[2]) { 88 k->x[1] = t[0]; 89 k->x[2] = t[2]; 90 return 1; 91 } else { 92 k->x[1] = t[2]; 93 k->x[2] = t[0]; 94 return 0; 95 } 96 } 97 } 98 99 static void 100 dump_trg_property 101 (const struct sg3d_geometry* geom, 102 FILE* stream, 103 const enum sg3d_property_type type) 104 { 105 size_t i; 106 const struct trg_descriptions* descriptions; 107 ASSERT(geom && stream && type < SG3D_PROP_TYPES_COUNT__); 108 109 descriptions 110 = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); 111 FOR_EACH(i, 0, darray_triangle_size_get(&geom->unique_triangles)) { 112 prop_id_t property = SG3D_UNSPECIFIED_PROPERTY; 113 size_t tdefs_count 114 = darray_definition_size_get(&descriptions[i].defs[type]); 115 if(tdefs_count && descriptions[i].property_defined[type]) { 116 const struct definition* tdefs 117 = darray_definition_cdata_get(&descriptions[i].defs[type]); 118 size_t j; 119 FOR_EACH(j, 0, tdefs_count) { 120 if(tdefs->property_value != SG3D_UNSPECIFIED_PROPERTY) { 121 property = tdefs->property_value; 122 break; /* Found the defined value */ 123 } 124 tdefs++; /* Next value */ 125 } 126 } 127 /* In VTK dumps UINT_MAX is used for unspecified */ 128 if(property == SG3D_UNSPECIFIED_PROPERTY) 129 fprintf(stream, "%u\n", UINT_MAX); 130 else fprintf(stream, "%u\n", (unsigned)property); 131 } 132 } 133 134 /****************************************************************************** 135 * Local functions 136 *****************************************************************************/ 137 res_T 138 geometry_register_triangle 139 (struct sg3d_geometry* geom, 140 const struct triangle* triangle, 141 const trg_id_t triangle_unique_id, 142 const unsigned set_id, 143 const int merge_conflict) 144 { 145 res_T res = RES_OK; 146 struct trg_descriptions* trg_d; 147 int i; 148 char keep_prop_def[SG3D_PROP_TYPES_COUNT__]; 149 150 ASSERT(geom && triangle); 151 152 ERR(geometry_enlarge_trg_descriptions(geom, triangle_unique_id + 1)); 153 trg_d = (darray_trg_descriptions_data_get(&geom->trg_descriptions) 154 + triangle_unique_id); 155 /* Record information */ 156 FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) { 157 struct darray_definition* definitions; 158 struct definition* defs; 159 int done = 0; 160 size_t j; 161 keep_prop_def[i] = trg_d->property_defined[i]; 162 if(triangle->properties[i] == SG3D_UNSPECIFIED_PROPERTY) 163 trg_d->defs_include_unspecified = 1; 164 else trg_d->property_defined[i] = 1; 165 definitions = trg_d->defs + i; 166 defs = darray_definition_data_get(definitions); 167 FOR_EACH(j, 0, darray_definition_size_get(definitions)) { 168 if(defs[j].property_value == triangle->properties[i]) { 169 /* This property_value is already registered: no conflict */ 170 const unsigned* ids = darray_uint_cdata_get(&defs[j].set_ids); 171 size_t k; 172 /* Search if property_value already includes set_id */ 173 FOR_EACH(k, 0, darray_uint_size_get(&defs[j].set_ids)) { 174 if(ids[k] == set_id) { 175 /* Same value+set_id was there already */ 176 done = 1; 177 break; 178 } 179 } 180 if(!done) { 181 /* Need to add the set_id for this property_value */ 182 ERR(darray_uint_push_back(&defs[j].set_ids, &set_id)); 183 done = 1; 184 } 185 break; 186 } 187 } 188 if(!done) { 189 /* This property_value was not recorded already */ 190 size_t defs_sz = darray_definition_size_get(definitions); 191 struct definition* new_def; 192 ERR(darray_definition_resize(definitions, 1 + defs_sz)); 193 new_def = darray_definition_data_get(definitions) + defs_sz; 194 ERR(darray_uint_push_back(&new_def->set_ids, &set_id)); 195 new_def->property_value = triangle->properties[i]; 196 if(!trg_d->merge_conflict && merge_conflict) { 197 /* If more than 1 merge_conflict occur, the first one remains */ 198 trg_d->merge_conflict = merge_conflict; 199 geom->merge_conflict_count++; 200 } 201 } 202 } 203 204 if((!keep_prop_def[SG3D_FRONT] || !keep_prop_def[SG3D_BACK]) 205 && trg_d->property_defined[SG3D_FRONT] && trg_d->property_defined[SG3D_BACK]) 206 { 207 /* Both sides are now defined */ 208 ASSERT(geom->trg_with_unspecified_sides_count > 0); 209 geom->trg_with_unspecified_sides_count--; 210 } 211 212 if(!keep_prop_def[SG3D_INTFACE] && trg_d->property_defined[SG3D_INTFACE]) { 213 /* Interface is now defined */ 214 ASSERT(geom->trg_with_unspecified_intface_count > 0); 215 geom->trg_with_unspecified_intface_count--; 216 } 217 218 exit: 219 return res; 220 error: 221 goto exit; 222 } 223 224 res_T 225 geometry_enlarge_trg_descriptions 226 (struct sg3d_geometry* geom, 227 const trg_id_t sz) 228 { 229 res_T res = RES_OK; 230 size_t old_sz = 231 darray_trg_descriptions_size_get(&geom->trg_descriptions); 232 if(sz <= old_sz) return RES_OK; 233 ERR(darray_trg_descriptions_resize(&geom->trg_descriptions, sz)); 234 ASSERT(geom->trg_with_unspecified_sides_count + sz - old_sz <= TRG_MAX__); 235 ASSERT(geom->trg_with_unspecified_intface_count + sz - old_sz <= TRG_MAX__); 236 geom->trg_with_unspecified_sides_count += (trg_id_t)(sz - old_sz); 237 geom->trg_with_unspecified_intface_count += (trg_id_t)(sz - old_sz); 238 239 exit: 240 return res; 241 error: 242 goto exit; 243 } 244 245 static void 246 dump_partition 247 (const struct sg3d_geometry* geom, 248 FILE* stream, 249 const char* group_name, 250 enum sg3d_obj_dump_content partition) 251 { 252 const struct trg_descriptions* trg_descriptions; 253 const struct triangle* triangles; 254 size_t sz, i; 255 ASSERT(geom && stream && group_name); 256 ASSERT(partition == SG3D_OBJ_DUMP_MERGE_CONFLICTS 257 || partition == SG3D_OBJ_DUMP_PROPERTY_CONFLICTS 258 || partition == SG3D_OBJ_DUMP_VALID_PRIMITIVE); 259 trg_descriptions 260 = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); 261 sz = darray_trg_descriptions_size_get(&geom->trg_descriptions); 262 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 263 fprintf(stream, "g %s\n", group_name); 264 FOR_EACH(i, 0, sz) { 265 int dump; 266 if(partition == SG3D_OBJ_DUMP_VALID_PRIMITIVE) 267 dump = !(trg_descriptions[i].merge_conflict 268 || trg_descriptions[i].properties_conflict); 269 else if(partition == SG3D_OBJ_DUMP_MERGE_CONFLICTS) 270 dump = trg_descriptions[i].merge_conflict; 271 else { 272 ASSERT(partition == SG3D_OBJ_DUMP_PROPERTY_CONFLICTS); 273 dump = trg_descriptions[i].properties_conflict; 274 } 275 if(!dump) continue; 276 fprintf(stream, "f "PRTF_VRTX" "PRTF_VRTX" "PRTF_VRTX"\n", 277 /* OBJ indexing starts at 1 */ 278 1 + triangles[i].vertex_ids[0], 279 1 + triangles[i].vertex_ids[1], 280 1 + triangles[i].vertex_ids[2]); 281 } 282 } 283 284 /****************************************************************************** 285 * Exported functions 286 *****************************************************************************/ 287 res_T 288 sg3d_geometry_create 289 (struct sg3d_device* dev, 290 struct sg3d_geometry** out_geometry) 291 { 292 struct sg3d_geometry* geom = NULL; 293 res_T res = RES_OK; 294 295 if(!dev || !out_geometry) { 296 res = RES_BAD_ARG; 297 goto error; 298 } 299 300 geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct sg3d_geometry)); 301 if(!geom) { 302 log_err(dev, 303 LIB_NAME":%s: could not allocate the sg3d.\n", FUNC_NAME); 304 res = RES_MEM_ERR; 305 goto error; 306 } 307 308 SG3D(device_ref_get(dev)); 309 darray_triangle_init(dev->allocator, &geom->unique_triangles); 310 darray_vertex_init(dev->allocator, &geom->unique_vertices); 311 htable_trg_init(dev->allocator, &geom->unique_triangles_ids); 312 htable_vrtx_init(dev->allocator, &geom->unique_vertices_ids); 313 darray_trg_descriptions_init(dev->allocator, &geom->trg_descriptions); 314 geom->triangle_count_including_duplicates = 0; 315 geom->sides_with_defined_medium_count = 0; 316 geom->set_id = 0; 317 geom->trg_with_unspecified_sides_count = 0; 318 geom->trg_with_unspecified_intface_count = 0; 319 geom->merge_conflict_count = 0; 320 geom->properties_conflict_count = 0; 321 geom->dev = dev; 322 323 ref_init(&geom->ref); 324 325 exit: 326 if(out_geometry) *out_geometry = geom; 327 return res; 328 error: 329 if(geom) { 330 SG3D(geometry_ref_put(geom)); 331 geom = NULL; 332 } 333 goto exit; 334 } 335 336 res_T 337 sg3d_geometry_reserve 338 (struct sg3d_geometry* geom, 339 const vrtx_id_t vertices_count, 340 const trg_id_t triangles_count, 341 const prop_id_t properties_count) 342 { 343 res_T res = RES_OK; 344 if(!geom) return RES_BAD_ARG; 345 346 ERR(darray_triangle_reserve(&geom->unique_triangles, triangles_count)); 347 ERR(darray_vertex_reserve(&geom->unique_vertices, vertices_count)); 348 ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, vertices_count)); 349 ERR(htable_trg_reserve(&geom->unique_triangles_ids, triangles_count)); 350 ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, 351 properties_count)); 352 353 end: 354 return res; 355 error: 356 goto end; 357 } 358 359 res_T 360 sg3d_geometry_add 361 (struct sg3d_geometry* geom, 362 const vrtx_id_t nverts, 363 const trg_id_t ntris, 364 const struct sg3d_geometry_add_callbacks* callbacks, 365 void* ctx) /* Can be NULL */ 366 { 367 res_T res = RES_OK; 368 struct mem_allocator* alloc; 369 size_t nutris, nuverts; 370 vrtx_id_t nv, n_new_uverts = 0; 371 trg_id_t nt, n_new_utris = 0; 372 struct triangle* trg; 373 /* Tmp table of IDs to record unique IDs of the currently added vertices */ 374 struct darray_vertice_ids unique_vertice_ids; 375 int unique_vertice_ids_initialized = 0; 376 get_indices_t get_ind; 377 get_properties_t get_prop; 378 get_position_t get_pos; 379 add_triangle_t add_trg; 380 merge_triangle_t mrg_trg; 381 degenerated_triangle_t dege_trg; 382 383 if(!geom || !callbacks || !callbacks->get_indices || !callbacks->get_position) 384 { 385 res = RES_BAD_ARG; 386 goto error; 387 } 388 389 get_ind = callbacks->get_indices; 390 get_prop = callbacks->get_properties; 391 get_pos = callbacks->get_position; 392 add_trg = callbacks->add_triangle; 393 mrg_trg = callbacks->merge_triangle; 394 dege_trg = callbacks->degenerated_triangle; 395 alloc = geom->dev->allocator; 396 nuverts = darray_vertex_size_get(&geom->unique_vertices); 397 nutris = darray_triangle_size_get(&geom->unique_triangles); 398 399 /* Make room for new geometry; suppose no more duplicates */ 400 darray_vertice_ids_init(alloc, &unique_vertice_ids); 401 unique_vertice_ids_initialized = 1; 402 ERR(darray_vertice_ids_reserve(&unique_vertice_ids, nverts)); 403 ERR(darray_vertex_reserve(&geom->unique_vertices, nuverts + nverts)); 404 ERR(darray_triangle_reserve(&geom->unique_triangles, nutris + ntris)); 405 ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, nuverts + nverts)); 406 ERR(htable_trg_reserve(&geom->unique_triangles_ids, nutris + ntris)); 407 ASSERT(nutris == darray_trg_descriptions_size_get(&geom->trg_descriptions)); 408 ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, nutris + ntris)); 409 /* Get vertices and deduplicate */ 410 FOR_EACH(nv, 0, nverts) { 411 vrtx_id_t* p_vrtx; 412 struct vertex tmp; 413 vrtx_id_t v_idx; 414 get_pos(nv, tmp.coord, ctx); 415 p_vrtx = htable_vrtx_find(&geom->unique_vertices_ids, &tmp); 416 if(p_vrtx) { 417 /* Duplicate vertex */ 418 v_idx = *p_vrtx; 419 } else { 420 /* New vertex */ 421 ASSERT(nuverts + n_new_uverts <= VRTX_MAX__); 422 v_idx = (vrtx_id_t)(nuverts + n_new_uverts); 423 ASSERT(v_idx == htable_vrtx_size_get(&geom->unique_vertices_ids)); 424 ERR(darray_vertex_push_back(&geom->unique_vertices, &tmp)); 425 ERR(htable_vrtx_set(&geom->unique_vertices_ids, &tmp, &v_idx)); 426 ++n_new_uverts; 427 } 428 /* Keep the unique ID for vertex nv */ 429 ERR(darray_vertice_ids_push_back(&unique_vertice_ids, &v_idx)); 430 } 431 432 /* Get triangles and deduplicate */ 433 trg = darray_triangle_data_get(&geom->unique_triangles); 434 FOR_EACH(nt, 0, ntris) { 435 int j, reversed, dg; 436 struct vrtx_id3 trg_key; 437 struct triangle tmp = TRG_UNDEF__; 438 trg_id_t* p_trg; 439 struct trg_descriptions* trg_descriptions = NULL; 440 trg_id_t unique_id; 441 442 get_ind(nt, tmp.vertex_ids, ctx); 443 FOR_EACH(j, 0, 3) { 444 if(tmp.vertex_ids[j] >= nverts) { 445 res = RES_BAD_ARG; 446 goto error; 447 } 448 /* Replace the vertex ID by its the unique ID */ 449 tmp.vertex_ids[j] 450 = darray_vertice_ids_cdata_get(&unique_vertice_ids)[tmp.vertex_ids[j]]; 451 } 452 dg = (tmp.vertex_ids[0] == tmp.vertex_ids[1] 453 || tmp.vertex_ids[0] == tmp.vertex_ids[2] 454 || tmp.vertex_ids[1] == tmp.vertex_ids[2]); 455 if(!dg) { 456 double edge1[3], edge2[3], n[3]; 457 const struct vertex* vertices = darray_vertex_cdata_get(&geom->unique_vertices); 458 d3_sub(edge1, vertices[tmp.vertex_ids[1]].coord, vertices[tmp.vertex_ids[0]].coord); 459 d3_sub(edge2, vertices[tmp.vertex_ids[2]].coord, vertices[tmp.vertex_ids[0]].coord); 460 d3_cross(n, edge1, edge2); 461 dg = d3_len(n) == 0; 462 } 463 if(dg) { 464 int abort = 0; 465 if(dege_trg) { 466 /* Let the client app rule. */ 467 ERR(dege_trg(nt, ctx, &abort)); 468 } else { 469 log_warn(geom->dev, 470 LIB_NAME":%s: triangle "PRTF_TRG" is degenerated (removed).\n", 471 FUNC_NAME, nt); 472 } 473 if(abort) { 474 res = RES_BAD_ARG; 475 goto error; 476 } 477 else continue; 478 } 479 /* Get properties */ 480 if(get_prop) get_prop(nt, tmp.properties, ctx); 481 /* Find duplicate triangles */ 482 reversed = trg_make_key(&trg_key, tmp.vertex_ids); 483 p_trg = htable_trg_find(&geom->unique_triangles_ids, &trg_key); 484 if(p_trg) { 485 /* Duplicate triangle. Need to check duplicate validity */ 486 trg_id_t trg_id = *p_trg; 487 struct vrtx_id3 utrg_key; 488 int ureversed = trg_make_key(&utrg_key, trg[trg_id].vertex_ids); 489 int same = (reversed == ureversed); 490 int already_conflict; 491 ASSERT(trg_key_eq(&trg_key, &utrg_key)); 492 unique_id = trg_id; 493 ERR(geometry_enlarge_trg_descriptions(geom, 1 + trg_id)); 494 trg_descriptions 495 = darray_trg_descriptions_data_get(&geom->trg_descriptions); 496 if(!same) 497 SWAP(prop_id_t, tmp.properties[SG3D_FRONT], tmp.properties[SG3D_BACK]); 498 already_conflict = trg_descriptions[trg_id].merge_conflict; 499 if(mrg_trg) { 500 /* Let the client app rule. */ 501 ERR(mrg_trg(trg_id, nt, !same, trg[trg_id].properties, 502 tmp.properties, ctx, &trg_descriptions[trg_id].merge_conflict)); 503 } else { 504 FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { 505 if(!sg3d_compatible_property(trg[trg_id].properties[j], 506 tmp.properties[j])) 507 { 508 trg_descriptions[trg_id].merge_conflict = 1; 509 break; 510 } 511 } 512 } 513 if(trg_descriptions[trg_id].merge_conflict && !already_conflict) 514 geom->merge_conflict_count++; 515 /* Replace SG3D_UNSPECIFIED_PROPERTY properties */ 516 FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { 517 if(trg[trg_id].properties[j] == SG3D_UNSPECIFIED_PROPERTY 518 && tmp.properties[j] != SG3D_UNSPECIFIED_PROPERTY) { 519 trg[trg_id].properties[j] = tmp.properties[j]; 520 if(j == SG3D_FRONT || j == SG3D_BACK) 521 geom->sides_with_defined_medium_count++; 522 } 523 } 524 } else { 525 /* New triangle */ 526 trg_id_t new_id = (trg_id_t)(nutris + n_new_utris); 527 ASSERT(new_id <= TRG_MAX__); 528 unique_id = new_id; 529 tmp.user_id = geom->triangle_count_including_duplicates + nt; 530 if(add_trg) ERR(add_trg(new_id, nt, ctx)); 531 ERR(geometry_enlarge_trg_descriptions(geom, 1 + new_id)); 532 trg_descriptions 533 = darray_trg_descriptions_data_get(&geom->trg_descriptions); 534 ERR(darray_triangle_push_back(&geom->unique_triangles, &tmp)); 535 trg = darray_triangle_data_get(&geom->unique_triangles); 536 FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { 537 if((j == SG3D_FRONT || j == SG3D_BACK) 538 && tmp.properties[j] != SG3D_UNSPECIFIED_PROPERTY) 539 geom->sides_with_defined_medium_count++; 540 } 541 ASSERT(new_id == htable_trg_size_get(&geom->unique_triangles_ids)); 542 ERR(htable_trg_set(&geom->unique_triangles_ids, &trg_key, &new_id)); 543 n_new_utris++; 544 } 545 ERR(geometry_register_triangle(geom, &tmp, unique_id, geom->set_id, 546 trg_descriptions[unique_id].properties_conflict)); 547 if(trg_descriptions[unique_id].properties_conflict) 548 geom->merge_conflict_count++; 549 } 550 551 ASSERT(nuverts + n_new_uverts 552 == htable_vrtx_size_get(&geom->unique_vertices_ids)); 553 ASSERT(nutris + n_new_utris 554 == htable_trg_size_get(&geom->unique_triangles_ids)); 555 exit: 556 if(geom) { 557 geom->set_id++; 558 geom->triangle_count_including_duplicates += ntris; 559 } 560 if(unique_vertice_ids_initialized) 561 darray_vertice_ids_release(&unique_vertice_ids); 562 return res; 563 error: 564 goto exit; 565 } 566 567 res_T 568 sg3d_geometry_validate_properties 569 (struct sg3d_geometry* geom, 570 res_T(*validate)(const trg_id_t, const prop_id_t*, void*, int*), 571 void* ctx) 572 { 573 size_t sz__; 574 trg_id_t i, sz; 575 struct trg_descriptions* trg_descriptions; 576 res_T res = RES_OK; 577 578 if(!geom || !validate) { 579 res = RES_BAD_ARG; 580 goto error; 581 } 582 583 sz__ = darray_trg_descriptions_size_get(&geom->trg_descriptions); 584 ASSERT(sz__ <= PROP_MAX__); 585 sz = (unsigned)sz__; 586 trg_descriptions 587 = darray_trg_descriptions_data_get(&geom->trg_descriptions); 588 geom->properties_conflict_count = 0; /* Reset count */ 589 FOR_EACH(i, 0, sz) { 590 int p; 591 prop_id_t props[SG3D_PROP_TYPES_COUNT__]; 592 struct trg_descriptions* trgd = trg_descriptions + i; 593 /* Validate only triangle not flagged with merge_conflict */ 594 if(trgd->merge_conflict) { 595 trgd->properties_conflict = 0; 596 continue; 597 } 598 /* Get properties for non-conflict triangles */ 599 FOR_EACH(p, 0, SG3D_PROP_TYPES_COUNT__) { 600 size_t j; 601 const struct definition* defs = darray_definition_cdata_get(trgd->defs + p); 602 props[p] = SG3D_UNSPECIFIED_PROPERTY; 603 FOR_EACH(j, 0, darray_definition_size_get(trgd->defs + p)) { 604 if(defs[j].property_value != SG3D_UNSPECIFIED_PROPERTY) { 605 props[p] = defs[j].property_value; 606 break; 607 } 608 } 609 } 610 /* Call validation */ 611 ERR(validate(i, props, ctx, &trgd->properties_conflict)); 612 if(trgd->properties_conflict) 613 geom->properties_conflict_count++; 614 } 615 616 exit: 617 return res; 618 error: 619 goto exit; 620 } 621 622 res_T 623 sg3d_geometry_get_unique_vertices_count 624 (const struct sg3d_geometry* geom, 625 vrtx_id_t* count) 626 { 627 res_T res = RES_OK; 628 size_t sz; 629 if(!geom || !count) { 630 res = RES_BAD_ARG; 631 goto error; 632 } 633 sz = darray_vertex_size_get(&geom->unique_vertices); 634 ASSERT(sz <= VRTX_MAX__); 635 *count = (vrtx_id_t)sz; 636 exit: 637 return res; 638 error: 639 goto exit; 640 } 641 642 res_T 643 sg3d_geometry_get_unique_vertex 644 (const struct sg3d_geometry* geom, 645 const vrtx_id_t ivtx, 646 double coord[SG3D_GEOMETRY_DIMENSION]) 647 { 648 res_T res = RES_OK; 649 const struct vertex* vertices; 650 if(!geom || !coord 651 || ivtx >= darray_vertex_size_get(&geom->unique_vertices)) 652 { 653 res = RES_BAD_ARG; 654 goto error; 655 } 656 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 657 d3_set(coord, vertices[ivtx].coord); 658 exit: 659 return res; 660 error: 661 goto exit; 662 } 663 664 res_T 665 sg3d_geometry_get_added_triangles_count 666 (const struct sg3d_geometry* geom, 667 trg_id_t* count) 668 { 669 res_T res = RES_OK; 670 if(!geom || !count) { 671 res = RES_BAD_ARG; 672 goto error; 673 } 674 *count = geom->triangle_count_including_duplicates; 675 exit: 676 return res; 677 error: 678 goto exit; 679 } 680 681 res_T 682 sg3d_geometry_get_unique_triangles_count 683 (const struct sg3d_geometry* geom, 684 trg_id_t* count) 685 { 686 res_T res = RES_OK; 687 size_t sz; 688 if(!geom || !count) { 689 res = RES_BAD_ARG; 690 goto error; 691 } 692 sz = darray_triangle_size_get(&geom->unique_triangles); 693 ASSERT(sz <= TRG_MAX__); 694 *count = (unsigned)sz; 695 exit: 696 return res; 697 error: 698 goto exit; 699 } 700 701 res_T 702 sg3d_geometry_get_unique_triangle_vertices 703 (const struct sg3d_geometry* geom, 704 const trg_id_t itri, 705 vrtx_id_t indices[SG3D_GEOMETRY_DIMENSION]) 706 { 707 res_T res = RES_OK; 708 const struct triangle* triangles; 709 size_t i; 710 if(!geom || !indices 711 || itri >= darray_triangle_size_get(&geom->unique_triangles)) 712 { 713 res = RES_BAD_ARG; 714 goto error; 715 } 716 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 717 FOR_EACH(i, 0, SG3D_GEOMETRY_DIMENSION) 718 indices[i] = triangles[itri].vertex_ids[i]; 719 exit: 720 return res; 721 error: 722 goto exit; 723 } 724 725 res_T 726 sg3d_geometry_get_unique_triangle_properties 727 (const struct sg3d_geometry* geom, 728 const trg_id_t itri, 729 prop_id_t properties[SG3D_PROP_TYPES_COUNT__]) 730 { 731 res_T res = RES_OK; 732 const struct triangle* triangles; 733 size_t i; 734 if(!geom || !properties 735 || itri >= darray_triangle_size_get(&geom->unique_triangles)) 736 { 737 res = RES_BAD_ARG; 738 goto error; 739 } 740 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 741 FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) 742 properties[i] = triangles[itri].properties[i]; 743 exit: 744 return res; 745 error: 746 goto exit; 747 } 748 749 res_T 750 sg3d_geometry_get_unique_triangle_user_id 751 (const struct sg3d_geometry* geom, 752 const trg_id_t itri, 753 trg_id_t* user_id) 754 { 755 res_T res = RES_OK; 756 const struct triangle* triangles; 757 if(!geom || !user_id 758 || itri >= darray_triangle_size_get(&geom->unique_triangles)) 759 { 760 res = RES_BAD_ARG; 761 goto error; 762 } 763 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 764 *user_id = triangles[itri].user_id; 765 exit: 766 return res; 767 error: 768 goto exit; 769 } 770 771 res_T 772 sg3d_geometry_get_unique_triangles_with_unspecified_side_count 773 (const struct sg3d_geometry* geom, 774 trg_id_t* count) 775 { 776 res_T res = RES_OK; 777 if(!geom || !count) { 778 res = RES_BAD_ARG; 779 goto error; 780 } 781 *count = geom->trg_with_unspecified_sides_count; 782 exit: 783 return res; 784 error: 785 goto exit; 786 } 787 788 res_T 789 sg3d_geometry_get_unique_triangles_with_unspecified_interface_count 790 (const struct sg3d_geometry* geom, 791 trg_id_t* count) 792 { 793 res_T res = RES_OK; 794 if(!geom || !count) { 795 res = RES_BAD_ARG; 796 goto error; 797 } 798 *count = geom->trg_with_unspecified_intface_count; 799 exit: 800 return res; 801 error: 802 goto exit; 803 } 804 805 res_T 806 sg3d_geometry_get_unique_triangles_with_merge_conflict_count 807 (const struct sg3d_geometry* geom, 808 trg_id_t* count) 809 { 810 res_T res = RES_OK; 811 if(!geom || !count) { 812 res = RES_BAD_ARG; 813 goto error; 814 } 815 *count = geom->merge_conflict_count; 816 exit: 817 return res; 818 error: 819 goto exit; 820 } 821 822 res_T 823 sg3d_geometry_get_unique_triangles_with_properties_conflict_count 824 (const struct sg3d_geometry* geom, 825 trg_id_t* count) 826 { 827 res_T res = RES_OK; 828 if(!geom || !count) { 829 res = RES_BAD_ARG; 830 goto error; 831 } 832 *count = geom->properties_conflict_count; 833 exit: 834 return res; 835 error: 836 goto exit; 837 } 838 839 res_T 840 sg3d_geometry_dump_as_obj 841 (const struct sg3d_geometry* geom, 842 FILE* stream, 843 int flags) 844 { 845 res_T res = RES_OK; 846 const struct vertex* vertices; 847 size_t vsz, tsz, i; 848 if(!geom || !stream || !flags 849 || !geom->triangle_count_including_duplicates) 850 { 851 if(geom && !geom->triangle_count_including_duplicates) 852 log_err(geom->dev, 853 LIB_NAME":%s: cannot dump empty geometries as OBJ\n", 854 FUNC_NAME); 855 res = RES_BAD_ARG; 856 goto error; 857 } 858 /* Headers */ 859 fprintf(stream, "# Dump of star-geometry-3d\n"); 860 fprintf(stream, "# Geometry counts:\n"); 861 vsz = darray_vertex_size_get(&geom->unique_vertices); 862 ASSERT(vsz <= VRTX_MAX__); 863 fprintf(stream, "# . "PRTF_VRTX" vertices\n", (vrtx_id_t)vsz); 864 tsz = darray_triangle_size_get(&geom->unique_triangles); 865 ASSERT(tsz <= TRG_MAX__); 866 fprintf(stream, "# . "PRTF_TRG" triangles\n", (trg_id_t)tsz); 867 fprintf(stream, 868 "# . "PRTF_TRG" triangles flagged with a merge conflict\n", 869 geom->merge_conflict_count); 870 fprintf(stream, 871 "# . "PRTF_TRG" triangles flagged with a property conflict\n", 872 geom->merge_conflict_count); 873 874 /* Dump vertices */ 875 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 876 FOR_EACH(i, 0, vsz) 877 fprintf(stream, "v %.16g %.16g %.16g\n", SPLIT3(vertices[i].coord)); 878 879 /* Dump triangles by groups */ 880 if(flags & SG3D_OBJ_DUMP_VALID_PRIMITIVE) { 881 dump_partition(geom, stream, 882 "Valid_triangles", SG3D_OBJ_DUMP_VALID_PRIMITIVE); 883 } 884 if(flags & SG3D_OBJ_DUMP_MERGE_CONFLICTS) { 885 dump_partition(geom, stream, 886 "Merge_conflicts", SG3D_OBJ_DUMP_MERGE_CONFLICTS); 887 } 888 if(flags & SG3D_OBJ_DUMP_PROPERTY_CONFLICTS) { 889 dump_partition(geom, stream, 890 "Property_conflicts", SG3D_OBJ_DUMP_PROPERTY_CONFLICTS); 891 } 892 893 exit: 894 return res; 895 error: 896 goto exit; 897 } 898 899 res_T 900 sg3d_geometry_dump_as_vtk 901 (const struct sg3d_geometry* geom, 902 FILE* stream) 903 { 904 res_T res = RES_OK; 905 const struct vertex* vertices; 906 const struct triangle* triangles; 907 const struct trg_descriptions* descriptions; 908 size_t vsz, tsz, i; 909 if(!geom || !stream || !geom->triangle_count_including_duplicates) { 910 if(geom && !geom->triangle_count_including_duplicates) 911 log_err(geom->dev, 912 LIB_NAME":%s: cannot dump empty geometries as VTK\n", 913 FUNC_NAME); 914 res = RES_BAD_ARG; 915 goto error; 916 } 917 /* Headers */ 918 fprintf(stream, "# vtk DataFile Version 2.0\n"); 919 fprintf(stream, "Dump of star-geometry-3d geometry\n"); 920 fprintf(stream, "ASCII\n"); 921 fprintf(stream, "DATASET POLYDATA\n"); 922 923 /* Dump vertices */ 924 vsz = darray_vertex_size_get(&geom->unique_vertices); 925 ASSERT(vsz <= VRTX_MAX__); 926 fprintf(stream, "POINTS "PRTF_VRTX" double\n", (vrtx_id_t)vsz); 927 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 928 FOR_EACH(i, 0, vsz) 929 fprintf(stream, "%.16g %.16g %.16g\n", SPLIT3(vertices[i].coord)); 930 931 /* Dump triangles */ 932 tsz = darray_triangle_size_get(&geom->unique_triangles); 933 ASSERT(4 * tsz <= TRG_MAX__); 934 fprintf(stream, "POLYGONS "PRTF_TRG" "PRTF_TRG"\n", 935 (trg_id_t)tsz, (trg_id_t)(4 * tsz)); 936 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 937 FOR_EACH(i, 0, tsz) 938 fprintf(stream, "3 "PRTF_VRTX" "PRTF_VRTX" "PRTF_VRTX"\n", 939 SPLIT3(triangles[i].vertex_ids)); 940 941 /* Start triangles properties */ 942 fprintf(stream, "CELL_DATA "PRTF_TRG"\n", (trg_id_t)tsz); 943 descriptions = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); 944 945 /* Dump front medium */ 946 fprintf(stream, "SCALARS Front_medium unsigned_int 1\n"); 947 fprintf(stream, "LOOKUP_TABLE default\n"); 948 dump_trg_property(geom, stream, SG3D_FRONT); 949 950 /* Dump back medium */ 951 fprintf(stream, "SCALARS Back_medium unsigned_int 1\n"); 952 fprintf(stream, "LOOKUP_TABLE default\n"); 953 dump_trg_property(geom, stream, SG3D_BACK); 954 955 /* Dump interface */ 956 fprintf(stream, "SCALARS Interface unsigned_int 1\n"); 957 fprintf(stream, "LOOKUP_TABLE default\n"); 958 dump_trg_property(geom, stream, SG3D_INTFACE); 959 960 /* Dump unique_id */ 961 fprintf(stream, "SCALARS Unique_ID unsigned_int 1\n"); 962 fprintf(stream, "LOOKUP_TABLE default\n"); 963 FOR_EACH(i, 0, tsz) fprintf(stream, PRTF_TRG"\n", (trg_id_t)i); 964 965 /* Dump user_id */ 966 fprintf(stream, "SCALARS User_ID unsigned_int 1\n"); 967 fprintf(stream, "LOOKUP_TABLE default\n"); 968 FOR_EACH(i, 0, tsz) fprintf(stream, PRTF_TRG"\n", triangles[i].user_id); 969 970 /* Dump merge conflict status (if any) */ 971 if(geom->merge_conflict_count) { 972 fprintf(stream, "SCALARS Merge_conflict int 1\n"); 973 fprintf(stream, "LOOKUP_TABLE default\n"); 974 FOR_EACH(i, 0, tsz) 975 fprintf(stream, "%d\n", descriptions[i].merge_conflict); 976 } 977 978 /* Dump property conflict status (if any) */ 979 if(geom->properties_conflict_count) { 980 fprintf(stream, "SCALARS Property_conflict int 1\n"); 981 fprintf(stream, "LOOKUP_TABLE default\n"); 982 FOR_EACH(i, 0, tsz) 983 fprintf(stream, "%d\n", descriptions[i].properties_conflict); 984 } 985 986 /* Dump rank of the sg3d_geometry_add that created the triangle */ 987 fprintf(stream, "SCALARS Created_at_sg3d_geometry_add unsigned_int 1\n"); 988 fprintf(stream, "LOOKUP_TABLE default\n"); 989 FOR_EACH(i, 0, tsz) { 990 const struct definition* tdefs; 991 const unsigned* ranks; 992 ASSERT(darray_definition_size_get(&descriptions[i].defs[SG3D_FRONT]) > 0); 993 /* Rank is the first set_id of the first definition of any property */ 994 tdefs = darray_definition_cdata_get(&descriptions[i].defs[SG3D_FRONT]); 995 ranks = darray_uint_cdata_get(&tdefs[0].set_ids); 996 fprintf(stream, "%u\n", ranks[0]); 997 } 998 999 exit: 1000 return res; 1001 error: 1002 goto exit; 1003 } 1004 1005 res_T 1006 sg3d_geometry_dump_as_c_code 1007 (const struct sg3d_geometry* geom, 1008 FILE* stream, 1009 const char* name_prefix, 1010 const int flags) 1011 { 1012 res_T res = RES_OK; 1013 const struct vertex* vertices; 1014 const struct triangle* triangles; 1015 const char* qualifiers; 1016 size_t vsz, tsz, i; 1017 if(!geom || !stream 1018 || geom->merge_conflict_count 1019 || geom->properties_conflict_count 1020 || !geom->triangle_count_including_duplicates) 1021 { 1022 if(geom 1023 && (geom->merge_conflict_count 1024 || geom->properties_conflict_count)) 1025 log_err(geom->dev, 1026 LIB_NAME":%s: cannot dump geometries with conflict as C code\n", 1027 FUNC_NAME); 1028 if(geom && !geom->triangle_count_including_duplicates) 1029 log_err(geom->dev, 1030 LIB_NAME":%s: cannot dump empty geometries as C code\n", 1031 FUNC_NAME); 1032 res = RES_BAD_ARG; 1033 goto error; 1034 } 1035 if(!name_prefix) name_prefix = ""; 1036 /* Headers */ 1037 if(name_prefix && name_prefix[0] != '\0') 1038 fprintf(stream, "/* Dump of star-geometry-3d '%s'. */\n", name_prefix); 1039 else 1040 fprintf(stream, "/* Dump of star-geometry-3d. */\n"); 1041 vsz = darray_vertex_size_get(&geom->unique_vertices); 1042 ASSERT(3 * vsz <= VRTX_MAX__); 1043 tsz = darray_triangle_size_get(&geom->unique_triangles); 1044 ASSERT(3 * tsz <= TRG_MAX__); 1045 1046 if(vsz == 0 || tsz == 0) { 1047 log_err(geom->dev, 1048 "%s: no geometry to dump\n", 1049 FUNC_NAME); 1050 res = RES_BAD_ARG; 1051 goto error; 1052 } 1053 1054 if(flags & SG3D_C_DUMP_CONST && flags & SG3D_C_DUMP_STATIC) 1055 qualifiers = "static const "; 1056 else if(flags & SG3D_C_DUMP_CONST) 1057 qualifiers = "const "; 1058 else if(flags & SG3D_C_DUMP_STATIC) 1059 qualifiers = "static "; 1060 else qualifiers = ""; 1061 1062 /* Dump vertices */ 1063 fprintf(stream, "%s"VRTX_TYPE_NAME" %s_vertices_count = "PRTF_VRTX";\n", 1064 qualifiers, name_prefix, (vrtx_id_t)vsz); 1065 1066 vertices = darray_vertex_cdata_get(&geom->unique_vertices); 1067 fprintf(stream, 1068 "%sdouble %s_vertices["PRTF_VRTX"] =\n" 1069 "{\n", 1070 qualifiers, name_prefix, (vrtx_id_t)(3 * vsz)); 1071 FOR_EACH(i, 0, vsz - 1) 1072 fprintf(stream, 1073 " %.16g, %.16g, %.16g,\n", SPLIT3(vertices[i].coord)); 1074 fprintf(stream, 1075 " %.16g, %.16g, %.16g\n", SPLIT3(vertices[vsz - 1].coord)); 1076 fprintf(stream, 1077 "};\n"); 1078 1079 /* Dump triangles */ 1080 fprintf(stream, "%s"TRG_TYPE_NAME" %s_triangles_count = "PRTF_TRG";\n", 1081 qualifiers, name_prefix, (trg_id_t)tsz); 1082 1083 triangles = darray_triangle_cdata_get(&geom->unique_triangles); 1084 fprintf(stream, 1085 "%s"TRG_TYPE_NAME" %s_triangles["PRTF_TRG"] =\n" 1086 "{\n", 1087 qualifiers, name_prefix, (trg_id_t)(3 * tsz)); 1088 FOR_EACH(i, 0, tsz - 1) 1089 fprintf(stream, 1090 " "PRTF_VRTX", "PRTF_VRTX", "PRTF_VRTX",\n", 1091 SPLIT3(triangles[i].vertex_ids)); 1092 fprintf(stream, 1093 " "PRTF_VRTX", "PRTF_VRTX", "PRTF_VRTX"\n", 1094 SPLIT3(triangles[tsz - 1].vertex_ids)); 1095 fprintf(stream, 1096 "};\n"); 1097 1098 /* Dump properties */ 1099 fprintf(stream, 1100 "%s"PROP_TYPE_NAME" %s_properties["PRTF_PROP"] =\n" 1101 "{\n", 1102 qualifiers, name_prefix, (prop_id_t)(SG3D_PROP_TYPES_COUNT__ * tsz)); 1103 FOR_EACH(i, 0, tsz) { 1104 int p; 1105 fprintf(stream, " "); 1106 FOR_EACH(p, 0, SG3D_PROP_TYPES_COUNT__) { 1107 if(triangles[i].properties[p] == SG3D_UNSPECIFIED_PROPERTY) 1108 fprintf(stream, " SG3D_UNSPECIFIED_PROPERTY"); 1109 else fprintf(stream," "PRTF_PROP"", triangles[i].properties[p]); 1110 if(i < tsz-1 || p < 2) fprintf(stream, ","); 1111 if(p == 2) fprintf(stream, "\n"); 1112 } 1113 } 1114 fprintf(stream, 1115 "};\n"); 1116 1117 exit: 1118 return res; 1119 error: 1120 goto exit; 1121 } 1122 1123 res_T 1124 sg3d_geometry_ref_get(struct sg3d_geometry* geom) 1125 { 1126 if(!geom) return RES_BAD_ARG; 1127 ref_get(&geom->ref); 1128 return RES_OK; 1129 } 1130 1131 res_T 1132 sg3d_geometry_ref_put(struct sg3d_geometry* geom) 1133 { 1134 if(!geom) return RES_BAD_ARG; 1135 ref_put(&geom->ref, geometry_release); 1136 return RES_OK; 1137 }