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 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:
Mcmake/CMakeLists.txt | 1+
Msrc/senc2d.h | 52++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/senc2d_descriptor.c | 29+++++++++++++++++++----------
Msrc/senc2d_enclosure_data.h | 13+++++++------
Msrc/senc2d_scene.c | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/senc2d_scene_analyze.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/senc2d_scene_analyze_c.h | 2+-
Msrc/senc2d_scene_c.h | 9++++-----
Msrc/test_senc2d_inconsistant_square.c | 2+-
Msrc/test_senc2d_scene.c | 45++++++++++++++++++++++++++++++++++++++++++---
Asrc/test_senc2d_undefined_medium.c | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_senc2d_utils.h | 23+++++++++++++----------
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(&current_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,