star-geometry-2d

Cleaning and decorating 2D geometries
git clone git://git.meso-star.fr/star-geometry-2d.git
Log | Files | Refs | README | LICENSE

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 }