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:
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];
}