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.h (16868B)


      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 #ifndef STAR_GEOMETRY_2D_H__
     17 #define STAR_GEOMETRY_2D_H__
     18 
     19 #include <rsys/rsys.h>
     20 #include <rsys/dynamic_array_uint.h>
     21 
     22 #include <limits.h>
     23 
     24 /* Library symbol management */
     25 #if defined(SG2D_SHARED_BUILD)
     26   #define SG2D_API extern EXPORT_SYM
     27 #elif defined(SG2D_STATIC_BUILD)
     28   #define SG2D_API extern LOCAL_SYM
     29 #else /* Use shared library */
     30   #define SG2D_API extern IMPORT_SYM
     31 #endif
     32 
     33 /* Helper macro that asserts if the invocation of the star-geometry function
     34  * `Func' returns an error. One should use this macro on star-geometry
     35  * function calls for which no explicit error checking is performed. */
     36 #ifndef NDEBUG
     37 #define SG2(Func) ASSERT(sg2d_ ## Func == RES_OK)
     38 #else
     39 #define SG2(Func) sg2d_ ## Func
     40 #endif
     41 
     42 /* Forward declaration of external opaque data types */
     43 struct logger;
     44 struct mem_allocator;
     45 
     46 /* Forward declaration of the star-geometry-2D opaque data types. These data
     47  * types are ref counted. Once created the caller implicitly owns the created
     48  * data, i.e. its reference counter is set to 1. The sdis_<TYPE>_ref_<get|put>
     49  * functions get or release a reference on the data, i.e. they increment or
     50  * decrement the reference counter, respectively. When this counter reaches 0,
     51  * the object is silently destroyed and cannot be used anymore. */
     52 struct sg2d_device;
     53 struct sg2d_geometry;
     54 
     55 /******************************************************************************
     56  * The dimension of the geometry used in the library.
     57  *****************************************************************************/
     58 #define SG2D_GEOMETRY_DIMENSION 2
     59 
     60 /******************************************************************************
     61  * A type to list the different user properties attached to segments.
     62  *****************************************************************************/
     63 enum sg2d_property_type {
     64   SG2D_FRONT,
     65   SG2D_BACK,
     66   SG2D_INTFACE,
     67   SG2D_PROP_TYPES_COUNT__
     68 };
     69 
     70 /******************************************************************************
     71  * A type to list the different possible partitions of segments.
     72  *****************************************************************************/
     73 enum sg2d_obj_dump_content {
     74   SG2D_OBJ_DUMP_MERGE_CONFLICTS = BIT(0),
     75   SG2D_OBJ_DUMP_PROPERTY_CONFLICTS = BIT(1),
     76   SG2D_OBJ_DUMP_VALID_PRIMITIVE = BIT(2),
     77   SG2D_OBJ_DUMP_ALL =
     78      SG2D_OBJ_DUMP_MERGE_CONFLICTS
     79    | SG2D_OBJ_DUMP_PROPERTY_CONFLICTS
     80    | SG2D_OBJ_DUMP_VALID_PRIMITIVE
     81 };
     82 
     83 /******************************************************************************
     84  * A type to list the different qualifiers of C code variable output.
     85  *****************************************************************************/
     86 enum sg2d_c_dump_qualifiers {
     87   SG2D_C_DUMP_CONST = BIT(0),
     88   SG2D_C_DUMP_STATIC = BIT(1)
     89 };
     90 
     91 /******************************************************************************
     92  * The value that should be used for properties attached to segments (i.e.
     93  * media or interface) when let unspecified.
     94  * SG2D_UNSPECIFIED_PROPERTY can be used for a property that has already been
     95  * defined; in this case the previous value will remain.
     96  *****************************************************************************/
     97 #define SG2D_UNSPECIFIED_PROPERTY UINT_MAX
     98 
     99  /*****************************************************************************
    100   * A type to hold callbacks for sg2d_geometry_add.
    101   ****************************************************************************/
    102 struct sg2d_geometry_add_callbacks {
    103   /* User function that provides vertices ids for added segments */
    104   void(*get_indices)
    105     (const unsigned iseg, unsigned ids[SG2D_GEOMETRY_DIMENSION], void* context);
    106   /* User function that provides properties for added segments */
    107   void(*get_properties) /* Can be NULL <=> SG2D_UNSPECIFIED_PROPERTY used */
    108     (const unsigned iseg,
    109      /* It is OK to have side and interface properties sharing the same IDs,
    110       * i.e. side and interface IDs both starting from 0 */
    111      unsigned properties[SG2D_PROP_TYPES_COUNT__],
    112      void* context);
    113   /* User function that provides coordinates for added vertices */
    114   void(*get_position)
    115     (const unsigned ivert, double pos[SG2D_GEOMETRY_DIMENSION], void* context);
    116   /* Called if the iseg_th segment of the current sg2d_geometry_add is a new
    117    * segment (i.e. not a duplicate) so that the client app can manage its own
    118    * segment data/properties/attributes.
    119    * If return is not RES_OK, sg2d_geometry_add stops immediately and returns
    120    * whatever value add_segment returned. */
    121   res_T(*add_segment) /* Can be NULL */
    122     (const unsigned unique_id, const unsigned iseg, void* context);
    123   /* Called if the iseg_th segment of the current sg2d_geometry_add is a
    124    * duplicate of the unique_id_th unique segment so that the client app can
    125    * merge its own segment data, rule merge validity, and possibly change the
    126    * recorded properties.
    127    * The reversed_segment arg indicates if the segment vertices' order is
    128    * the same it was when the segment was first added.
    129    * The merge_conflict_status argument can be set to any value. Any non-0
    130    * value is accounted for a conflict and is kept as-is in dumps, allowing
    131    * different shades of conflict.
    132    * The segment_properties and merged_properties args contain the involved
    133    * properties. */
    134   res_T(*merge_segment) /* Can be NULL */
    135     (const unsigned unique_id,
    136      const unsigned iseg,
    137      const int reversed_segment,
    138      unsigned segment_properties[SG2D_PROP_TYPES_COUNT__],
    139      const unsigned merged_properties[SG2D_PROP_TYPES_COUNT__],
    140      void* context,
    141      int* merge_conflict_status);
    142   /* Called if the iseg_th segment is degenerated. According to the value 
    143    * of abort, sg2d_geometry_add will stop and return RES_BAD_ARG or continue
    144    * silently. */
    145   res_T(*degenerated_segment) /* Can be NULL <=> Drop segment, don't abort */
    146     (const unsigned iseg, void* context, int* abort);
    147 };
    148 #define SG2D_ADD_CALLBACKS_NULL__ { NULL, NULL, NULL, NULL, NULL, NULL }
    149 
    150 BEGIN_DECLS
    151 
    152 /******************************************************************************
    153  * A helper function on properties compatibility.
    154  *****************************************************************************/
    155 static INLINE int
    156 sg2d_compatible_property
    157   (const unsigned p1,
    158    const unsigned p2)
    159 {
    160   if(p1 == SG2D_UNSPECIFIED_PROPERTY || p2 == SG2D_UNSPECIFIED_PROPERTY) return 1;
    161   return (p1 == p2);
    162 }
    163 
    164 /******************************************************************************
    165  * star-geometry device. It is an handle toward the star-geometry library.
    166  * It manages the star-geometry resources.
    167  *****************************************************************************/
    168 SG2D_API res_T
    169 sg2d_device_create
    170   (struct logger* logger, /* Can be NULL <=> use default logger */
    171    struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */
    172    const int verbose, /* Verbosity level */
    173    struct sg2d_device** dev);
    174 
    175 SG2D_API res_T
    176 sg2d_device_ref_get
    177   (struct sg2d_device* dev);
    178 
    179 SG2D_API res_T
    180 sg2d_device_ref_put
    181   (struct sg2d_device* dev);
    182 
    183 /******************************************************************************
    184  * star-geometry geometry.
    185  * It stores decorated geometry accumulated through calls to sg2d_geometry_add,
    186  * information related to this geometry and its creation process, including
    187  * merge conflicts.
    188  *****************************************************************************/
    189 /* Create a geometry that can be used to accumulate vertices and segments
    190  * decorated with properties. */
    191 SG2D_API res_T
    192 sg2d_geometry_create
    193   (struct sg2d_device* dev,
    194    struct sg2d_geometry** geometry);
    195 
    196 /* Reserve memory according to anticipated geometry size. */
    197 SG2D_API res_T
    198 sg2d_geometry_reserve
    199   (struct sg2d_geometry* geometry,
    200    const unsigned vertices_count,
    201    const unsigned segments_count,
    202    const unsigned properties_count);
    203 
    204 /* Add a new set of 2D vertices and segments to the geometry; segments can
    205  * be decorated with 3 properties (front and back media and interface) that can
    206  * be let unspecified using the SG2D_UNSPECIFIED_PROPERTY special value.
    207  * Vertices can be duplicates and are silently deduplicated, always valid.
    208  * Segments can be duplicates, but this can be ruled invalid due to property
    209  * inconsistency. Segment duplicates are silently deduplicated, even if
    210  * invalid. Consistency is to be understood as the consistency of the
    211  * successive values for the same property across calls of sg2d_geometry_add,
    212  * not as the consistency of the values of the 3 properties of a segment at
    213  * some given time (this question has its own callback (validate) in the
    214  * sg2d_geometry_validate_properties API call). 
    215  * Duplicate segments validity is either ruled by the user-provided
    216  * merge_segment callback, or is just a matter of properties consistency if no
    217  * callback is provided. In either case, sg2d_geometry_add never stops
    218  * prematurely nor returns an error code due to a merge conflict.
    219  * - if provided, the callback must return the consistency status using the
    220  *   merge_conflict_status int* paramater (0 for consistent; any other value
    221  *   for inconsistent, this value being recorded); regardless of
    222  *   merge_conflict_status, the callback can change the properties of the
    223  *   segment before the SG2D_UNSPECIFIED_PROPERTY overwriting step;
    224  * - if not, a non-SG2D_UNSPECIFIED_PROPERTY is only consistent with itself and
    225  *   with SG2D_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is
    226  *   set to 1 and recorded) ; regardless of merge_conflict_status, a
    227  *   non-SG2D_UNSPECIFIED_PROPERTY property is never overridden.
    228  * When deduplicating segments, the first occurence remains (with its
    229  * original index in user world). After consistency being computed, a final
    230  * step consists in rewriting SG2D_UNSPECIFIED_PROPERTY properties if the merged
    231  * property is defined. */
    232 SG2D_API res_T
    233 sg2d_geometry_add
    234   (struct sg2d_geometry* geometry,
    235    const unsigned vertices_count,
    236    const unsigned segments_count,
    237    const struct sg2d_geometry_add_callbacks* callbacks,
    238    void* context); /* Can be NULL */
    239 
    240 /* Apply a validation callback on each segment included in this geometry that
    241  * is not already flagged with a merge error. If validate returns a non-RES_OK
    242  * value, the validation stops and returns the same error value; on the other
    243  * hand, validation goes to the end regardless of properties conflicts.
    244  * The properties_conflict_status argument can be set to any value. Any non-0
    245  * value is accounted for a conflict and is kept as-is in dumps, allowing
    246  * different shades of conflict.
    247  * If validation is processed again, the properties conflict count is reset,
    248  * as well as the properties_conflict_status status of the segments. */
    249 SG2D_API res_T
    250 sg2d_geometry_validate_properties
    251   (struct sg2d_geometry* geometry,
    252    res_T(*validate)
    253      (const unsigned iseg,
    254       const unsigned properties[SG2D_PROP_TYPES_COUNT__],
    255       void* context,
    256       int* properties_conflict_status),
    257    void* context); /* Can be NULL */
    258 
    259 /* Get the number of unique vertices. */
    260 SG2D_API res_T
    261 sg2d_geometry_get_unique_vertices_count
    262   (const struct sg2d_geometry* geometry,
    263    unsigned* count);
    264 
    265 /* Get the ivtx_th vertex. */
    266 SG2D_API res_T
    267 sg2d_geometry_get_unique_vertex
    268   (const struct sg2d_geometry* geometry,
    269    const unsigned ivtx,
    270    double coord[SG2D_GEOMETRY_DIMENSION]);
    271 
    272 /* Get the number of segments added to the geometry, regardless of unicity. */
    273 SG2D_API res_T
    274 sg2d_geometry_get_added_segments_count
    275   (const struct sg2d_geometry* geometry,
    276    unsigned* count);
    277 
    278 /* Get the number of unique segments. */
    279 SG2D_API res_T
    280 sg2d_geometry_get_unique_segments_count
    281   (const struct sg2d_geometry* geometry,
    282    unsigned* count);
    283 
    284 /* Get the vertex indices of the iseg_th unique segment. */
    285 SG2D_API res_T
    286 sg2d_geometry_get_unique_segment_vertices
    287   (const struct sg2d_geometry* geometry,
    288    const unsigned iseg,
    289    unsigned indices[SG2D_GEOMETRY_DIMENSION]);
    290 
    291 /* Get the properties of the iseg_th unique segment. */
    292 SG2D_API res_T
    293 sg2d_geometry_get_unique_segment_properties
    294   (const struct sg2d_geometry* geometry,
    295    const unsigned iseg,
    296    unsigned properties[SG2D_PROP_TYPES_COUNT__]);
    297 
    298 /* Get the user ID of the iseg_th unique segment, that is the user world's
    299  * index of the segment that first created this unique segment.
    300  * User world index starts at 0 and increases for every segment that is
    301  * submitted to sg2d_geometry_add calls, regardless of duplication or
    302  * sg2d_geometry_add failures (non-RES_OK return value). */
    303 SG2D_API res_T
    304 sg2d_geometry_get_unique_segment_user_id
    305   (const struct sg2d_geometry* geometry,
    306    const unsigned iseg,
    307    unsigned* user_id);
    308 
    309 /* Get the number of segments with (at least) one unspecified side. */
    310 SG2D_API res_T
    311 sg2d_geometry_get_unique_segments_with_unspecified_side_count
    312   (const struct sg2d_geometry* geometry,
    313    unsigned* count);
    314 
    315 /* Get the number of segments with unspecified interface. */
    316 SG2D_API res_T
    317 sg2d_geometry_get_unique_segments_with_unspecified_interface_count
    318   (const struct sg2d_geometry* geometry,
    319    unsigned* count);
    320 
    321 /* Get the number of segments flagged with a merge conflict. */
    322 SG2D_API res_T
    323 sg2d_geometry_get_unique_segments_with_merge_conflict_count
    324   (const struct sg2d_geometry* geometry,
    325    unsigned* count);
    326 
    327 /* Get the number of segments flagged with a property conflict. Only meaningful
    328  * after sg2d_geometry_validate_properties has been called. */
    329 SG2D_API res_T
    330 sg2d_geometry_get_unique_segments_with_properties_conflict_count
    331   (const struct sg2d_geometry* geometry,
    332    unsigned* count);
    333 
    334 /* Dump a geometry in the provided stream in the OBJ format.
    335  * The geometry can include conflicts, but cannot be empty. Note that vertices
    336  * in this output are 3D with Z==0, as OBJ files cannot define 2D vertices.
    337  * The dump is made of the vertices and some segments, without their
    338  * properties. The dumped segments are defined by the flags argument, that
    339  * must be ORed enum sg2d_obj_dump_content values.
    340  * The dumped segments are partitioned in the following groups:
    341  * - Valid_segments
    342  * - Merge_conflicts
    343  * - Property_conflict */
    344 SG2D_API res_T
    345 sg2d_geometry_dump_as_obj
    346   (const struct sg2d_geometry* geometry,
    347    FILE* stream,
    348    const int flags);
    349 
    350 /* Dump a geometry in the provided stream in the VTK ascii format.
    351  * The geometry can include conflicts, but cannot be empty. Note that POINTS
    352  * in this output are 3D with Z==0, as VTK text files cannot define 2D POINTS.
    353  * The dump is made of the vertices and segments, with most of their
    354  * properties:
    355  * - Front_medium (medium ID of the front side, INT_MAX for both unspecified
    356  *   and conflicted)
    357  * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and
    358  *   conflicted)
    359  * - Interface (interface ID, INT_MAX for both unspecified and conflicted)
    360  * - Merge_conflict (merge conflict status)
    361  * - Property_conflict (property conflict status)
    362  * - Created_at_sg2d_geometry_add (rank of the sg2d_geometry_add that created the
    363  *   segment) */
    364 SG2D_API res_T
    365 sg2d_geometry_dump_as_vtk
    366   (const struct sg2d_geometry* geometry,
    367    FILE* stream);
    368 
    369 /* Dump the geometry as C code.
    370  * The geometry cannot be empty and must be conflict-free.
    371  * The C code defines the 5 variables:
    372  * - [static] [const] unsigned <name_prefix>_vertices_count = N1;
    373  * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... };
    374  * - [static] [const] unsigned <name_prefix>_segments_count = N2;
    375  * - [static] [const] unsigned <name_prefix>_segments[<N2>] = { .... };
    376  * - [static] [const] unsigned <name_prefix>_properties[<N3>] = { .... };
    377  * Where <N1> is 2 * vertices_count, <N2> is 2 * segments_count and <N3> is
    378  * 3 * segments_count.
    379  * The two qualifiers static and const are output or not according to flags;
    380  * flags must be ORed enum sg2d_c_dump_qualifiers values. */
    381 SG2D_API res_T
    382 sg2d_geometry_dump_as_c_code
    383   (const struct sg2d_geometry* geometry,
    384    FILE* stream,
    385    const char* name_prefix, /* Can be NULL or "" */
    386    const int flags);
    387 
    388 SG2D_API res_T
    389 sg2d_geometry_ref_get
    390   (struct sg2d_geometry* geometry);
    391 
    392 SG2D_API res_T
    393 sg2d_geometry_ref_put
    394   (struct sg2d_geometry* geometry);
    395 
    396 END_DECLS
    397 
    398 #endif /* STAR_GEOMETRY_2D_H__ */