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