star-enclosures-2d

Extract enclosures from 2D geometry
git clone git://git.meso-star.fr/star-enclosures-2d.git
Log | Files | Refs | README | LICENSE

commit 0bd40758ecdebec80ca453607d902a1b6ac0fa1b
parent 03fdc536e376e12be60172cc0293adea915c4e7e
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 25 Oct 2019 18:01:59 +0200

Make possible to add geometry with some side's media undefined

 Allows to create geometry on-the-fly, in multiple rounds

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/senc2d.h | 8+++++++-
Msrc/senc2d_scene.c | 61++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/senc2d_scene_analyze.c | 14++++++++++----
Msrc/senc2d_scene_c.h | 7+++----
Msrc/test_senc2d_utils.h | 19+++++++++++--------
6 files changed, 76 insertions(+), 34 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -130,6 +130,7 @@ if(NOT NO_TEST) new_test(test_senc2d_many_segments) new_test(test_senc2d_sample_enclosure) new_test(test_senc2d_scene) + new_test(test_senc2d_undefined_medium) target_link_libraries(test_senc2d_sample_enclosure StarSP) rcmake_copy_runtime_libraries(test_senc2d_sample_enclosure) diff --git a/src/senc2d.h b/src/senc2d.h @@ -40,6 +40,9 @@ * as CPU cores */ #define SENC2D_NTHREADS_DEFAULT (~0u) +/* A constant to specify an undefined medium */ +#define SENC2D_UNDEFINED_MEDIUM UINT_MAX + /* Forward declaration of external opaque data types */ struct logger; struct mem_allocator; @@ -162,6 +165,8 @@ senc2d_scene_reserve * Vertices can be duplicates and are deduplicated on the fly. * Segments can be duplicates as long as they constantly define the same * medium on both sides (or an error will be reported) and are deduplicated. + * The special value SENC2D_UNDEFINED_MEDIUM denotes an undefined medium. + * It can be used to define the 2 sides of a segment at different times. * When deduplicating segments, the first occurence is kept (with its original * global_id). Users can provide their own global ids for segments; these ids * are not used by the library but are returned as-is by some API calls. */ @@ -177,7 +182,8 @@ senc2d_scene_add_geometry void(*position)(const unsigned ivert, double pos[2], void* context), void* context); -/* Returns a descriptor of the scene that holds the analysis' result. */ +/* Returns a descriptor of the scene that holds the analysis' result. + * Its an error that some segment side still has undefined medium. */ SENC2D_API res_T senc2d_scene_analyze (struct senc2d_scene* scene, diff --git a/src/senc2d_scene.c b/src/senc2d_scene.c @@ -42,6 +42,15 @@ scene_release(ref_T * ref) SENC2D(device_ref_put(dev)); } +static INLINE int +compatible_medium + (const medium_id_t m1, + const medium_id_t m2) +{ + if(m1 == SENC2D_UNDEFINED_MEDIUM || m2 == SENC2D_UNDEFINED_MEDIUM) return 1; + return (m1 == m2); +} + /******************************************************************************* * Exported functions ******************************************************************************/ @@ -76,6 +85,7 @@ senc2d_scene_create scn->nmeds = 0; scn->nverts = 0; scn->nuverts = 0; + scn->sides_with_defined_medium_count = 0; darray_segment_in_init(dev->allocator, &scn->segments_in); darray_position_init(dev->allocator, &scn->vertices); htable_vrtx_init(dev->allocator, &scn->unique_vertices); @@ -169,8 +179,8 @@ senc2d_scene_add_geometry } else { /* New vertex */ unique_v = scn->nuverts + actual_nuverts; - OK(darray_position_push_back(&scn->vertices, &tmp)); ASSERT(unique_v == htable_vrtx_size_get(&scn->unique_vertices)); + OK(darray_position_push_back(&scn->vertices, &tmp)); OK(htable_vrtx_set(&scn->unique_vertices, &tmp, &unique_v)); ++actual_nuverts; } @@ -185,7 +195,7 @@ senc2d_scene_add_geometry unsigned med[2]; unsigned ind[2]; union vrtx_id2 seg_key; - struct segment_in tmp; + struct segment_in tmp, *range_adjust_ptr = NULL; seg_id_t* p_seg; char reversed; if(global_id) { @@ -215,11 +225,10 @@ senc2d_scene_add_geometry goto error; } /* Get media */ - media(i, med, ctx); /* API: media needs an unsigned */ + media(i, med, ctx); /* API: media need unsigneds */ FOR_EACH(j, 0, 2) { - if(med[j] >= scn->nmeds) { - /* New medium */ - ASSERT(med[j] <= MEDIUM_MAX__); + if(med[j] != SENC2D_UNDEFINED_MEDIUM && med[j] >= scn->nmeds) { + ASSERT(med[j] < MEDIUM_MAX__); scn->nmeds = 1 + med[j]; darray_side_range_resize(&scn->media_use, scn->nmeds); } @@ -235,9 +244,11 @@ senc2d_scene_add_geometry const medium_id_t* umed; /* Duplicate segment. Need to check duplicate validity */ ASSERT(seg_key_eq(&seg_key, &useg_key)); + if(!same) SWAP(unsigned, tmp.medium[0], tmp.medium[1]); umed = seg[*p_seg].medium; - if(umed[0] != (same ? med[0] : med[1]) - || umed[1] != (same ? med[1] : med[0])) { + if(!compatible_medium(umed[0], tmp.medium[0]) + || !compatible_medium(umed[1], tmp.medium[1])) + { /* Same segments with different media: invalid! */ const union double2* positions = darray_position_cdata_get(&scn->vertices); @@ -253,8 +264,8 @@ senc2d_scene_add_geometry log_err(scn->dev, "Media: (%lu, %lu) VS (%lu, %lu)\n", (unsigned long)umed[ureversed? 1 : 0], (unsigned long)umed[ureversed ? 0 : 1], - (unsigned long)med[reversed ? 1 : 0], - (unsigned long)med[reversed ? 0 : 1]); + (unsigned long)tmp.medium[reversed ? 1 : 0], + (unsigned long)tmp.medium[reversed ? 0 : 1]); res = RES_BAD_ARG; goto error; } else { @@ -262,29 +273,45 @@ senc2d_scene_add_geometry log_warn(scn->dev, "%s: segment %lu is a duplicate of segment %lu.\n", FUNC_NAME, (unsigned long)tmp.global_id, (unsigned long)seg[*p_seg].global_id); - if(!same) { - FOR_EACH(j, 0, 2) { - tmp.medium[j] = (medium_id_t)med[1-j]; + range_adjust_ptr = darray_segment_in_data_get(&scn->segments_in) + *p_seg; + /* Replace possible undefined media */ + FOR_EACH(j, 0, 2) { + if(range_adjust_ptr->medium[j] == SENC2D_UNDEFINED_MEDIUM + && tmp.medium[j] != SENC2D_UNDEFINED_MEDIUM) { + range_adjust_ptr->medium[j] = tmp.medium[j]; + scn->sides_with_defined_medium_count++; } } } } else { /* New segment */ seg_id_t u = scn->nusegs + actual_nusegs; - struct side_range* media_use; ASSERT(u == htable_seg_size_get(&scn->unique_segments)); OK(htable_seg_set(&scn->unique_segments, &seg_key, &u)); OK(darray_segment_in_push_back(&scn->segments_in, &tmp)); + range_adjust_ptr = darray_segment_in_data_get(&scn->segments_in) + u; FOR_EACH(j, 0, 2) { + if(tmp.medium[j] != SENC2D_UNDEFINED_MEDIUM) + scn->sides_with_defined_medium_count++; + } + ++actual_nusegs; + } + if (range_adjust_ptr) { + ptrdiff_t u = range_adjust_ptr - seg; + ASSERT(u < scn->nusegs + actual_nusegs && u < SEG_MAX__); + FOR_EACH(j, 0, 2) { + struct side_range* media_use; + if (tmp.medium[j] == SENC2D_UNDEFINED_MEDIUM) continue; ASSERT(tmp.medium[j] < scn->nmeds); media_use = darray_side_range_data_get(&scn->media_use) + tmp.medium[j]; - media_use->first = MMIN(media_use->first, SEGIDxSIDE_2_SEGSIDE(u, j)); + media_use->first = + MMIN(media_use->first, SEGIDxSIDE_2_SEGSIDE((seg_id_t)u, j)); ASSERT(media_use->first < 2 * (scn->nusegs + actual_nusegs + 1)); - media_use->last = MMAX(media_use->last, SEGIDxSIDE_2_SEGSIDE(u, j)); + media_use->last = + MMAX(media_use->last, SEGIDxSIDE_2_SEGSIDE((seg_id_t)u, j)); ASSERT(media_use->last < 2 * (scn->nusegs + actual_nusegs + 1)); ASSERT(media_use->first <= media_use->last); } - ++actual_nusegs; } ++actual_nsegs; } diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c @@ -147,7 +147,7 @@ extract_connex_components { /* This function is called from an omp parallel block and executed * concurrently. */ - const struct senc2d_scene* scn; + struct senc2d_scene* scn; struct mem_allocator* alloc; int64_t mm; struct darray_side_id stack; @@ -498,7 +498,7 @@ canceled: ASSERT(desc->scene->nuverts < UINT_MAX); OK(s2d_line_segments_setup_indexed_vertices(s2d_shp, (unsigned)desc->scene->nusegs, get_scn_indices, - (unsigned)desc->scene->nuverts, &attribs, 1, desc->scene)); + (unsigned)desc->scene->nuverts, &attribs, 1, scn)); s2d_line_segments_set_hit_filter_function(s2d_shp, self_hit_filter, segments_comp_array); OK(s2d_scene_attach_shape(s2d_scn, s2d_shp)); @@ -691,8 +691,8 @@ collect_and_link_neighbours * concurrently. * Resize / Push operations on neighbourhood_by_vertex are valid * because each neighbourhood is processes by an unique thread */ - const struct segment_in *segments_in; - struct segment_tmp *segments_tmp; + const struct segment_in* segments_in; + struct segment_tmp* segments_tmp; const union double2* vertices; const int thread_count = omp_get_num_threads(); const int rank = omp_get_thread_num(); @@ -1143,6 +1143,12 @@ senc2d_scene_analyze if(!scn || !out_desc) return RES_BAD_ARG; + if(scn->sides_with_defined_medium_count < 2 * scn->nusegs) { + log_err(scn->dev, + "%s: not all segments have defined media on both sides.\n", FUNC_NAME); + return RES_BAD_ARG; + } + /* The first part of the analyze is single threaded */ desc = descriptor_create(scn); if(!desc) { diff --git a/src/senc2d_scene_c.h b/src/senc2d_scene_c.h @@ -52,21 +52,19 @@ struct segment_in { unsigned global_id; }; -#ifndef NDEBUG static FINLINE void segment_in_init(struct mem_allocator* alloc, struct segment_in* seg) { int i; (void)alloc; ASSERT(seg); FOR_EACH(i, 0, 2) seg->vertice_id[i] = VRTX_NULL__; - FOR_EACH(i, 0, 2) seg->medium[i] = MEDIUM_NULL__; + FOR_EACH(i, 0, 2) seg->medium[i] = SENC2D_UNDEFINED_MEDIUM; seg->global_id = 0; } -#define DARRAY_FUNCTOR_INIT segment_in_init -#endif #define DARRAY_NAME segment_in #define DARRAY_DATA struct segment_in +#define DARRAY_FUNCTOR_INIT segment_in_init #include <rsys/dynamic_array.h> static FINLINE void @@ -179,6 +177,7 @@ struct senc2d_scene { vrtx_id_t nverts, nuverts; /* Vrtx count, unique vrtx count */ medium_id_t nmeds; struct darray_side_range media_use; + side_id_t sides_with_defined_medium_count; ref_T ref; struct senc2d_device* dev; diff --git a/src/test_senc2d_utils.h b/src/test_senc2d_utils.h @@ -23,6 +23,9 @@ #include <stdio.h> +#define OK(Expr) CHK((Expr) == RES_OK) +#define BA(Expr) CHK((Expr) == RES_BAD_ARG) + /******************************************************************************* * Geometry ******************************************************************************/ @@ -84,36 +87,36 @@ static const unsigned medium1_front0[4] = { 1, 0, 1, 1 }; static const unsigned gid_face[4] = { 0, 1, 2, 3 }; static INLINE void -get_indices(const unsigned iseg, unsigned ids[2], void* context) +get_indices(const unsigned iseg, unsigned ids[2], const void* context) { - struct context* ctx = context; + const struct context* ctx = context; ASSERT(ids && ctx); ids[ctx->reverse_vrtx ? 1 : 0] = ctx->indices[iseg * 2 + 0]; ids[ctx->reverse_vrtx ? 0 : 1] = ctx->indices[iseg * 2 + 1]; } static INLINE void -get_position(const unsigned ivert, double pos[2], void* context) +get_position(const unsigned ivert, double pos[2], const void* context) { - struct context* ctx = context; + const struct context* ctx = context; ASSERT(pos && ctx); pos[0] = ctx->positions[ivert * 2 + 0] * ctx->scale + ctx->offset[0]; pos[1] = ctx->positions[ivert * 2 + 1] * ctx->scale + ctx->offset[1]; } static INLINE void -get_media(const unsigned iseg, unsigned medium[2], void* context) +get_media(const unsigned iseg, unsigned medium[2], const void* context) { - struct context* ctx = context; + const struct context* ctx = context; ASSERT(medium && ctx); medium[ctx->reverse_med ? 1 : 0] = ctx->front_media[iseg]; medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[iseg]; } static INLINE void -get_global_id(const unsigned iseg, unsigned* gid, void* context) +get_global_id(const unsigned iseg, unsigned* gid, const void* context) { - struct context* ctx = context; + const struct context* ctx = context; ASSERT(gid && context); *gid = ctx->global_ids[iseg]; }