commit 3615bb2ade2ec25ab0e5e55c634ff41d93b304de
parent 03fdc536e376e12be60172cc0293adea915c4e7e
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Thu, 31 Oct 2019 15:51:15 +0100
Merge branch 'feature_geom_multi_add' into develop
Diffstat:
12 files changed, 587 insertions(+), 92 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;
@@ -66,7 +69,8 @@ struct senc2d_enclosure_header {
unsigned unique_segment_count;
/* Number of vertices */
unsigned vertices_count;
- /* The number of media inside the enclosure */
+ /* The number of media inside the enclosure,
+ * SENC2D_UNDEFINED_MEDIUM included */
unsigned enclosed_media_count;
/* Is the enclosure infinite?
* Only the outermost enclosure is infinite. */
@@ -155,13 +159,16 @@ SENC2D_API res_T
senc2d_scene_reserve
(struct senc2d_scene* scene,
const unsigned vertices_count,
- const unsigned triangles_count,
+ const unsigned segments_count,
const unsigned media_count);
/* Add a new set of vertices and segments to the scene.
* 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.
+ * medium on both sides (or an error will be reported, with the exception
+ * of SENC_UNDEFINED_MEDIUM that causes no error) 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. */
@@ -170,9 +177,10 @@ senc2d_scene_add_geometry
(struct senc2d_scene* scene,
const unsigned segments_count,
void(*indices)(const unsigned iseg, unsigned ids[2], void* context),
- void(*media)(const unsigned iseg, unsigned med[2], void* context),
- void(*global_id) /* May be NULL <=> use segment rank */
- (const unsigned iseg, unsigned* gid, void* context),
+ void(*media) /* Can be NULL <=> SENC2D_UNDEFINED_MEDIUM medium used */
+ (const unsigned iseg, unsigned med[2], void* context),
+ void(*global_id) /* Can be NULL <=> use segment rank */
+ (const unsigned iseg, unsigned* gid, void* context),
const unsigned vertices_count,
void(*position)(const unsigned ivert, double pos[2], void* context),
void* context);
@@ -202,6 +210,30 @@ senc2d_scene_get_unique_segments_count
(const struct senc2d_scene* scene,
unsigned* count);
+/* Returns the number of unique sides with SENC2D_UNDEFINED_MEDIUM medium. */
+SENC2D_API res_T
+senc2d_scene_get_unique_sides_without_medium_count
+ (const struct senc2d_scene* scene,
+ unsigned* count);
+
+/* Returns the iseg_th unique segment; the returned indices are
+ * unique vertex indices.
+ * Can be called anytime, before or after a call to analyze. */
+SENC2D_API res_T
+senc2d_scene_get_unique_segment
+ (const struct senc2d_scene* scene,
+ const unsigned iseg,
+ unsigned indices[2]);
+
+/* Returns the iseg_th unique segment; the returned indices are
+ * unique vertex indices.
+ * Can be called anytime, before or after a call to analyze. */
+SENC2D_API res_T
+senc2d_scene_get_unique_segment_media
+ (const struct senc2d_scene* scene,
+ const unsigned iseg,
+ unsigned media[2]);
+
/* Returns the number of vertices in the scene. */
SENC2D_API res_T
senc2d_scene_get_vertices_count
@@ -215,6 +247,14 @@ senc2d_scene_get_unique_vertices_count
(const struct senc2d_scene* scene,
unsigned* count);
+/* Returns the coordinates of the ivert_th unique vertex.
+ * Can be called anytime, before or after a call to analyze. */
+SENC2D_API res_T
+senc2d_scene_get_unique_vertex
+ (const struct senc2d_scene* scene,
+ const unsigned ivert,
+ double coord[2]);
+
SENC2D_API res_T
senc2d_scene_ref_get
(struct senc2d_scene* scene);
diff --git a/src/senc2d_descriptor.c b/src/senc2d_descriptor.c
@@ -61,7 +61,8 @@ descriptor_create(struct senc2d_scene* scn)
darray_enclosure_init(scn->dev->allocator, &desc->enclosures);
darray_enc_ids_array_init(scn->dev->allocator,
&desc->enc_ids_array_by_medium);
- OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium, scn->nmeds));
+ OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium,
+ 1 + scn->next_medium_idx)); /* +1 is for undef */
darray_vrtx_id_init(scn->dev->allocator, &desc->frontiers);
/* Enclosure 0 is always defined for infinite */
OK(darray_enclosure_resize(&desc->enclosures, 1));
@@ -91,8 +92,8 @@ senc2d_descriptor_get_max_medium
(const struct senc2d_descriptor* desc, unsigned* max_medium_id)
{
if(!desc || !max_medium_id) return RES_BAD_ARG;
- ASSERT(desc->scene->nmeds < UINT_MAX); /* API type */
- *max_medium_id = (unsigned)desc->scene->nmeds - 1;
+ ASSERT(desc->scene->next_medium_idx < UINT_MAX); /* API type */
+ *max_medium_id = (unsigned)desc->scene->next_medium_idx - 1;
return RES_OK;
}
@@ -115,14 +116,16 @@ senc2d_descriptor_get_enclosure_count_by_medium
const unsigned imed,
unsigned* count)
{
- size_t tmp;
+ size_t tmp, m_idx;
const struct darray_enc_id* enc_ids;
- if(!desc || !count || imed >= desc->scene->nmeds)
+ if(!desc || !count
+ || (imed != SENC2D_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx))
return RES_BAD_ARG;
ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
- == desc->scene->nmeds);
- enc_ids =
- darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed;
+ == 1 + desc->scene->next_medium_idx);
+ m_idx = (imed == SENC2D_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed;
+ enc_ids = darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium)
+ + m_idx;
tmp = darray_enc_id_size_get(enc_ids);
ASSERT(tmp < UINT_MAX); /* API type */
*count = (unsigned)tmp;
@@ -151,11 +154,17 @@ senc2d_descriptor_get_enclosure_by_medium
const unsigned idx,
struct senc2d_enclosure** out_enc)
{
+ size_t m_idx;
const struct darray_enc_id* enc_ids;
unsigned index;
- if(!desc || imed >= desc->scene->nmeds || !out_enc) return RES_BAD_ARG;
+ if(!desc || !out_enc
+ || (imed != SENC2D_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx))
+ return RES_BAD_ARG;
+ ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
+ == 1 + desc->scene->next_medium_idx);
+ m_idx = (imed == SENC2D_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed;
enc_ids =
- darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed;
+ darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + m_idx;
if(idx >= darray_enc_id_size_get(enc_ids)) return RES_BAD_ARG;
index = darray_enc_id_cdata_get(enc_ids)[idx];
return senc2d_descriptor_get_enclosure(desc, index, out_enc);
diff --git a/src/senc2d_enclosure_data.h b/src/senc2d_enclosure_data.h
@@ -83,23 +83,24 @@ error:
static FINLINE res_T
bool_array_of_media_to_darray_media
(struct darray_media* dst,
- struct darray_uchar* src)
+ struct darray_uchar* src,
+ const medium_id_t undef_idx)
{
res_T res = RES_OK;
medium_id_t i;
- size_t sz;
const unsigned char* data;
ASSERT(src && dst);
data = darray_uchar_cdata_get(src);
- sz = darray_uchar_size_get(src);
- ASSERT(sz <= MEDIUM_MAX__);
+ ASSERT(undef_idx + 1 == darray_uchar_size_get(src));
+ ASSERT(undef_idx < MEDIUM_MAX__);
darray_media_clear(dst);
if(res != RES_OK) goto error;
- FOR_EACH(i, 0, (medium_id_t)sz) {
+ FOR_EACH(i, 0, undef_idx + 1) {
+ medium_id_t v = (i == undef_idx) ? SENC2D_UNDEFINED_MEDIUM : i;
if(!data[i]) continue;
- res = darray_media_push_back(dst, &i);
+ res = darray_media_push_back(dst, &v);
if(res != RES_OK) goto error;
}
end:
diff --git a/src/senc2d_scene.c b/src/senc2d_scene.c
@@ -18,6 +18,7 @@
#include "senc2d_scene_c.h"
#include <rsys/rsys.h>
+#include <rsys/double2.h>
#include <rsys/mem_allocator.h>
#include <limits.h>
@@ -42,6 +43,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
******************************************************************************/
@@ -73,9 +83,10 @@ senc2d_scene_create
scn->ngeoms = 0;
scn->nsegs = 0;
scn->nusegs = 0;
- scn->nmeds = 0;
+ scn->next_medium_idx = 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);
@@ -97,16 +108,16 @@ res_T
senc2d_scene_reserve
(struct senc2d_scene* scn,
const unsigned vertices_count,
- const unsigned triangles_count,
+ const unsigned segments_count,
const unsigned media_count)
{
res_T res = RES_OK;
if(!scn) return RES_BAD_ARG;
OK(darray_position_reserve(&scn->vertices, vertices_count));
- OK(darray_segment_in_reserve(&scn->segments_in, triangles_count));
+ OK(darray_segment_in_reserve(&scn->segments_in, segments_count));
OK(htable_vrtx_reserve(&scn->unique_vertices, vertices_count));
- OK(htable_seg_reserve(&scn->unique_segments, triangles_count));
+ OK(htable_seg_reserve(&scn->unique_segments, segments_count));
OK(darray_side_range_reserve(&scn->media_use, media_count));
end:
@@ -136,7 +147,7 @@ senc2d_scene_add_geometry
res_T res = RES_OK;
if(!scn
- || !indices || !media || !position
+ || !indices || !position
|| !nverts || ((size_t)scn->nverts + (size_t)nverts) > VRTX_MAX__
|| !nsegs || ((size_t)scn->nsegs + (size_t)nsegs) > SEG_MAX__)
return RES_BAD_ARG;
@@ -169,8 +180,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;
}
@@ -182,10 +193,10 @@ senc2d_scene_add_geometry
FOR_EACH(i, 0, nsegs) {
int j;
- unsigned med[2];
+ unsigned med[2] = { SENC2D_UNDEFINED_MEDIUM, SENC2D_UNDEFINED_MEDIUM };
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,13 +226,12 @@ senc2d_scene_add_geometry
goto error;
}
/* Get media */
- media(i, med, ctx); /* API: media needs an unsigned */
+ if(media) 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__);
- scn->nmeds = 1 + med[j];
- darray_side_range_resize(&scn->media_use, scn->nmeds);
+ if(med[j] != SENC2D_UNDEFINED_MEDIUM && med[j] >= scn->next_medium_idx) {
+ ASSERT(med[j] < MEDIUM_MAX__);
+ scn->next_medium_idx = 1 + med[j];
+ darray_side_range_resize(&scn->media_use, scn->next_medium_idx);
}
tmp.medium[j] = (medium_id_t)med[j];
}
@@ -235,9 +245,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 +265,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 +274,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) {
- ASSERT(tmp.medium[j] < scn->nmeds);
+ struct side_range* media_use;
+ if(tmp.medium[j] == SENC2D_UNDEFINED_MEDIUM) continue;
+ ASSERT(tmp.medium[j] < scn->next_medium_idx);
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;
}
@@ -336,6 +364,57 @@ senc2d_scene_get_unique_segments_count
}
res_T
+senc2d_scene_get_unique_sides_without_medium_count
+ (const struct senc2d_scene* scn,
+ unsigned* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ ASSERT(2 * scn->nusegs >= scn->sides_with_defined_medium_count);
+ *count = 2 * scn->nusegs - scn->sides_with_defined_medium_count;
+ return RES_OK;
+}
+
+res_T
+senc2d_scene_get_unique_segment
+ (const struct senc2d_scene* scn,
+ const unsigned iseg,
+ unsigned indices[2])
+{
+ const struct segment_in* seg;
+ int i;
+ if(!scn || !indices
+ || iseg >= darray_segment_in_size_get(&scn->segments_in))
+ return RES_BAD_ARG;
+ seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg;
+
+ FOR_EACH(i, 0, 2) {
+ ASSERT(seg->vertice_id[i] < UINT_MAX);
+ indices[i] = (unsigned)seg->vertice_id[i]; /* Back to API type */
+ }
+ return RES_OK;
+}
+
+res_T
+senc2d_scene_get_unique_segment_media
+ (const struct senc2d_scene* scn,
+ const unsigned iseg,
+ unsigned media[2])
+{
+ const struct segment_in* seg;
+ int i;
+ if(!scn || !media
+ || iseg >= darray_segment_in_size_get(&scn->segments_in))
+ return RES_BAD_ARG;
+ seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg;
+
+ FOR_EACH(i, 0, 2) {
+ ASSERT(seg->vertice_id[i] < UINT_MAX);
+ media[i] = (unsigned)seg->medium[i]; /* Back to API type */
+ }
+ return RES_OK;
+}
+
+res_T
senc2d_scene_get_vertices_count
(const struct senc2d_scene* scn,
unsigned* count)
@@ -356,6 +435,23 @@ senc2d_scene_get_unique_vertices_count
}
res_T
+senc2d_scene_get_unique_vertex
+ (const struct senc2d_scene* scn,
+ const unsigned ivert,
+ double coord[2])
+{
+
+ const union double2* v;
+ if(!scn || !coord
+ || ivert >= darray_position_size_get(&scn->vertices))
+ return RES_BAD_ARG;
+
+ v = darray_position_cdata_get(&scn->vertices) + ivert;
+ d2_set(coord, v->vec);
+ return RES_OK;
+}
+
+res_T
senc2d_scene_ref_get(struct senc2d_scene* scn)
{
if(!scn) return RES_BAD_ARG;
diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c
@@ -147,9 +147,9 @@ 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;
+ int64_t mm, undefs;
struct darray_side_id stack;
struct darray_side_id ids_of_sides_around_max_y_vertex;
const union double2* positions;
@@ -179,6 +179,19 @@ extract_connex_components
return;
}
+ /* If there are sides with undefined medium, its like another medium */
+ undefs = (scn->sides_with_defined_medium_count < 2 * scn->nsegs) ? 1 : 0;
+#pragma omp single
+ {
+ if(undefs) {
+ /* Range is unknown, process each side */
+ struct side_range und;
+ und.first = 0;
+ und.last = 2 * scn->nsegs - 1;
+ darray_side_range_push_back(&scn->media_use, &und);
+ }
+ } /* Implicit barrier here */
+
#ifndef NDEBUG
#pragma omp single
{
@@ -191,7 +204,8 @@ extract_connex_components
= darray_side_range_cdata_get(&scn->media_use);
FOR_EACH(mm, 0, 2) {
const side_id_t side = SEGIDxSIDE_2_SEGSIDE(s_, mm);
- const medium_id_t medium = seg_in->medium[mm];
+ medium_id_t medium = seg_in->medium[mm];
+ if(medium == SENC2D_UNDEFINED_MEDIUM) medium = scn->next_medium_idx;
ASSERT(media_use[medium].first <= side && side
<= media_use[medium].last);
}
@@ -201,11 +215,14 @@ extract_connex_components
/* We loop on sides to build connex components. */
#pragma omp for schedule(dynamic) nowait
- for(mm = 0; mm < (int64_t)scn->nmeds; mm++) { /* Process all media */
- const medium_id_t m = (medium_id_t)mm;
+ /* Process all media, including undef */
+ for(mm = 0; mm < undefs + (int64_t)scn->next_medium_idx; mm++) {
+ const medium_id_t m_idx = (medium_id_t)mm;
+ const medium_id_t m = (mm == scn->next_medium_idx)
+ ? SENC2D_UNDEFINED_MEDIUM : (medium_id_t)mm;
/* Any not-already-used side is used as a starting point */
const struct side_range* media_use =
- darray_side_range_cdata_get(&scn->media_use) + m;
+ darray_side_range_cdata_get(&scn->media_use) + m_idx;
side_id_t first_side_not_in_component = media_use->first;
double max_ny;
side_id_t max_ny_side_id = SIDE_NULL__;
@@ -249,15 +266,15 @@ extract_connex_components
/* Reuse array if possible, or create a new one */
if(current_media) {
- memset(current_media, 0, scn->nmeds);
+ memset(current_media, 0, scn->next_medium_idx);
} else {
- current_media = MEM_CALLOC(alloc, scn->nmeds, sizeof(unsigned char));
+ current_media = MEM_CALLOC(alloc, 1 + scn->next_medium_idx, sizeof(unsigned char));
if(!current_media) {
*p_res = RES_MEM_ERR;
continue;
}
}
- current_media[m] = 1;
+ current_media[m_idx] = 1;
for(;;) { /* Process all sides of this component */
int i;
enum side_flag crt_side_flag = SEGSIDE_2_SIDEFLAG(crt_side_id);
@@ -316,6 +333,8 @@ extract_connex_components
enum side_flag nbour_side_id = SEGSIDE_2_SIDEFLAG(neighbour_id);
unsigned char* nbour_used = processed + nbour_seg_id;
const struct segside* neighbour = segsides + neighbour_id;
+ medium_id_t nbour_med_idx = (neighbour->medium == SENC2D_UNDEFINED_MEDIUM)
+ ? scn->next_medium_idx : neighbour->medium;
if(neighbour->medium < m
|| (*nbour_used & (unsigned char)SIDE_CANCELED_FLAG(nbour_side_id)))
{
@@ -352,7 +371,7 @@ extract_connex_components
*nbour_used |= (unsigned char)nbour_side_id;
OK2(darray_side_id_push_back(&stack, &neighbour_id));
OK2(darray_side_id_push_back(¤t_component, &neighbour_id));
- current_media[neighbour->medium] = 1;
+ current_media[nbour_med_idx] = 1;
}
sz = darray_side_id_size_get(&stack);
if(sz == 0) break; /* Empty stack => component is done! */
@@ -493,12 +512,12 @@ canceled:
OK(s2d_scene_create(s2d, &s2d_scn));
OK(s2d_shape_create_line_segments(s2d, &s2d_shp));
- /* Back to API type for ntris and nverts */
+ /* Back to API type for nsegs and nverts */
ASSERT(desc->scene->nusegs < UINT_MAX);
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));
@@ -665,7 +684,7 @@ group_connex_components
enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last);
enc->side_count += cc->side_count;
tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media,
- desc->scene->nmeds);
+ desc->scene->next_medium_idx + 1);
if(tmp_res != RES_OK) {
*res = tmp_res;
break;
@@ -691,8 +710,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();
@@ -882,8 +901,10 @@ collect_and_link_neighbours
|| p_ccw_side->medium == segments_in[ccw_id].medium[ccw_side]);
p_crt_side->medium = segments_in[crt_id].medium[crt_side];
p_ccw_side->medium = segments_in[ccw_id].medium[ccw_side];
- ASSERT(p_crt_side->medium < scn->nmeds);
- ASSERT(p_ccw_side->medium < scn->nmeds);
+ ASSERT(p_crt_side->medium == SENC2D_UNDEFINED_MEDIUM
+ || p_crt_side->medium < scn->next_medium_idx);
+ ASSERT(p_ccw_side->medium == SENC2D_UNDEFINED_MEDIUM
+ || p_ccw_side->medium < scn->next_medium_idx);
/* Detect segments that could surround a hole:
* - single segments on (one of) its end
* - different media on its sides */
@@ -994,9 +1015,9 @@ build_result
enc->header.is_infinite = (e == 0);
ASSERT(darray_uchar_size_get(&enc->tmp_enclosed_media) <= UINT_MAX);
- ASSERT(enc->header.enclosed_media_count <= scn->nmeds);
+ ASSERT(enc->header.enclosed_media_count < 1 + scn->next_medium_idx);
OK2(bool_array_of_media_to_darray_media
- (&enc->enclosed_media, &enc->tmp_enclosed_media));
+ (&enc->enclosed_media, &enc->tmp_enclosed_media, scn->next_medium_idx));
enc->header.enclosed_media_count
= (unsigned)darray_media_size_get(&enc->enclosed_media);
darray_uchar_purge(&enc->tmp_enclosed_media);
@@ -1004,8 +1025,14 @@ build_result
/* Add this enclosure in relevant by-medium lists */
FOR_EACH(m, 0, enc->header.enclosed_media_count) {
medium_id_t medium = darray_media_data_get(&enc->enclosed_media)[m];
- struct darray_enc_id* enc_ids_by_medium =
- darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + medium;
+ size_t m_idx = (medium == SENC2D_UNDEFINED_MEDIUM)
+ ? scn->next_medium_idx : medium;
+ struct darray_enc_id* enc_ids_by_medium;
+ ASSERT(medium == SENC2D_UNDEFINED_MEDIUM || medium < scn->next_medium_idx);
+ ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
+ == 1 + scn->next_medium_idx);
+ enc_ids_by_medium =
+ darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + m_idx;
#pragma omp critical
{
tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e);
@@ -1058,7 +1085,7 @@ build_result
ASSERT(segments_enc[s].enclosure[SIDE_FRONT] == e
|| segments_enc[s].enclosure[SIDE_BACK] == e);
if(segments_enc[s].enclosure[SIDE_FRONT] == e) {
- /* Front side of the original triangle is member of the enclosure */
+ /* Front side of the original segment is member of the enclosure */
int input_normal_in = normals_front;
int revert_segment = (input_normal_in != output_normal_in);
++enc->header.segment_count;
@@ -1074,7 +1101,7 @@ build_result
}
}
if(segments_enc[s].enclosure[SIDE_BACK] == e) {
- /* Back side of the original triangle is member of the enclosure */
+ /* Back side of the original segment is member of the enclosure */
int input_normal_in = normals_back;
int revert_segment = (input_normal_in != output_normal_in);
++enc->header.segment_count;
@@ -1208,7 +1235,7 @@ senc2d_scene_analyze
connex_components_initialized = 1;
/* Just a hint; to limit contention */
OK2(darray_ptr_component_descriptor_reserve(&connex_components,
- 2 * scn->nmeds));
+ 2 + 2 * scn->next_medium_idx));
darray_segment_comp_init(scn->dev->allocator, &segments_comp);
segments_comp_initialized = 1;
OK2(darray_segment_comp_resize(&segments_comp, scn->nusegs));
diff --git a/src/senc2d_scene_analyze_c.h b/src/senc2d_scene_analyze_c.h
@@ -42,7 +42,7 @@ init_segside(struct mem_allocator* alloc, struct segside* data)
{
int i;
ASSERT(data); (void)alloc;
- FOR_EACH(i, 0, 3) data->facing_side_id[i] = SIDE_NULL__;
+ FOR_EACH(i, 0, 2) data->facing_side_id[i] = SIDE_NULL__;
data->medium = MEDIUM_NULL__;
}
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
@@ -177,8 +175,9 @@ struct senc2d_scene {
unsigned ngeoms; /* Not used yet (just counted). */
seg_id_t nsegs, nusegs; /* Segment count, unique segment count */
vrtx_id_t nverts, nuverts; /* Vrtx count, unique vrtx count */
- medium_id_t nmeds;
+ medium_id_t next_medium_idx;
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_inconsistant_square.c b/src/test_senc2d_inconsistant_square.c
@@ -105,7 +105,7 @@ test(enum senc2d_convention convention)
expected_medium = (header.is_infinite ?
expected_external_medium : !expected_external_medium);
CHK(medium == expected_medium);
- /* Common media, for non input triangles */
+ /* Common media, for non input segments */
front_inside = (conv_front == conv_in);
expected_side = front_inside ? 0 : 1;
diff --git a/src/test_senc2d_scene.c b/src/test_senc2d_scene.c
@@ -29,7 +29,8 @@ main(int argc, char** argv)
struct senc2d_enclosure* enc = NULL;
struct senc2d_enclosure_header header;
struct context ctx;
- unsigned medfront[2], medback[2];
+ unsigned medfront[2], medback[2], ind[2];
+ double vrtx[2];
unsigned count, i, maxm;
enum senc2d_convention convention;
(void)argc, (void)argv;
@@ -55,6 +56,9 @@ main(int argc, char** argv)
SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_INSIDE, &scn)
== RES_OK);
+ CHK(senc2d_scene_reserve(NULL, 0, 0, 0) == RES_BAD_ARG);
+ CHK(senc2d_scene_reserve(scn, 0, 0, 0) == RES_OK);
+
CHK(senc2d_scene_get_convention(NULL, &convention) == RES_BAD_ARG);
CHK(senc2d_scene_get_convention(scn, NULL) == RES_BAD_ARG);
CHK(senc2d_scene_get_convention(NULL, NULL) == RES_BAD_ARG);
@@ -86,6 +90,16 @@ main(int argc, char** argv)
CHK(senc2d_scene_get_unique_vertices_count(scn, &count) == RES_OK);
CHK(count == 0);
+ CHK(senc2d_scene_get_unique_sides_without_medium_count(NULL, &count)
+ == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_sides_without_medium_count(scn, NULL)
+ == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_sides_without_medium_count(NULL, NULL)
+ == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_sides_without_medium_count(scn, &count)
+ == RES_OK);
+ CHK(count == 0);
+
/* A 2D square
* With this geometry front is inside with NORMAL_BACK convention,
* outside with NORMAL_FRONT convention */
@@ -105,8 +119,6 @@ main(int argc, char** argv)
nvertices, get_position, &ctx) == RES_BAD_ARG);
CHK(senc2d_scene_add_geometry(scn, nsegments, NULL, get_media,
get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, NULL,
- get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG);
CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
get_global_id, 0, get_position, &ctx) == RES_BAD_ARG);
CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
@@ -123,6 +135,33 @@ main(int argc, char** argv)
CHK(senc2d_scene_get_unique_vertices_count(scn, &count) == RES_OK);
CHK(count == nvertices);
+ CHK(senc2d_scene_get_unique_segment(NULL, 0, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(scn, UINT_MAX, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(scn, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(NULL, UINT_MAX, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(scn, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment(scn, 0, ind) == RES_OK);
+
+ CHK(senc2d_scene_get_unique_segment_media(NULL, 0, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(scn, UINT_MAX, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(scn, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(NULL, UINT_MAX, ind) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(scn, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_segment_media(scn, 0, ind) == RES_OK);
+
+ CHK(senc2d_scene_get_unique_vertex(NULL, 0, vrtx) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(scn, UINT_MAX, vrtx) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(scn, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(NULL, UINT_MAX, vrtx) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(scn, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
+ CHK(senc2d_scene_get_unique_vertex(scn, 0, vrtx) == RES_OK);
+
CHK(senc2d_scene_analyze(NULL, NULL) == RES_BAD_ARG);
CHK(senc2d_scene_analyze(scn, NULL) == RES_BAD_ARG);
CHK(senc2d_scene_analyze(NULL, &desc) == RES_BAD_ARG);
diff --git a/src/test_senc2d_undefined_medium.c b/src/test_senc2d_undefined_medium.c
@@ -0,0 +1,280 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "senc2d.h"
+#include "senc2d_s2d_wrapper.h"
+#include "test_senc2d_utils.h"
+
+#include <rsys/double2.h>
+
+static void
+test(enum senc2d_convention convention)
+{
+ struct mem_allocator allocator;
+ struct senc2d_descriptor* desc = NULL;
+ struct senc2d_device* dev = NULL;
+ struct senc2d_scene* scn = NULL;
+ struct senc2d_enclosure* enclosure;
+ struct senc2d_enclosure_header header;
+ unsigned medium, expected_external_medium, expected_internal_medium;
+ unsigned gid;
+ struct context ctx;
+ unsigned i, s, ecount, vcount, scount;
+ int is_front, is_in;
+ unsigned media[4];
+ unsigned rev_box_indices[sizeof(box_indices) / sizeof(*box_indices)];
+ int conv_front, conv_in;
+
+ conv_front = (convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0;
+ conv_in = (convention & SENC2D_CONVENTION_NORMAL_INSIDE) != 0;
+
+ /* Create the box with reversed segments */
+ FOR_EACH(i, 0, sizeof(rev_box_indices) / sizeof(*rev_box_indices)) {
+ switch (i % 2) {
+ case 0: rev_box_indices[i] = box_indices[i + 1]; break;
+ case 1: rev_box_indices[i] = box_indices[i - 1]; break;
+ }
+ }
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc2d_device_create(NULL, &allocator, SENC2D_NTHREADS_DEFAULT, 1, &dev));
+
+ OK(senc2d_scene_create(dev, convention, &scn));
+ is_front = (convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0;
+ is_in = (convention & SENC2D_CONVENTION_NORMAL_INSIDE) != 0;
+
+ /* A 2D square.
+ * 2 enclosures (inside, outside) sharing the same segments,
+ * but opposite sides */
+ ctx.positions = box_vertices;
+ ctx.indices = box_indices;
+ ctx.scale = 1;
+ ctx.reverse_vrtx = 0;
+ ctx.reverse_med = 0;
+ d2(ctx.offset, 0, 0);
+ ctx.front_media = media;
+ ctx.back_media = medium1;
+
+ /* Can add the same segments again defined/undefined media in any order */
+
+ /* Add geometry with no media information on both sides */
+ for(i = 0; i < sizeof(media) / sizeof(*media); i++)
+ media[i] = SENC2D_UNDEFINED_MEDIUM;
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, NULL,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == 2 * nsegments);
+
+ /* Add geometry with no media information on the front sides */
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == nsegments);
+
+ /* Analyze with undefined media on the front sides */
+ OK(senc2d_scene_analyze(scn, &desc));
+ OK(senc2d_descriptor_get_enclosure_count(desc, &ecount));
+ CHK(ecount == 2);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc2d_enclosure* ee;
+ struct senc2d_enclosure_header hh;
+ unsigned cc;
+ OK(senc2d_descriptor_get_enclosure(desc, i, &enclosure));
+ OK(senc2d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+
+ OK(senc2d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input segments:
+ * if convention is front, front medium (undef) is outside,
+ * that is medium 0's enclosure is infinite */
+ expected_external_medium = conv_front ? SENC2D_UNDEFINED_MEDIUM : 1;
+ expected_internal_medium = conv_front ? 1 : SENC2D_UNDEFINED_MEDIUM;
+
+ CHK(medium == (header.is_infinite
+ ? expected_external_medium : expected_internal_medium));
+ CHK(header.segment_count == nsegments);
+ CHK(header.unique_segment_count == nsegments);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ OK(senc2d_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
+ CHK(cc == 1);
+ OK(senc2d_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
+ OK(senc2d_enclosure_get_header(ee, &hh));
+ CHK(header.enclosure_id == hh.enclosure_id);
+ OK(senc2d_enclosure_ref_put(ee));
+
+ FOR_EACH(s, 0, header.segment_count) {
+ unsigned ind[2];
+ OK(senc2d_enclosure_get_segment_global_id(enclosure, s, &gid));
+ CHK(gid == s);
+ OK(senc2d_enclosure_get_segment(enclosure, s, ind));
+ }
+ OK(senc2d_enclosure_ref_put(enclosure));
+ }
+ OK(senc2d_descriptor_ref_put(desc));
+
+
+ /* Same geometry, front media are defined for odd segments */
+ for(i = 0; i < sizeof(media) / sizeof(*media); i++)
+ media[i] = (i % 2) ? 0 : SENC2D_UNDEFINED_MEDIUM;
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == nsegments / 2);
+
+ /* Analyze with undefined media */
+ OK(senc2d_scene_analyze(scn, &desc));
+ OK(senc2d_descriptor_ref_put(desc));
+
+ /* Get the deduplicated geometry without (successful) analyze */
+ OK(senc2d_scene_get_unique_vertices_count(scn, &vcount));
+ CHK(vcount == nvertices);
+ OK(senc2d_scene_get_unique_segments_count(scn, &scount));
+ CHK(vcount == nsegments);
+ FOR_EACH(i, 0, vcount) {
+ int j;
+ unsigned med[2], ids[2];
+ OK(senc2d_scene_get_unique_segment(scn, i, ids));
+ OK(senc2d_scene_get_unique_segment_media(scn, i, med));
+ CHK(med[0] == ((i % 2) ? 0 : SENC2D_UNDEFINED_MEDIUM) && med[1] == 1);
+ FOR_EACH(j, 0, 2) {
+ double pos[2];
+ CHK(ids[j] < vcount);
+ OK(senc2d_scene_get_unique_vertex(scn, ids[j], pos));
+ }
+ }
+
+ /* Same information again, using a reversed box */
+ ctx.indices = rev_box_indices;
+ SWAP(const unsigned*, ctx.front_media, ctx.back_media);
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == nsegments / 2);
+
+ /* Analyze with undefined media */
+ OK(senc2d_scene_analyze(scn, &desc));
+ OK(senc2d_descriptor_ref_put(desc));
+
+ /* Define media for remaining segments, using reversed box */
+ for(i = 0; i < sizeof(media) / sizeof(*media); i++)
+ media[i] = (i % 2) ? SENC2D_UNDEFINED_MEDIUM : 0;
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == 0);
+
+ /* Get the deduplicated geometry without (successful) analyze */
+ OK(senc2d_scene_get_unique_vertices_count(scn, &vcount));
+ CHK(vcount == nvertices);
+ OK(senc2d_scene_get_unique_segments_count(scn, &scount));
+ CHK(scount == nsegments);
+ FOR_EACH(i, 0, scount) {
+ int j;
+ unsigned med[2], ids[2];
+ OK(senc2d_scene_get_unique_segment(scn, i, ids));
+ OK(senc2d_scene_get_unique_segment_media(scn, i, med));
+ CHK(med[0] == 0 && med[1] == 1);
+ FOR_EACH(j, 0, 2) {
+ double pos[2];
+ CHK(ids[j] < vcount);
+ OK(senc2d_scene_get_unique_vertex(scn, ids[j], pos));
+ }
+ }
+
+ /* Analyze with all media defined */
+ OK(senc2d_scene_analyze(scn, &desc));
+ OK(senc2d_descriptor_ref_put(desc));
+
+ /* Define media for all segments, nothing new here */
+ for(i = 0; i < sizeof(media) / sizeof(*media); i++)
+ media[i] = 0;
+ OK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == 0);
+
+ /* Define incoherent media for some segments */
+ for(i = 0; i < sizeof(media) / sizeof(*media); i++)
+ media[i] = (i % 2);
+ BA(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx));
+ OK(senc2d_scene_get_unique_sides_without_medium_count(scn, &scount));
+ CHK(scount == 0);
+
+ /* Scene is still OK and can be analyzed */
+ OK(senc2d_scene_analyze(scn, &desc));
+
+ OK(senc2d_descriptor_get_global_segments_count(desc, &scount));
+ CHK(scount == sizeof(media) / sizeof(*media));
+
+ OK(senc2d_descriptor_get_enclosure_count(desc, &ecount));
+ CHK(ecount == 2);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc2d_enclosure* ee;
+ struct senc2d_enclosure_header hh;
+ unsigned cc;
+ OK(senc2d_descriptor_get_enclosure(desc, i, &enclosure));
+ OK(senc2d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+ OK(senc2d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input segments:
+ * if convention is front, front medium (0) is outside,
+ * that is medium 0's enclosure is infinite */
+ CHK(is_front == ((medium == 0) == header.is_infinite));
+ CHK(header.segment_count == nsegments);
+ CHK(header.unique_segment_count == nsegments);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ OK(senc2d_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
+ CHK(cc == 1);
+ OK(senc2d_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
+ OK(senc2d_enclosure_get_header(ee, &hh));
+ CHK(header.enclosure_id == hh.enclosure_id);
+ OK(senc2d_enclosure_ref_put(ee));
+
+ FOR_EACH(s, 0, header.segment_count) {
+ OK(senc2d_enclosure_get_segment_global_id(enclosure, s, &gid));
+ CHK(gid == s);
+ }
+ OK(senc2d_enclosure_ref_put(enclosure));
+ }
+
+ SENC2D(scene_ref_put(scn));
+ SENC2D(device_ref_put(dev));
+ SENC2D(descriptor_ref_put(desc));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+}
+
+int
+main(int argc, char** argv)
+{
+ (void)argc, (void)argv;
+ test(SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_INSIDE);
+ test(SENC2D_CONVENTION_NORMAL_BACK | SENC2D_CONVENTION_NORMAL_INSIDE);
+ test(SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC2D_CONVENTION_NORMAL_BACK | SENC2D_CONVENTION_NORMAL_OUTSIDE);
+ return 0;
+}
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];
}
@@ -189,7 +192,7 @@ static INLINE void
check_memory_allocator(struct mem_allocator* allocator)
{
if(MEM_ALLOCATED_SIZE(allocator)) {
- char dump[128];
+ char dump[1024];
MEM_DUMP(allocator, dump, sizeof(dump));
fprintf(stderr, "%s\n", dump);
FATAL("Memory leaks.\n");
@@ -275,7 +278,7 @@ static INLINE void check_desc(struct senc2d_descriptor* desc)
ASSERT(e_cpt >= ecount); /* Every enc has been visited at least once */
}
-/* Compare the itri-th segment of enclosure with a segment described by seg2 & vertices2 */
+/* Compare the iseg-th segment of enclosure with a segment described by seg2 & vertices2 */
static INLINE void
cmp_seg
(const unsigned iseg,