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__ */