commit d3dc3115564e6e67950a2f94ed75bec59ab55755
parent d63d9621865eed644204a84a3b56d5a8397d1241
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 20 Jul 2018 12:05:15 +0200
An enclosure can now be made of more than 1 medium.
Diffstat:
18 files changed, 881 insertions(+), 437 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -46,8 +46,8 @@ endif()
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 1)
-set(VERSION_PATCH 1)
+set(VERSION_MINOR 2)
+set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SENC2D_FILES_SRC
diff --git a/src/senc2d.h b/src/senc2d.h
@@ -66,8 +66,8 @@ struct senc2d_enclosure_header {
unsigned unique_segment_count;
/* Number of vertices */
unsigned vertices_count;
- /* The medium inside the enclosure */
- unsigned enclosed_medium;
+ /* The number of media inside the enclosure */
+ unsigned enclosed_media_count;
/* Is the enclosure infinite?
* Only the outermost enclosure is infinite. */
char is_infinite;
@@ -163,7 +163,7 @@ senc2d_scene_ref_put
SENC2D_API res_T
senc2d_descriptor_get_max_medium
(const struct senc2d_descriptor* descriptor,
- unsigned* rank);
+ unsigned* max_medium_id);
SENC2D_API res_T
senc2d_descriptor_get_enclosure_count
@@ -173,7 +173,7 @@ senc2d_descriptor_get_enclosure_count
SENC2D_API res_T
senc2d_descriptor_get_enclosure_count_by_medium
(const struct senc2d_descriptor* descriptor,
- const unsigned imed,
+ const unsigned imed, /* Must be in [0 max_medium_id] */
unsigned* count);
SENC2D_API res_T
@@ -278,6 +278,12 @@ senc2d_enclosure_get_segment_global_id
unsigned* gid);
SENC2D_API res_T
+senc2d_enclosure_get_medium
+ (const struct senc2d_enclosure* enclosure,
+ const unsigned imed,
+ unsigned* medium);
+
+SENC2D_API res_T
senc2d_enclosure_ref_get
(struct senc2d_enclosure* enclosure);
diff --git a/src/senc2d_descriptor.c b/src/senc2d_descriptor.c
@@ -86,11 +86,11 @@ struct mem_allocator*
******************************************************************************/
res_T
senc2d_descriptor_get_max_medium
- (const struct senc2d_descriptor* desc, unsigned* rank)
+ (const struct senc2d_descriptor* desc, unsigned* max_medium_id)
{
- if(!desc || !rank) return RES_BAD_ARG;
+ if(!desc || !max_medium_id) return RES_BAD_ARG;
ASSERT(desc->scene->nmeds < UINT_MAX); /* API type */
- *rank = (unsigned)desc->scene->nmeds;
+ *max_medium_id = (unsigned)desc->scene->nmeds - 1;
return RES_OK;
}
@@ -136,8 +136,7 @@ senc2d_descriptor_get_enclosure
struct senc2d_enclosure* enc;
if(!desc || idx >= darray_enclosure_size_get(&desc->enclosures) || !out_enc)
return RES_BAD_ARG;
- enc =
- enclosure_create(desc, darray_enclosure_data_get(&desc->enclosures) + idx);
+ enc = enclosure_create(desc, idx);
if(!enc) return RES_MEM_ERR;
*out_enc = enc;
return RES_OK;
diff --git a/src/senc2d_descriptor_c.h b/src/senc2d_descriptor_c.h
@@ -26,26 +26,26 @@
struct senc2d_scene;
struct mem_allocator;
-struct segment_comp {
- /* The connex component in which each side is. */
- component_id_t component[2];
+struct segment_part {
+ /* The connex component part in which each side is. */
+ part_id_t part[2];
};
static void
-segment_comp_init(struct mem_allocator* alloc, struct segment_comp* seg) {
+segment_part_init(struct mem_allocator* alloc, struct segment_part* seg) {
int i;
(void)alloc;
ASSERT(seg);
- FOR_EACH(i, 0, 2) seg->component[i] = COMPONENT_NULL__;
+ FOR_EACH(i, 0, 2) seg->part[i] = PART_NULL__;
}
-#define DARRAY_NAME segment_comp
-#define DARRAY_DATA struct segment_comp
-#define DARRAY_FUNCTOR_INIT segment_comp_init
+#define DARRAY_NAME segment_part
+#define DARRAY_DATA struct segment_part
+#define DARRAY_FUNCTOR_INIT segment_part_init
#include <rsys/dynamic_array.h>
struct segment_enc {
- /* The connex component in which each side is. */
+ /* The enclosure in which each side is. */
enclosure_id_t enclosure[2];
};
diff --git a/src/senc2d_enclosure.c b/src/senc2d_enclosure.c
@@ -45,13 +45,15 @@ enclosure_release(ref_T * ref)
struct senc2d_enclosure*
enclosure_create
(struct senc2d_descriptor* desc,
- const struct enclosure_data* data)
+ const unsigned idx)
{
struct senc2d_enclosure* enc;
- ASSERT(desc);
+ ASSERT(desc && idx < darray_enclosure_size_get(&desc->enclosures));
enc = MEM_CALLOC(descriptor_get_allocator(desc),
1, sizeof(struct senc2d_enclosure));
if(enc) {
+ const struct enclosure_data* data
+ = darray_enclosure_data_get(&desc->enclosures) + idx;
SENC2D(descriptor_ref_get(desc));
enc->desc = desc;
enc->data = data;
@@ -156,6 +158,21 @@ senc2d_enclosure_get_segment_global_id
}
res_T
+senc2d_enclosure_get_medium
+ (const struct senc2d_enclosure* enclosure,
+ const unsigned imed,
+ unsigned* medium)
+{
+ if(!enclosure || !medium
+ || imed >= enclosure->data->header.enclosed_media_count)
+ return RES_BAD_ARG;
+ ASSERT(enclosure->data->header.enclosed_media_count
+ == darray_media_size_get(&enclosure->data->enclosed_media));
+ *medium = darray_media_cdata_get(&enclosure->data->enclosed_media)[imed];
+ return RES_OK;
+}
+
+res_T
senc2d_enclosure_ref_get(struct senc2d_enclosure* enc)
{
if(!enc) return RES_BAD_ARG;
diff --git a/src/senc2d_enclosure_c.h b/src/senc2d_enclosure_c.h
@@ -32,6 +32,6 @@ struct senc2d_enclosure {
struct senc2d_enclosure*
enclosure_create
(struct senc2d_descriptor* desc,
- const struct enclosure_data* data);
+ const unsigned idx);
#endif /* SENC2D_ENCLOSURE_C_H */
diff --git a/src/senc2d_enclosure_data.h b/src/senc2d_enclosure_data.h
@@ -18,6 +18,8 @@
#include <rsys/rsys.h>
#include <rsys/ref_count.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
#include "senc2d.h"
#include "senc2d_scene_c.h"
@@ -33,16 +35,78 @@ init_header(struct senc2d_enclosure_header* header)
header->segment_count = 0;
header->unique_segment_count = 0;
header->vertices_count = 0;
- header->enclosed_medium = MEDIUM_NULL__;
+ header->enclosed_media_count = 0;
header->is_infinite = CHAR_MAX;
}
+#define HTABLE_NAME media
+#define HTABLE_KEY medium_id_t
+#define HTABLE_DATA char
+#include <rsys/hash_table.h>
+
+static FINLINE res_T
+htable_media_merge
+(struct htable_media* dst,
+ struct htable_media* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ struct htable_media_iterator it, end;
+ char one = 1;
+
+ htable_media_begin(src, &it);
+ htable_media_end(src, &end);
+ while(!htable_media_iterator_eq(&it, &end)) {
+ medium_id_t* k = htable_media_iterator_key_get(&it);
+ res = htable_media_set(dst, k, &one);
+ if(res != RES_OK) goto error;
+ htable_media_iterator_next(&it);
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+#define DARRAY_NAME media
+#define DARRAY_DATA medium_id_t
+#include <rsys/dynamic_array.h>
+
+static FINLINE res_T
+htable_media_to_darray_media
+ (struct darray_media* dst,
+ struct htable_media* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ struct htable_media_iterator it, end;
+
+ darray_media_clear(dst);
+ res = darray_media_reserve(dst, htable_media_size_get(src));
+ if(res != RES_OK) goto error;
+ htable_media_begin(src, &it);
+ htable_media_end(src, &end);
+ while(!htable_media_iterator_eq(&it, &end)) {
+ medium_id_t* k = htable_media_iterator_key_get(&it);
+ res = darray_media_push_back(dst, k);
+ if(res != RES_OK) goto error;
+ htable_media_iterator_next(&it);
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
struct enclosure_data {
struct senc2d_enclosure_header header;
/* Same segment can appear twice if both sides */
struct darray_segment_in sides;
/* Index of vertices in scene's unique vertices */
struct darray_vrtx_id vertices;
+ /* List of the enclosed media */
+ struct htable_media tmp_enclosed_media;
+ struct darray_media enclosed_media;
/* Number of components involved in this enclosure */
component_id_t cc_count;
/* Linked list of the components */
@@ -64,6 +128,8 @@ enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) {
enc->side_count = 0;
darray_segment_in_init(alloc, &enc->sides);
darray_vrtx_id_init(alloc, &enc->vertices);
+ htable_media_init(alloc, &enc->tmp_enclosed_media);
+ darray_media_init(alloc, &enc->enclosed_media);
}
static FINLINE res_T
@@ -80,6 +146,8 @@ enclosure_data_copy
dst->side_count = src->side_count;
OK(darray_segment_in_copy(&dst->sides, &src->sides));
OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices));
+ OK(htable_media_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media));
+ OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media));
error:
return res;
}
@@ -89,6 +157,8 @@ enclosure_data_release(struct enclosure_data* n) {
ASSERT(n);
darray_segment_in_release(&n->sides);
darray_vrtx_id_release(&n->vertices);
+ htable_media_release(&n->tmp_enclosed_media);
+ darray_media_release(&n->enclosed_media);
}
static FINLINE res_T
@@ -105,6 +175,9 @@ enclosure_data_copy_and_release
dst->side_count = src->side_count;
OK(darray_segment_in_copy_and_release(&dst->sides, &src->sides));
OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices));
+ OK(htable_media_copy_and_release(&dst->tmp_enclosed_media,
+ &src->tmp_enclosed_media));
+ OK(darray_media_copy_and_release(&dst->enclosed_media, &src->enclosed_media));
error:
return res;
}
diff --git a/src/senc2d_internal_types.h b/src/senc2d_internal_types.h
@@ -81,8 +81,20 @@ typedef uint32_t enclosure_id_t;
/* Component IDs use the same type than enclosure IDs */
typedef enclosure_id_t component_id_t;
-#define COMPONENT_MAX__ ENCLOSURE_MAX__
-#define COMPONENT_NULL__ ENCLOSURE_NULL__
+#define COMPONENT_MAX__ (UINT32_MAX - 2) /* To allow special values */
+#define COMPONENT_NULL__ UINT32_MAX
+/* Special part values */
+#define CC_GROUP_ROOT_NONE UINT32_MAX
+#define CC_GROUP_ROOT_INFINITE (UINT32_MAX - 1)
+#define CC_GROUP_ID_NONE UINT32_MAX
+#define CC_ID_NONE UINT32_MAX
+
+/* Part IDs use the same type than Component IDs */
+typedef component_id_t part_id_t;
+#define PART_MAX__ (UINT32_MAX - 2) /* To allow special values */
+#define PART_NULL__ UINT32_MAX
+/* Special part values */
+#define PART_IN_STACK (UINT32_MAX - 1)
/* This one is used as an index to arrays */
enum side_id {
diff --git a/src/senc2d_scene.c b/src/senc2d_scene.c
@@ -178,7 +178,7 @@ senc2d_scene_add_geometry
if(tmp.vertice_id[0] == tmp.vertice_id[1]) {
const union double2* positions
= darray_position_cdata_get(&scn->vertices);
- log_err(scn->dev, "%s: segment %lu is degenerate.\n",
+ log_warn(scn->dev, "%s: segment %lu is degenerate.\n",
FUNC_NAME, (unsigned long)tmp.global_id);
log_err(scn->dev, " (%g %g) (%g %g)\n",
SPLIT2(positions[seg[i].vertice_id[0]].vec),
diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c
@@ -32,8 +32,14 @@
#include <limits.h>
#include <stdlib.h>
+#define PART_DESCRIPTOR_NULL__ {\
+ 0, PART_NULL__, VRTX_NULL__, 0, MEDIUM_NULL__,\
+ { SEG_NULL__, 0}\
+}
+const struct part_descriptor PART_DESCRIPTOR_NULL = PART_DESCRIPTOR_NULL__;
+
#define CC_DESCRIPTOR_NULL__ {\
- CHAR_MAX, VRTX_NULL__, 0, MEDIUM_NULL__,\
+ CHAR_MAX, VRTX_NULL__, 0,\
CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\
{ SEG_NULL__, 0}\
}
@@ -43,36 +49,10 @@ const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
#define DARRAY_DATA component_id_t
#include <rsys/dynamic_array.h>
-#define DARRAY_NAME side_id
-#define DARRAY_DATA side_id_t
-#include <rsys/dynamic_array.h>
-
/*******************************************************************************
* Helper function
******************************************************************************/
static INLINE int
-find_side_in_list
- (const struct segside* segsides,
- const struct darray_side_id* side_ids,
- const side_id_t side_id,
- const enum list_id list_id)
-{
- side_id_t i;
- size_t tmp;
- (void)list_id;
- (void)segsides;
- ASSERT(segsides && side_ids);
- tmp = darray_side_id_size_get(side_ids);
- ASSERT(tmp <= SIDE_MAX__);
- FOR_EACH(i, 0, (side_id_t)tmp) {
- const side_id_t id = darray_side_id_cdata_get(side_ids)[i];
- ASSERT(segsides[id].list_id & list_id);
- if(id == side_id) return 1;
- }
- return 0;
-}
-
-static INLINE int
neighbour_cmp(const void* w1, const void* w2)
{
const double a1 = ((struct neighbour_info*)w1)->angle;
@@ -84,54 +64,56 @@ static FINLINE res_T
add_side_to_stack
(const struct senc2d_scene* scn,
struct darray_side_id* stack,
- struct segside* segsides,
+ struct segment_part* segments_part,
const side_id_t side_id)
{
(void)scn;
- ASSERT(scn && segsides && stack
+ seg_id_t seg = SEGSIDE_2_SEG(side_id);
+ enum side_flag sf = SEGSIDE_2_SIDE(side_id);
+ ASSERT(scn && segments_part && stack
&& side_id < SIDE_MAX__ && side_id < 2 * scn->nusegs);
- ASSERT((darray_side_id_size_get(stack) > 128)
- || !find_side_in_list(segsides, stack, side_id, FLAG_WAITING_STACK));
- segsides[side_id].list_id = FLAG_WAITING_STACK;
+ ASSERT(segments_part[seg].part[sf] == PART_NULL__);
+ segments_part[seg].part[sf] = PART_IN_STACK;
return darray_side_id_push_back(stack, &side_id);
}
static side_id_t
-get_side_not_in_connex_component
- (const struct senc2d_scene* scn,
+get_side_not_in_connex_part
+ (const seg_id_t last_side,
const struct segside* segsides,
- side_id_t* first_side_not_in_component,
+ const struct segment_part* segments_part,
+ side_id_t* first_side_not_in_part,
const medium_id_t medium)
{
- side_id_t i;
- const seg_id_t last_side
- = darray_side_range_cdata_get(&scn->media_use)[medium].last;
- ASSERT(scn && segsides && first_side_not_in_component);
- i = *first_side_not_in_component;
- while(i <= last_side
- && (segsides[i].medium != medium
- || segsides[i].list_id != FLAG_LIST_SIDE_LIST)) {
- ++i;
+ ASSERT(segsides && segments_part && first_side_not_in_part);
+ {
+ side_id_t i = *first_side_not_in_part;
+ while(i <= last_side
+ && (segsides[i].medium != medium
+ || (segments_part[SEGSIDE_2_SEG(i)].part[SEGSIDE_2_SIDE(i)]
+ <= PART_MAX__))) {
+ ++i;
+ }
+ *first_side_not_in_part = i + 1;
+ if(i > last_side) return SIDE_NULL__;
+ return i;
}
-
- *first_side_not_in_component = i+1;
- if(i > last_side) return SIDE_NULL__;
- return i;
}
static FINLINE side_id_t
get_side_from_stack
- (const struct segside* segsides,
+ (const struct segment_part* segments_part,
struct darray_side_id* stack)
{
side_id_t id;
size_t sz;
- (void)segsides;
- ASSERT(segsides && stack);
+ (void) segments_part;
+ ASSERT(segments_part && stack);
sz = darray_side_id_size_get(stack);
ASSERT(sz);
id = darray_side_id_cdata_get(stack)[sz - 1];
- ASSERT(segsides[id].list_id == FLAG_WAITING_STACK);
+ ASSERT(segments_part[SEGSIDE_2_SEG(id)].part[SEGSIDE_2_SIDE(id)]
+ == PART_IN_STACK);
darray_side_id_pop_back(stack);
return id;
}
@@ -156,6 +138,22 @@ get_scn_position(const unsigned ivert, float pos[2], void* ctx) {
f2_set_d2(pos, pt->vec);
}
+static component_id_t FINLINE
+part2comp
+ (const struct darray_component_id* part2comp_table,
+ const part_id_t part)
+{
+ if(!part2comp_table) return part;
+ ASSERT(part < darray_component_id_size_get(part2comp_table));
+ return darray_component_id_cdata_get(part2comp_table)[part];
+}
+
+struct filter_context {
+ const struct darray_segment_part* segments_part;
+ const struct darray_component_id* part2comp_table;
+ component_id_t* self_hit_component;
+};
+
static int
self_hit_filter
(const struct s2d_hit* hit,
@@ -164,19 +162,26 @@ self_hit_filter
void* ray_data,
void* filter_data)
{
- const struct darray_segment_comp* segments_comp = filter_data;
- const component_id_t* origin_component = ray_data;
- const struct segment_comp* hit_seg_comp;
+ struct filter_context* context = ray_data;
+ const struct darray_segment_part* segments_part;
+ const struct darray_component_id* part2comp_table;
+ const component_id_t* origin_component;
+ const struct segment_part* hit_seg_part;
enum side_id hit_side;
+ part_id_t hit_part;
component_id_t hit_component;
- (void)ray_org; (void)ray_dir;
- ASSERT(hit && segments_comp && origin_component);
- ASSERT(hit->prim.prim_id < darray_segment_comp_size_get(segments_comp));
- hit_seg_comp = darray_segment_comp_cdata_get(segments_comp)
+ (void)ray_org; (void)ray_dir; (void)filter_data;
+ ASSERT(hit && context && context);
+ segments_part = context->segments_part;
+ part2comp_table = context->part2comp_table;
+ origin_component = context->self_hit_component;
+ ASSERT(hit->prim.prim_id < darray_segment_part_size_get(segments_part));
+ hit_seg_part = darray_segment_part_cdata_get(segments_part)
+ hit->prim.prim_id;
hit_side = (hit->normal[1] > 0) ? SIDE_FRONT : SIDE_BACK;
- hit_component = hit_seg_comp->component[hit_side];
+ hit_part = hit_seg_part->part[hit_side];
+ hit_component = part2comp(part2comp_table, hit_part);
/* If self hit, distance should be small */
ASSERT(hit_component != *origin_component || hit->distance < 1e-6);
@@ -184,14 +189,14 @@ self_hit_filter
}
static void
-extract_connex_components
+extract_connex_parts
(struct senc2d_descriptor* desc,
struct segside* segsides,
- struct darray_ptr_component_descriptor* connex_components,
+ struct darray_ptr_part_descriptor* connex_parts,
const struct darray_segment_tmp* segments_tmp_array,
- struct darray_segment_comp* segments_comp,
+ struct darray_segment_part* segments_part_array,
struct s2d_scene_view** s2d_view,
- ATOMIC* component_count,
+ ATOMIC* part_count,
/* Shared error status.
* We accept to overwritte an error with a different error */
res_T* res)
@@ -204,24 +209,25 @@ extract_connex_components
struct darray_side_id stack;
struct darray_side_id ids_of_sides_around_max_y_vertex;
const union double2* positions;
- size_t sz, ii;
-#ifndef NDEBUG
- seg_id_t s_;
- component_id_t c;
-#endif
+ const struct segment_tmp* segments_tmp;
+ struct segment_part* segments_part;
+ size_t sz;
- ASSERT(segsides && desc && connex_components && segments_tmp_array
- && s2d_view && component_count && res);
+ ASSERT(segsides && desc && connex_parts && segments_tmp_array
+ && segments_part_array && s2d_view && part_count && res);
alloc = descriptor_get_allocator(desc);
scn = desc->scene;
positions = darray_position_cdata_get(&scn->vertices);
+ segments_tmp = darray_segment_tmp_cdata_get(segments_tmp_array);
+ segments_part = darray_segment_part_data_get(segments_part_array);
darray_side_id_init(alloc, &stack);
darray_side_id_init(alloc, &ids_of_sides_around_max_y_vertex);
#ifndef NDEBUG
#pragma omp single
{
- ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0);
+ seg_id_t s_;
+ ASSERT(darray_ptr_part_descriptor_size_get(connex_parts) == 0);
FOR_EACH(s_, 0, scn->nusegs) {
const struct segment_in* seg_in =
darray_segment_in_cdata_get(&scn->segments_in) + s_;
@@ -237,24 +243,26 @@ extract_connex_components
} /* Implicit barrier here */
#endif
+ /* We loop on sides to build parts of 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;
- struct cc_descriptor* cc;
+ struct part_descriptor* part;
/* Any not-already-used side is used as a starting point */
- side_id_t first_side_not_in_component;
- double max_y_ny;
+ const struct side_range* media_use =
+ darray_side_range_cdata_get(&scn->media_use) + m;
+ side_id_t first_side_not_in_part = media_use->first;
+ const seg_id_t last_side = media_use->last;
+ ATOMIC id;
if(*res != RES_OK) continue;
- first_side_not_in_component
- = darray_side_range_cdata_get(&scn->media_use)[m].first;
- if(first_side_not_in_component == SIDE_NULL__)
+ if(first_side_not_in_part == SIDE_NULL__)
continue; /* Unused medium */
- ASSERT(first_side_not_in_component < 2 * scn->nusegs);
+ ASSERT(first_side_not_in_part < 2 * scn->nusegs);
ASSERT(darray_side_id_size_get(&stack) == 0);
- for(;;) { /* Process all components for this medium */
- const side_id_t start_side_id = get_side_not_in_connex_component(scn,
- segsides, &first_side_not_in_component, m);
+ for(;;) { /* Process all parts for this medium */
+ const side_id_t start_side_id = get_side_not_in_connex_part
+ (last_side, segsides, segments_part, &first_side_not_in_part, m);
side_id_t crt_side_id = start_side_id;
side_id_t last_side_id = start_side_id;
double max_y = -DBL_MAX;
@@ -264,7 +272,6 @@ extract_connex_components
if(*res != RES_OK) break;
if(start_side_id == SIDE_NULL__)
break; /* start_side_id=SIDE_NULL__ => done! */
- ASSERT(segsides[start_side_id].list_id == FLAG_LIST_SIDE_LIST);
#ifndef NDEBUG
{
@@ -276,36 +283,36 @@ extract_connex_components
}
#endif
- /* Create and init a new component */
- cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor));
- if(!cc) {
+ /* Create and init a new part */
+ part = MEM_ALLOC(alloc, sizeof(struct part_descriptor));
+ if(!part) {
*res = RES_MEM_ERR;
continue;
}
- cc_descriptor_init(alloc, cc);
+ part_descriptor_init(alloc, part);
ASSERT(m == segsides[start_side_id].medium);
- cc->cc_id = (component_id_t)(ATOMIC_INCR(component_count) - 1);
- cc->medium = m;
- cc->side_range.first = start_side_id;
+ id = ATOMIC_INCR(part_count) - 1;
+ ASSERT(id <= PART_MAX__);
+ part->part_id = (part_id_t)id;
+ part->side_range.first = start_side_id;
+ part->medium = m;
- for(;;) { /* Process all sides of this component */
+ for(;;) { /* Process all sides of this part */
int i;
enum side_flag crt_side_flag = SEGSIDE_2_SIDE(crt_side_id);
struct segside* crt_side = segsides + crt_side_id;
const seg_id_t crt_seg_id = SEGSIDE_2_SEG(crt_side_id);
const struct segment_in* seg_in =
darray_segment_in_cdata_get(&scn->segments_in) + crt_seg_id;
- struct segment_comp* seg_comp =
- darray_segment_comp_data_get(segments_comp) + crt_seg_id;
- const struct segment_tmp* const seg_tmp =
- darray_segment_tmp_cdata_get(segments_tmp_array) + crt_seg_id;
+ struct segment_part* seg_part = segments_part + crt_seg_id;
+ const struct segment_tmp* const seg_tmp = segments_tmp + crt_seg_id;
ASSERT(crt_seg_id < scn->nusegs);
- ASSERT(segsides[crt_side_id].medium == m);
+ ASSERT(seg_in->medium[crt_side_flag] == part->medium);
if(*res != RES_OK) break;
/* Record Ymax information
- * Keep track of the appropriate vertex of the connex component in order
+ * Keep track of the appropriate vertex of the part in order
* to cast a ray at the component grouping step of the algorithm.
* The most appropriate vertex is (the) one with the greater Y
* coordinate. */
@@ -317,10 +324,10 @@ extract_connex_components
/* Select one vertex with y == max_y */
if(max_y == positions[seg_in->vertice_id[0]].pos.y) {
- cc->max_y_vrtx_id = seg_in->vertice_id[0];
+ part->max_y_vrtx_id = seg_in->vertice_id[0];
} else {
ASSERT(max_y == positions[seg_in->vertice_id[1]].pos.y);
- cc->max_y_vrtx_id = seg_in->vertice_id[1];
+ part->max_y_vrtx_id = seg_in->vertice_id[1];
}
/* List of sides using the vertex */
*res = darray_side_id_push_back(&ids_of_sides_around_max_y_vertex,
@@ -328,7 +335,7 @@ extract_connex_components
} else if(max_y == seg_tmp->max_y) {
/* Does this segment use the currently selected max_y vertex? */
FOR_EACH(i, 0, 2) {
- if(cc->max_y_vrtx_id == seg_in->vertice_id[i]) {
+ if(part->max_y_vrtx_id == seg_in->vertice_id[i]) {
/* List of sides using the vertex */
*res = darray_side_id_push_back(&ids_of_sides_around_max_y_vertex,
&crt_side_id);
@@ -338,130 +345,74 @@ extract_connex_components
}
if(*res != RES_OK) break;
- /* Record crt_side both as component and segment level */
- cc->side_count++;
- segsides[crt_side_id].list_id = FLAG_LIST_COMPONENT;
- ASSERT(seg_comp->component[crt_side_flag] == COMPONENT_NULL__);
- seg_comp->component[crt_side_flag] = cc->cc_id;
-#ifndef NDEBUG
- crt_side->member_of_cc = cc->cc_id;
-#endif
+ /* Record crt_side both as part and segment level */
+ part->side_count++;
+ ASSERT(seg_part->part[crt_side_flag] > PART_MAX__);
+ seg_part->part[crt_side_flag] = part->part_id;
- /* Store neighbour sides in a waiting stack */
+ /* Store neighbours' sides in a stack */
FOR_EACH(i, 0, 2) {
side_id_t neighbour_id = crt_side->facing_side_id[i];
seg_id_t nbour_seg_id = SEGSIDE_2_SEG(neighbour_id);
+ seg_id_t nbour_side_id = SEGSIDE_2_SIDE(neighbour_id);
+ struct segment_part* nbour_part = segments_part + nbour_seg_id;
const struct segside* neighbour = segsides + neighbour_id;
- ASSERT(m == crt_side->medium);
if(neighbour->medium != crt_side->medium) {
- /* Found medium discontinuity! Model topology is broken. */
- const struct segment_in* segments_in
- = darray_segment_in_cdata_get(&scn->segments_in);
- log_err(scn->dev,
- "Medium mismatch found between neighbour segments %lu %s"
- " side and %u %s side.\n",
- (unsigned long)segments_in[crt_seg_id].global_id,
- SEGSIDE_IS_FRONT(crt_side_id) ? "front" : "back",
- segments_in[nbour_seg_id].global_id,
- SEGSIDE_IS_FRONT(neighbour_id) ? "front" : "back");
- log_err(scn->dev,
- "Segment %lu:\n (%g %g) (%g %g))\n",
- (unsigned long)segments_in[crt_seg_id].global_id,
- SPLIT2(positions[segments_in[crt_seg_id].vertice_id[0]].vec),
- SPLIT2(positions[segments_in[crt_seg_id].vertice_id[1]].vec));
- log_err(scn->dev,
- "Segment %lu:\n (%g %g) (%g %g)\n",
- (unsigned long)segments_in[nbour_seg_id].global_id,
- SPLIT2(positions[segments_in[nbour_seg_id].vertice_id[0]].vec),
- SPLIT2(positions[segments_in[nbour_seg_id].vertice_id[1]].vec));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- (unsigned long)neighbour->medium, (unsigned long)crt_side->medium);
- *res = RES_BAD_ARG;
- break;
+ /* Not the same medium: will be included in another computation.
+ * If the id of the part including it is already known
+ * record it for a further merge. In the opposite, the other
+ * computation will reach the very same point at a point in time
+ * when it will have the information: it will then do the job. */
+ if(nbour_part->part[nbour_side_id] <= PART_MAX__) {
+ res_T tmp_res;
+ char one = 1;
+ tmp_res = htable_part_id_set(&part->parts_to_merge_with,
+ &nbour_part->part[nbour_side_id], &one);
+ if(tmp_res != RES_OK) *res = tmp_res;
+ if(*res != RES_OK) break;
+ }
+ continue;
}
- if(neighbour->list_id == FLAG_LIST_COMPONENT) {
- /* Already processed */
+ if(nbour_part->part[nbour_side_id] != PART_NULL__) {
#ifndef NDEBUG
- ASSERT(neighbour->member_of_cc == cc->cc_id);
+ /* If already affected must be to the same part */
+ ASSERT(nbour_part->part[nbour_side_id] == PART_IN_STACK
+ || nbour_part->part[nbour_side_id] == part->part_id);
#endif
- continue;
- }
- if(neighbour->list_id == FLAG_WAITING_STACK) {
continue; /* Already processed */
}
- *res = add_side_to_stack(scn, &stack, segsides, neighbour_id);
+ *res = add_side_to_stack(scn, &stack, segments_part, neighbour_id);
if(*res != RES_OK) break;
}
if(*res != RES_OK) break;
if(darray_side_id_size_get(&stack) == 0)
- break; /* Empty stack => connex component is done! */
- crt_side_id = get_side_from_stack(segsides, &stack);
+ break; /* Empty stack => part is done! */
+ crt_side_id = get_side_from_stack(segments_part, &stack);
last_side_id = MMAX(last_side_id, crt_side_id);
}
if(*res != RES_OK) {
- MEM_RM(alloc, cc);
- cc = NULL;
+ MEM_RM(alloc, part);
+ part = NULL;
break;
}
- /* Keep track of this new connex component */
- cc->side_range.last = last_side_id;
-
- /* Compute the normal at the max_y vertex. */
- max_y_ny = 0;
- sz = darray_side_id_size_get(&ids_of_sides_around_max_y_vertex);
- FOR_EACH(ii, 0, sz) {
- const side_id_t side_id =
- darray_side_id_cdata_get(&ids_of_sides_around_max_y_vertex)[ii];
- const seg_id_t seg_id = SEGSIDE_2_SEG(side_id);
- const struct segment_in* seg_in =
- darray_segment_in_cdata_get(&scn->segments_in) + seg_id;
- struct segment_comp* seg_comp =
- darray_segment_comp_data_get(segments_comp) + seg_id;
- const union double2* vertices =
- darray_position_cdata_get(&scn->vertices);
- double edge[2], normal[2], norm;
-
- /* To garanty that segments with 2 sides in the component total to 0
- * regardless of numeric accuracy, we need to prevent them to
- * contribute (remember than x + y - x - y can be non-zero). */
- ASSERT(seg_comp->component[SIDE_FRONT] == cc->cc_id
- || seg_comp->component[SIDE_BACK] == cc->cc_id);
- if(seg_comp->component[SIDE_FRONT] == seg_comp->component[SIDE_BACK])
- continue;
-
- d2_sub(edge, vertices[seg_in->vertice_id[1]].vec,
- vertices[seg_in->vertice_id[0]].vec);
- d2(normal, edge[1], -edge[0]);
- norm = d2_normalize(normal, normal);
- ASSERT(norm); (void)norm;
-
- /* Geometrical normal points toward the back side */
- if(SEGSIDE_IS_FRONT(side_id)) {
- max_y_ny -= normal[1];
- } else {
- max_y_ny += normal[1];
- }
- }
- if(*res != RES_OK) break;
- cc->is_outer_border = (max_y_ny < 0);
+ part->side_range.last = last_side_id;
- /* Need to synchronize connex_components growth as this global structure
+ /* Need to synchronize connex_parts growth as this global structure
* is accessed by multipe threads */
#pragma omp critical
{
- struct cc_descriptor** components;
- sz = darray_ptr_component_descriptor_size_get(connex_components);
- if(sz <= cc->cc_id) {
- res_T tmp_res = darray_ptr_component_descriptor_resize(connex_components,
- 1 + cc->cc_id);
+ struct part_descriptor** parts;
+ sz = darray_ptr_part_descriptor_size_get(connex_parts);
+ if(sz <= part->part_id) {
+ res_T tmp_res = darray_ptr_part_descriptor_resize(connex_parts,
+ 1 + part->part_id);
if(tmp_res != RES_OK) *res = tmp_res;
}
if(*res == RES_OK) {
/* Don't set the pointer before resize as this can lead to move data */
- components =
- darray_ptr_component_descriptor_data_get(connex_components);
- ASSERT(components[cc->cc_id] == NULL);
- components[cc->cc_id] = cc;
+ parts = darray_ptr_part_descriptor_data_get(connex_parts);
+ ASSERT(parts[part->part_id] == NULL);
+ parts[part->part_id] = part;
}
}
}
@@ -494,8 +445,7 @@ extract_connex_components
OK2(s2d_line_segments_setup_indexed_vertices(s2d_shp,
(unsigned)desc->scene->nusegs, get_scn_indices,
(unsigned)desc->scene->nuverts, &attribs, 1, desc->scene));
- s2d_line_segments_set_hit_filter_function(s2d_shp, self_hit_filter,
- segments_comp);
+ s2d_line_segments_set_hit_filter_function(s2d_shp, self_hit_filter, NULL);
OK2(s2d_scene_attach_shape(s2d_scn, s2d_shp));
OK2(s2d_scene_view_create(s2d_scn, S2D_TRACE, s2d_view));
tmp_error:
@@ -511,32 +461,248 @@ extract_connex_components
if(*res != RES_OK) return;
#pragma omp single
{
- ASSERT(ATOMIC_GET(component_count) ==
- (int)darray_ptr_component_descriptor_size_get(connex_components));
+ seg_id_t s_;
+ part_id_t p;
+ ASSERT(ATOMIC_GET(part_count) ==
+ (int)darray_ptr_part_descriptor_size_get(connex_parts));
FOR_EACH(s_, 0, scn->nusegs) {
- struct segment_comp* seg_comp =
- darray_segment_comp_data_get(segments_comp) + s_;
- ASSERT(seg_comp->component[SIDE_FRONT] != COMPONENT_NULL__);
- ASSERT(seg_comp->component[SIDE_BACK] != COMPONENT_NULL__);
+ struct segment_part* seg_part = segments_part + s_;
+ ASSERT(seg_part->part[SIDE_FRONT] != PART_NULL__);
+ ASSERT(seg_part->part[SIDE_BACK] != PART_NULL__);
}
- FOR_EACH(c, 0, ATOMIC_GET(component_count)) {
- struct cc_descriptor** components =
- darray_ptr_component_descriptor_data_get(connex_components);
- ASSERT(components[c] != NULL &&
- components[c]->cc_id == c);
+ FOR_EACH(p, 0, ATOMIC_GET(part_count)) {
+ struct part_descriptor** parts =
+ darray_ptr_part_descriptor_data_get(connex_parts);
+ ASSERT(parts[p] != NULL && parts[p]->part_id == p);
}
- ASSERT(desc->segment_count
- == darray_segment_comp_size_get(segments_comp));
+ ASSERT(desc->segment_count == scn->nusegs);
} /* Implicit barrier here */
#endif
}
static void
+merge_connex_parts
+ (struct senc2d_descriptor* desc,
+ const struct darray_segment_part* segments_part,
+ const struct darray_ptr_part_descriptor* connex_parts,
+ struct darray_ptr_component_descriptor* connex_components,
+ struct darray_component_id* part2comp_table,
+ ATOMIC* component_count,
+ /* Shared error status. */
+ res_T* res)
+{
+ /* This function must be called from an omp single block.
+ * Not suitable for use by multiple threads. */
+ struct part_descriptor* const* parts;
+ const union double2* vertices;
+ struct mem_allocator* alloc;
+ component_id_t* p2c;
+ char one = 1;
+ size_t tmp;
+ part_id_t part_count;
+ int64_t ppp;
+ ASSERT(desc && segments_part && connex_parts && connex_components
+ && part2comp_table && component_count && res);
+
+ alloc = descriptor_get_allocator(desc);
+ parts = darray_ptr_part_descriptor_cdata_get(connex_parts);
+ tmp = darray_ptr_part_descriptor_size_get(connex_parts);
+ vertices = darray_position_cdata_get(&desc->scene->vertices);
+ p2c = darray_component_id_data_get(part2comp_table);
+ ASSERT(tmp <= PART_MAX__);
+ part_count = (component_id_t)tmp;
+
+ /* Propagate merge information accross parts
+ * The goal is to have all part aware of any part with a higher id */
+ #pragma omp single
+ for (ppp = 0; ppp < (int64_t) part_count; ppp++) {
+ part_id_t pid = (part_id_t)ppp;
+ struct part_descriptor* part = parts[pid];
+ struct htable_part_id_iterator it, end;
+ res_T tmp_res = RES_OK;
+ if(*res != RES_OK) continue;
+ htable_part_id_begin(&part->parts_to_merge_with, &it);
+ htable_part_id_end(&part->parts_to_merge_with, &end);
+ while(!htable_part_id_iterator_eq(&it, &end)) {
+ part_id_t* did = htable_part_id_iterator_key_get(&it);
+ struct part_descriptor* d;
+ ASSERT(did && *did < part_count && *did != part->part_id);
+ htable_part_id_iterator_next(&it);
+ if(*did > part->part_id) {
+ parts[*did]->not_head_of_group = 1;
+ continue;
+ }
+ part->not_head_of_group = 1;
+
+ d = parts[*did];
+ tmp_res =
+ htable_part_id_set(&d->parts_to_merge_with, &part->part_id, &one);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
+ }
+ /* Add self */
+ tmp_res =
+ htable_part_id_set(&part->parts_to_merge_with, &part->part_id, &one);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ continue;
+ }
+ } /* Implicit barrier here */
+
+ /* Merge the parts to create components */
+ #pragma omp for
+ for(ppp = 0; ppp < (int64_t)part_count; ppp++) {
+ part_id_t pid = (part_id_t)ppp;
+ struct cc_descriptor* cc = NULL;
+ struct part_descriptor* part = parts[pid];
+ struct htable_part_id_iterator beg, it, end;
+ double max_y = -DBL_MAX;
+ vrtx_id_t max_y_vrtx_id = VRTX_NULL__;
+ double edge[2], normal[2], norm, max_y_ny = 0;
+ double comp_max_y;
+ ATOMIC id;
+ res_T tmp_res = RES_OK;
+
+ if(*res != RES_OK) continue;
+ if(part->not_head_of_group) continue;
+
+ /* Create the component to hold merged data */
+ cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor));
+ if(!cc) {
+ *res = RES_MEM_ERR;
+ continue;
+ }
+
+ cc_descriptor_init(alloc, cc);
+ id = ATOMIC_INCR(component_count) - 1;
+ ASSERT(id <= COMPONENT_MAX__);
+ cc->cc_id = (component_id_t)id;
+
+ /* Need to synchronize connex_components growth as this global structure
+ * is accessed by multipe threads */
+ #pragma omp critical
+ {
+ struct cc_descriptor** components;
+ size_t sz = darray_ptr_component_descriptor_size_get(connex_components);
+ if(sz <= cc->cc_id) {
+ res_T r = darray_ptr_component_descriptor_resize(connex_components,
+ 1 + cc->cc_id);
+ if(r != RES_OK) *res = r;
+ }
+ if(*res == RES_OK) {
+ /* Don't set the pointer before resize as this can lead to move data */
+ components = darray_ptr_component_descriptor_data_get(connex_components);
+ ASSERT(components[cc->cc_id] == NULL);
+ components[cc->cc_id] = cc;
+ }
+ }
+ if(*res != RES_OK) goto tmp_error;
+
+ /* Find max y accross parts and process counts */
+ htable_part_id_begin(&part->parts_to_merge_with, &beg);
+ htable_part_id_end(&part->parts_to_merge_with, &end);
+ it = beg;
+ while(!htable_part_id_iterator_eq(&it, &end)) {
+ part_id_t* did = htable_part_id_iterator_key_get(&it);
+ struct part_descriptor* d;
+ htable_part_id_iterator_next(&it);
+
+ ASSERT(did);
+ d = parts[*did];
+
+ p2c[*did] = cc->cc_id;
+
+ cc->side_count += d->side_count;
+ cc->side_range.first = MMIN(cc->side_range.first, d->side_range.first);
+ cc->side_range.last = MMAX(cc->side_range.last, d->side_range.last);
+ tmp_res = htable_media_set(&cc->media, &d->medium, &one);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ goto tmp_error;
+ }
+
+ comp_max_y = vertices[d->max_y_vrtx_id].pos.y;
+ if(max_y < comp_max_y) {
+ max_y = comp_max_y;
+ max_y_vrtx_id = d->max_y_vrtx_id;
+ }
+ }
+ ASSERT(max_y_vrtx_id != VRTX_NULL__);
+ cc->max_y_vrtx_id = max_y_vrtx_id;
+
+ /* Process the parts with max_y as max y value to compute local normal
+ * at max_y_vrtx_id vertex from sides sharing it */
+ it = beg;
+ while(!htable_part_id_iterator_eq(&it, &end)) {
+ part_id_t* did = htable_part_id_iterator_key_get(&it);
+ struct part_descriptor* d = parts[*did];
+ side_id_t side_id;
+ htable_part_id_iterator_next(&it);
+
+ comp_max_y = vertices[d->max_y_vrtx_id].pos.y;
+ if(max_y != comp_max_y) continue;
+ FOR_EACH(side_id, d->side_range.first, d->side_range.last) {
+ const seg_id_t seg_id = SEGSIDE_2_SEG(side_id);
+ enum side_flag side_flag = SEGSIDE_2_SIDE(side_id);
+ const struct segment_in* seg_in =
+ darray_segment_in_cdata_get(&desc->scene->segments_in) + seg_id;
+ const struct segment_part* seg_part =
+ darray_segment_part_cdata_get(segments_part) + seg_id;
+
+ /* To garanty that segments with 2 sides in the component total to 0
+ * regardless of numeric accuracy, we need to prevent them to
+ * contribute (remember than x + y - x - y can be non-zero). */
+ if(part2comp(part2comp_table, seg_part->part[SIDE_FRONT]) ==
+ part2comp(part2comp_table, seg_part->part[SIDE_BACK]))
+ continue;
+ /* Is this side a member of the component? */
+ if(seg_part->part[side_flag] != d->part_id) continue;
+ /* Does this segment use the currently selected max_y vertex? */
+ if(max_y_vrtx_id != seg_in->vertice_id[0]
+ && max_y_vrtx_id != seg_in->vertice_id[1])
+ continue;
+
+ /* This segments' normal contributes to the local normal */
+ d2_sub(edge, vertices[seg_in->vertice_id[1]].vec,
+ vertices[seg_in->vertice_id[0]].vec);
+ d2(normal, edge[1], -edge[0]);
+ norm = d2_normalize(normal, normal);
+ ASSERT(norm); (void)norm;
+
+ /* Geometrical normal points toward the back side */
+ if(SEGSIDE_IS_FRONT(side_id)) {
+ max_y_ny -= normal[1];
+ } else {
+ max_y_ny += normal[1];
+ }
+ }
+ }
+
+ /* All this computation was to set this flag!
+ * Note that it cannot be computed from the flags of the parts of the
+ * component as we need to filter segments whom 2 sides belongs to
+ * the component (to ensure n + -n = 0) but each side was member of 2
+ * different parts. */
+ cc->is_outer_border = (max_y_ny < 0);
+ continue;
+ tmp_error:
+ MEM_RM(alloc, cc);
+ *res = tmp_res;
+ continue;
+ }
+
+ return;
+}
+
+static void
group_connex_components
(struct senc2d_descriptor* desc,
struct segside* segsides,
- struct darray_segment_comp* segments_comp,
+ struct darray_segment_part* segments_part,
struct darray_ptr_component_descriptor* connex_components,
+ struct darray_component_id* part2comp_table,
struct s2d_scene_view* s2d_view,
ATOMIC* next_enclosure_id,
ATOMIC* infinity_first_cc,
@@ -551,9 +717,11 @@ group_connex_components
size_t tmp;
component_id_t cc_count;
int64_t ccc;
+ struct filter_context context;
+
(void)segsides;
- ASSERT(desc && segsides && segments_comp && connex_components
+ ASSERT(desc && segsides && segments_part && connex_components && part2comp_table
&& s2d_view && next_enclosure_id && infinity_first_cc && res);
ASSERT(desc->enclosures_count == 1);
@@ -562,6 +730,8 @@ group_connex_components
ASSERT(tmp <= COMPONENT_MAX__);
cc_count = (component_id_t)tmp;
positions = darray_position_cdata_get(&desc->scene->vertices);
+ context.segments_part = segments_part;
+ context.part2comp_table = part2comp_table;
/* Cast rays to find links between connex components */
#pragma omp for
@@ -574,26 +744,29 @@ group_connex_components
const float range[2] = { 0, FLT_MAX };
struct cc_descriptor* const cc = descriptors[c];
component_id_t self_hit_component = cc->cc_id;
- const double* max_vrtx = positions[cc->max_y_vrtx_id].vec;
+ const double* max_vrtx;
if(*res != RES_OK) continue;
ASSERT(cc->cc_id == c);
ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE);
+ ASSERT(cc->max_y_vrtx_id < desc->scene->nverts);
+ max_vrtx = positions[cc->max_y_vrtx_id].vec;
if(cc->is_outer_border) {
- int64_t id;
+ ATOMIC id;
/* Don't need to cast a ray */
cc->cc_group_root = cc->cc_id; /* New group with self as root */
id = ATOMIC_INCR(next_enclosure_id) - 1;
- ASSERT(id < ENCLOSURE_MAX__);
+ ASSERT(id <= ENCLOSURE_MAX__);
cc->enclosure_id = (enclosure_id_t)id;
continue;
}
f2_set_d2(origin, max_vrtx);
/* Self-hit data: self hit if hit this component "on the other side" */
+ context.self_hit_component = &self_hit_component;
tmp_res = s2d_scene_view_trace_ray(s2d_view, origin, dir, range,
- &self_hit_component, &hit);
+ &context, &hit);
if(tmp_res != RES_OK) {
*res = tmp_res;
continue;
@@ -606,77 +779,23 @@ group_connex_components
/* Keep track of the first component facing infinity */
ATOMIC_CAS(infinity_first_cc, (ATOMIC)cc, (ATOMIC)NULL);
inf_first_cc = (struct cc_descriptor*)ATOMIC_GET(infinity_first_cc);
- if(inf_first_cc->medium != cc->medium) {
- /* Medium mismatch! Model topology is broken. */
- const double* infinity_max_vrtx =
- positions[inf_first_cc->max_y_vrtx_id].vec;
- log_err(desc->scene->dev,
- "Medium mismatch found between vertex %lu and vertex %lu,"
- " both facing infinity.\n",
- (unsigned long) inf_first_cc->max_y_vrtx_id,
- (unsigned long)cc->max_y_vrtx_id);
- log_err(desc->scene->dev,
- "Vertex %lu: (%g %g)\n",
- (unsigned long) inf_first_cc->max_y_vrtx_id,
- SPLIT2(infinity_max_vrtx));
- log_err(desc->scene->dev,
- "Vertex %lu: (%g %g)\n",
- (unsigned long)cc->max_y_vrtx_id,
- SPLIT2(max_vrtx));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- (unsigned long) inf_first_cc->medium, (unsigned long)cc->medium);
- *res = RES_BAD_ARG;
- }
- /* Same medium as previous members of the group: OK */
} else {
/* If hit, group this component */
const seg_id_t hit_seg_id = (seg_id_t)hit.prim.prim_id;
- const struct segment_in* hit_seg_in =
- darray_segment_in_cdata_get(&desc->scene->segments_in) + hit_seg_id;
- const struct segment_comp* hit_seg_comp =
- darray_segment_comp_cdata_get(segments_comp) + hit_seg_id;
+ /* const struct segment_in* hit_seg_in =
+ darray_segment_in_cdata_get(&desc->scene->segments_in) + hit_seg_id; */
+ const struct segment_part* hit_seg_part =
+ darray_segment_part_cdata_get(segments_part) + hit_seg_id;
enum side_id hit_side = (hit.normal[1] > 0) ? SIDE_FRONT : SIDE_BACK;
- const side_id_t hit_side_id = SEGIDxSIDE_2_SEGSIDE(hit_seg_id, hit_side);
+ /* const side_id_t hit_side_id
+ = SEGIDxSIDE_2_SEGSIDE(hit_seg_id, hit_side); */
ASSERT(hit_seg_id < desc->scene->nusegs);
/* Not really the root until following links */
- cc->cc_group_root = hit_seg_comp->component[hit_side];
-#ifndef NDEBUG
- {
- const struct cc_descriptor* hit_desc;
- ASSERT(cc->cc_group_root
- < darray_ptr_component_descriptor_size_get(connex_components));
- hit_desc = *(darray_ptr_component_descriptor_cdata_get(connex_components)
- + cc->cc_group_root);
- ASSERT(hit_desc->medium == hit_seg_in->medium[hit_side]);
- }
-#endif
- if(hit_seg_in->medium[hit_side] != cc->medium) {
- /* Medium mismatch! Model topology is broken. */
- const seg_id_t seg = SEGSIDE_2_SEG(hit_side_id);
- const struct segment_in* segments_in
- = darray_segment_in_cdata_get(&desc->scene->segments_in);
- log_err(desc->scene->dev,
- "Medium mismatch found between vertex %lu and segment"
- " %lu %s side facing each other.\n",
- (unsigned long)cc->max_y_vrtx_id,
- (unsigned long)segments_in[seg].global_id,
- SEGSIDE_IS_FRONT(hit_side_id) ? "front" : "back");
- log_err(desc->scene->dev,
- "Vertex %lu: (%g %g)\n",
- (unsigned long)cc->max_y_vrtx_id,
- SPLIT2(max_vrtx));
- log_err(desc->scene->dev,
- "Segment %lu:\n (%g %g) (%g %g)\n",
- (unsigned long)segments_in[seg].global_id,
- SPLIT2(positions[segments_in[seg].vertice_id[0]].vec),
- SPLIT2(positions[segments_in[seg].vertice_id[1]].vec));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- (unsigned long)cc->medium,
- (unsigned long)hit_seg_in->medium[hit_side]);
- *res = RES_BAD_ARG;
- }
+ cc->cc_group_root =
+ part2comp(part2comp_table, hit_seg_part->part[hit_side]);
+ ASSERT(cc->cc_group_root < cc_count);
}
}
/* Implicit barrier here */
@@ -705,7 +824,6 @@ group_connex_components
}
ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE);
ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE);
- ASSERT(cc->medium == other_desc->medium);
cc->cc_group_root = other_desc->cc_group_root;
cc->enclosure_id = other_desc->enclosure_id;
++enclosures[cc->enclosure_id].cc_count;
@@ -716,6 +834,12 @@ group_connex_components
enclosures[cc->enclosure_id].side_range.last
= MMAX(enclosures[cc->enclosure_id].side_range.last, cc->side_range.last);
enclosures[cc->enclosure_id].side_count += cc->side_count;
+ tmp_res = htable_media_merge(
+ &enclosures[cc->enclosure_id].tmp_enclosed_media, &cc->media);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
}
}
}
@@ -874,8 +998,6 @@ collect_and_link_neighbours
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);
- p_crt_side->list_id = FLAG_LIST_SIDE_LIST;
- p_ccw_side->list_id = FLAG_LIST_SIDE_LIST;
}
}
/* Threads are allowed to return whitout sync. */
@@ -885,7 +1007,8 @@ static void
build_result
(struct senc2d_descriptor* desc,
const struct darray_ptr_component_descriptor* connex_components,
- const struct darray_segment_comp* segments_comp_array,
+ struct darray_component_id* part2comp_table,
+ const struct darray_segment_part* segments_part_array,
/* Shared error status.
* We accept to overwritte an error with a different error */
res_T* res)
@@ -897,20 +1020,20 @@ build_result
struct enclosure_data* enclosures;
const struct segment_in* segments_in;
struct segment_enc* segments_enc;
- const struct segment_comp* segments_comp;
+ const struct segment_part* segments_part;
struct htable_vrtx_id vtable;
int64_t sg;
int64_t ee;
- ASSERT(desc && connex_components && segments_comp_array && res);
+ ASSERT(desc && connex_components && segments_part_array && res);
alloc = descriptor_get_allocator(desc);
ASSERT(darray_ptr_component_descriptor_size_get(connex_components)
- < COMPONENT_MAX__);
+ <= COMPONENT_MAX__);
cc_descriptors = darray_ptr_component_descriptor_cdata_get(connex_components);
enclosures = darray_enclosure_data_get(&desc->enclosures);
segments_in = darray_segment_in_cdata_get(&desc->scene->segments_in);
- segments_comp = darray_segment_comp_cdata_get(segments_comp_array);
+ segments_part = darray_segment_part_cdata_get(segments_part_array);
#pragma omp single
{
res_T tmp_res =
@@ -924,8 +1047,10 @@ build_result
#pragma omp for
for(sg = 0; sg < (int64_t)desc->scene->nusegs; sg++) {
seg_id_t s = (seg_id_t)sg;
- const component_id_t cf_id = segments_comp[s].component[SIDE_FRONT];
- const component_id_t cb_id = segments_comp[s].component[SIDE_BACK];
+ const part_id_t pf_id = segments_part[s].part[SIDE_FRONT];
+ const part_id_t pb_id = segments_part[s].part[SIDE_BACK];
+ const component_id_t cf_id = part2comp(part2comp_table, pf_id);
+ const component_id_t cb_id = part2comp(part2comp_table, pb_id);
const struct cc_descriptor* cf = cc_descriptors[cf_id];
const struct cc_descriptor* cb = cc_descriptors[cb_id];
const enclosure_id_t ef_id = cf->enclosure_id;
@@ -946,33 +1071,45 @@ build_result
for(ee = 0; ee < (int64_t)desc->enclosures_count; ee++) {
const enclosure_id_t e = (enclosure_id_t)ee;
struct enclosure_data* enc = enclosures + e;
- const struct cc_descriptor* current = cc_descriptors[enc->first_component];
- struct darray_enc_id* enc_ids_by_medium;
seg_id_t fst_idx = 0;
seg_id_t sgd_idx = enc->side_count;
seg_id_t s;
+ medium_id_t m;
res_T tmp_res = RES_OK;
ASSERT(enc->first_component
< darray_ptr_component_descriptor_size_get(connex_components));
- ASSERT(current->cc_id == enc->first_component);
+ ASSERT(cc_descriptors[enc->first_component]->cc_id
+ == enc->first_component);
if(*res != RES_OK) continue;
ASSERT(e <= UINT_MAX);
enc->header.enclosure_id = (unsigned)e; /* Back to API type */
- ASSERT(current->enclosure_id == enc->header.enclosure_id);
+ ASSERT(cc_descriptors[enc->first_component]->enclosure_id
+ == enc->header.enclosure_id);
enc->header.is_infinite = (e == 0);
- enc->header.enclosed_medium
- = (unsigned)current->medium; /* Back to API type */
- ASSERT(enc->header.enclosed_medium < desc->scene->nmeds);
- enc_ids_by_medium =
- darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium)
- + current->medium;
- #pragma omp critical
- {
- tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e);
+ ASSERT(htable_media_size_get(&enc->tmp_enclosed_media) <= UINT_MAX);
+ enc->header.enclosed_media_count
+ = (unsigned)htable_media_size_get(&enc->tmp_enclosed_media);
+ ASSERT(enc->header.enclosed_media_count <= desc->scene->nmeds);
+ OK2(htable_media_to_darray_media
+ (&enc->enclosed_media, &enc->tmp_enclosed_media));
+ htable_media_purge(&enc->tmp_enclosed_media);
+
+ /* 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;
+ #pragma omp critical
+ {
+ tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e);
+ }
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
}
- if(tmp_res != RES_OK) *res = tmp_res;
if(*res != RES_OK) continue;
/* Build side and vertex lists. */
@@ -1057,11 +1194,15 @@ senc2d_scene_analyze
char segments_tmp_initialized = 0;
/* Array of connex components.
* They are refered to by arrays of ids. */
+ struct darray_ptr_part_descriptor connex_parts;
+ char connex_parts_initialized = 0;
+ struct darray_component_id part2comp_table;
+ char part2comp_table_initialized = 0;
struct darray_ptr_component_descriptor connex_components;
char connex_components_initialized = 0;
- /* Store by-segment components */
- struct darray_segment_comp segments_comp;
- char segments_comp_initialized = 0;
+ /* Store by-segment parts */
+ struct darray_segment_part segments_part;
+ char segments_part_initialized = 0;
/* Array of vertices (segment ends). */
struct segside* segsides = NULL;
struct s2d_scene_view* s2d_view = NULL;
@@ -1069,12 +1210,13 @@ senc2d_scene_analyze
struct darray_neighbourhood neighbourhood_by_vertex;
char neighbourhood_by_vertex_initialized = 0;
/* Atomic counters to share beetwen threads */
+ ATOMIC part_count = 0;
ATOMIC component_count = 0;
ATOMIC next_enclosure_id = 1;
/* Used as args to have shared vars between threads in functions */
static_assert(sizeof(intptr_t) == sizeof(ATOMIC),
"Cannot use ATOMIC to store pointers");
- ATOMIC infinity_first_cc = (ATOMIC) NULL;
+ ATOMIC infinity_first_cc = (ATOMIC)NULL;
res_T res = RES_OK;
res_T res2 = RES_OK;
@@ -1102,7 +1244,7 @@ senc2d_scene_analyze
/* We create a neighbourhood for every single unique vertex,
* regardless the fact it is used by a segment.
- * This allows threads to use these neighbourhoods whithout syn. */
+ * This allows threads to use these neighbourhoods whithout sync. */
darray_neighbourhood_init(scn->dev->allocator, &neighbourhood_by_vertex);
neighbourhood_by_vertex_initialized = 1;
OK(darray_neighbourhood_resize(&neighbourhood_by_vertex, scn->nuverts));
@@ -1123,15 +1265,15 @@ senc2d_scene_analyze
#pragma omp single
{
res_T tmp_res = RES_OK;
- darray_ptr_component_descriptor_init(scn->dev->allocator,
- &connex_components);
- connex_components_initialized = 1;
+
+ darray_segment_part_init(scn->dev->allocator, &segments_part);
+ segments_part_initialized = 1;
+ OK2(darray_segment_part_resize(&segments_part, scn->nusegs));
+ darray_ptr_part_descriptor_init(scn->dev->allocator,
+ &connex_parts);
+ connex_parts_initialized = 1;
/* Just a hint; to limit contention */
- OK2(darray_ptr_component_descriptor_reserve(&connex_components,
- 2 * scn->nmeds));
- darray_segment_comp_init(scn->dev->allocator, &segments_comp);
- segments_comp_initialized = 1;
- OK2(darray_segment_comp_resize(&segments_comp, scn->nusegs));
+ OK2(darray_ptr_part_descriptor_reserve(&connex_parts, 2 * scn->nmeds));
tmp_error:
if(tmp_res != RES_OK) res2 = tmp_res;
}
@@ -1159,8 +1301,8 @@ senc2d_scene_analyze
} /* No barrier here */
/* Step 2: extract segment connex components */
- extract_connex_components(desc, segsides, &connex_components,
- &segments_tmp, &segments_comp, &s2d_view, &component_count, &res);
+ extract_connex_parts(desc, segsides, &connex_parts, &segments_tmp,
+ &segments_part, &s2d_view, &part_count, &res);
/* No barrier at the end of step 2: data used in step 2 cannot be
* released / data produced by step 2 cannot be used
* until next sync point */
@@ -1177,19 +1319,51 @@ senc2d_scene_analyze
goto error_;
}
- /* One thread releases some data before going to step 3,
- * the others go to step 3 without sync */
- #pragma omp single nowait
+ #pragma omp sections
{
- darray_segment_tmp_release(&segments_tmp);
- segments_tmp_initialized = 0;
- } /* No barrier here */
+ /* One thread releases some data */
+ #pragma omp section
+ {
+ darray_segment_tmp_release(&segments_tmp);
+ segments_tmp_initialized = 0;
+ }
+ /* Another allocates */
+ #pragma omp section
+ {
+ res_T tmp_res = RES_OK;
+ component_id_t* data;
+ size_t parts_count = darray_ptr_part_descriptor_size_get(&connex_parts);
+ size_t i;
+
+ darray_component_id_init(scn->dev->allocator, &part2comp_table);
+ part2comp_table_initialized = 1;
+ tmp_res = darray_component_id_resize(&part2comp_table, parts_count);
+ if(tmp_res != RES_OK) goto tmp2_error;
+ data = darray_component_id_data_get(&part2comp_table);
+ FOR_EACH(i, 0, parts_count) data[i] = PART_NULL__;
+ darray_ptr_component_descriptor_init(scn->dev->allocator,
+ &connex_components);
+ connex_components_initialized = 1;
+ /* Just a starting point */
+ tmp_res = darray_ptr_component_descriptor_reserve(&connex_components,
+ 2 * scn->nmeds);
+ tmp2_error:
+ if(tmp_res != RES_OK) res2 = tmp_res;
+ }
+ }
+ /* Implicit barrier here */
+
+ /* Step 3: merge parts */
+ merge_connex_parts(desc, &segments_part, &connex_parts,
+ &connex_components, &part2comp_table, &component_count, &res);
+ /* Barrier at the end of step 3: data used in step 4 can be released /
+ * data produced by step 4 can be used */
- /* Step 3: group components */
- group_connex_components(desc, segsides, &segments_comp, &connex_components,
- s2d_view, &next_enclosure_id, &infinity_first_cc, &res);
- /* Barrier at the end of step 3: data used in step 3 can be released /
- * data produced by step 3 can be used */
+ /* Step 4: group components */
+ group_connex_components(desc, segsides, &segments_part, &connex_components,
+ &part2comp_table, s2d_view, &next_enclosure_id, &infinity_first_cc, &res);
+ /* Barrier at the end of step 4: data used in step 4 can be released /
+ * data produced by step 4 can be used */
if(res != RES_OK) {
#pragma omp single nowait
@@ -1200,22 +1374,24 @@ senc2d_scene_analyze
goto error_;
}
- /* One thread releases some data before going to step 4,
- * the others go to step 4 without sync */
+ /* One thread releases some data before going to step 5,
+ * the others go to step 5 without sync */
#pragma omp single nowait
{
+ custom_darray_ptr_part_descriptor_release(&connex_parts);
+ connex_parts_initialized = 0;
if(s2d_view) S2D(scene_view_ref_put(s2d_view));
s2d_view = NULL;
} /* No barrier here */
- /* Step 4: Build result */
- build_result(desc, &connex_components, &segments_comp, &res);
- /* No barrier at the end of step 4: data used in step 4 cannot be
- * released / data produced by step 4 cannot be used
+ /* Step 5: Build result */
+ build_result(desc, &connex_components, &part2comp_table, &segments_part, &res);
+ /* No barrier at the end of step 5: data used in step 5 cannot be
+ * released / data produced by step 5 cannot be used
* until next sync point */
#pragma omp barrier
- /* Constraints on step 4 data are now met */
+ /* Constraints on step 5 data are now met */
if(res != RES_OK) {
#pragma omp single nowait
@@ -1230,14 +1406,18 @@ senc2d_scene_analyze
{
#pragma omp section
{
- ASSERT(connex_components_initialized);
custom_darray_ptr_component_descriptor_release(&connex_components);
connex_components_initialized = 0;
}
#pragma omp section
{
- darray_segment_comp_release(&segments_comp);
- segments_comp_initialized = 0;
+ darray_segment_part_release(&segments_part);
+ segments_part_initialized = 0;
+ }
+#pragma omp section
+ {
+ darray_component_id_release(&part2comp_table);
+ part2comp_table_initialized = 0;
}
} /* No barrier here */
error_:
@@ -1246,13 +1426,17 @@ error_:
if(res != RES_OK) goto error;
exit:
+ if(connex_parts_initialized)
+ custom_darray_ptr_part_descriptor_release(&connex_parts);
if(connex_components_initialized)
custom_darray_ptr_component_descriptor_release(&connex_components);
+ if(connex_parts_initialized)
+ custom_darray_ptr_part_descriptor_release(&connex_parts);
if(s2d_view) S2D(scene_view_ref_put(s2d_view));
if(neighbourhood_by_vertex_initialized)
darray_neighbourhood_release(&neighbourhood_by_vertex);
if(segments_tmp_initialized) darray_segment_tmp_release(&segments_tmp);
- if(segments_comp_initialized) darray_segment_comp_release(&segments_comp);
+ if(segments_part_initialized) darray_segment_part_release(&segments_part);
if(segsides) MEM_RM(scn->dev->allocator, segsides);
if(desc) *out_desc = desc;
diff --git a/src/senc2d_scene_analyze_c.h b/src/senc2d_scene_analyze_c.h
@@ -20,65 +20,119 @@
#include "senc2d_internal_types.h"
#include <rsys/mem_allocator.h>
-#include <rsys/dynamic_array_uchar.h>
#include <rsys/hash_table.h>
#include <rsys/double2.h>
-
/* This one is used as flag */
enum side_flag {
FLAG_FRONT = BIT(0),
FLAG_BACK = BIT(1)
};
-enum list_id {
- FLAG_NO_LIST = 0,
- FLAG_LIST_SIDE_LIST = BIT(1),
- FLAG_LIST_COMPONENT = BIT(2),
- FLAG_WAITING_STACK = BIT(3),
- FLAG_ANY_LIST = 0xFF
-};
-
/* Information kept during the building side groups. */
struct segside {
/* Rank of the segside facing this segside through its vertices */
side_id_t facing_side_id[2];
/* Id of this segside's medium */
medium_id_t medium;
- /* The list containing the segside; made of enum list_id flags */
- unsigned char list_id;
/* Implicit information that we don't need to store:
* - segment_id
* - side
* This is due to the memory layout of the elt darray:
* front(seg_0), back(seg_0), front(seg_1), back(seg_1), ... */
+};
-#ifndef NDEBUG
- component_id_t member_of_cc;
-#endif
+#define HTABLE_NAME part_id
+#define HTABLE_KEY part_id_t
+#define HTABLE_DATA char
+#include <rsys/hash_table.h>
+
+#define DARRAY_NAME side_id
+#define DARRAY_DATA side_id_t
+#include <rsys/dynamic_array.h>
+
+/* Descriptors for parts of connex components.
+ * Define lists of seg sides starting from a given head.
+ * Also keeps the maximum y info of the component
+ * along with the associated segment and vertex ids
+ * and the list of media found */
+struct part_descriptor {
+ char not_head_of_group;
+ component_id_t part_id;
+ vrtx_id_t max_y_vrtx_id; /* id of the vrtx with max y value */
+ side_id_t side_count;
+ medium_id_t medium;
+ /* Range of sides member of this part */
+ struct side_range side_range;
+ /* Other parts that need to be merged with this one */
+ struct htable_part_id parts_to_merge_with;
};
+extern const struct part_descriptor PART_DESCRIPTOR_NULL;
+
+static FINLINE void
+part_descriptor_init
+ (struct mem_allocator* alloc,
+ struct part_descriptor* data)
+{
+ ASSERT(data);
+ (void) alloc;
+ *data = PART_DESCRIPTOR_NULL;
+ htable_part_id_init(alloc, &data->parts_to_merge_with);
+}
+
+static FINLINE void
+ptr_part_descriptor_init
+ (struct mem_allocator* alloc,
+ struct part_descriptor** data)
+{
+ (void) alloc;
+ ASSERT(data);
+ *data = NULL;
+}
-/* Descriptors for connex component.
+#define DARRAY_NAME ptr_part_descriptor
+#define DARRAY_DATA struct part_descriptor*
+#define DARRAY_FUNCTOR_INIT ptr_part_descriptor_init
+#include <rsys/dynamic_array.h>
+
+/* Need allocator to free array elts: cannot rely on standard
+* darray release stuff */
+static FINLINE void
+custom_darray_ptr_part_descriptor_release
+ (struct darray_ptr_part_descriptor* array)
+{
+ size_t c, cc_count;
+ struct part_descriptor** components;
+ if(!array) return;
+ cc_count = darray_ptr_part_descriptor_size_get(array);
+ components = darray_ptr_part_descriptor_data_get(array);
+ FOR_EACH(c, 0, cc_count) {
+ if(!components[c]) continue;
+ htable_part_id_release(&components[c]->parts_to_merge_with);
+ MEM_RM(array->allocator, components[c]);
+ }
+ darray_ptr_part_descriptor_release(array);
+}
+
+/* Descriptors for connex components.
* Define lists of seg sides starting from a given head.
* Also keeps the maximum y info of the component
- * along with the associated segment and vertex ids */
-#define CC_ID_NONE COMPONENT_MAX__
-#define CC_GROUP_ROOT_NONE COMPONENT_MAX__
-#define CC_GROUP_ROOT_INFINITE (COMPONENT_MAX__-1)
-#define CC_GROUP_ID_NONE COMPONENT_MAX__
+ * along with the associated segment and vertex ids
+ * and the list of media found */
struct cc_descriptor {
/* Does this component is an outer border of an enclosure or an inner one? */
char is_outer_border;
- vrtx_id_t max_y_vrtx_id;
+ vrtx_id_t max_y_vrtx_id; /* id of the vrtx with max y value */
side_id_t side_count;
- medium_id_t medium;
/* Used when grouping components to form enclosures */
component_id_t cc_id;
component_id_t cc_group_root;
enclosure_id_t enclosure_id;
- /* Range of sides member of this component */
+ /* Range of sides member of this part */
struct side_range side_range;
+ /* Media used by this component */
+ struct htable_media media;
};
extern const struct cc_descriptor CC_DESCRIPTOR_NULL;
@@ -90,6 +144,7 @@ cc_descriptor_init
ASSERT(data);
(void)alloc;
*data = CC_DESCRIPTOR_NULL;
+ htable_media_init(alloc, &data->media);
}
static FINLINE void
@@ -118,7 +173,11 @@ custom_darray_ptr_component_descriptor_release
if(!array) return;
cc_count = darray_ptr_component_descriptor_size_get(array);
components = darray_ptr_component_descriptor_data_get(array);
- FOR_EACH(c, 0, cc_count) MEM_RM(array->allocator, components[c]);
+ FOR_EACH(c, 0, cc_count) {
+ if(!components[c]) continue;
+ htable_media_release(&components[c]->media);
+ MEM_RM(array->allocator, components[c]);
+ }
darray_ptr_component_descriptor_release(array);
}
diff --git a/src/test_senc2d_descriptor.c b/src/test_senc2d_descriptor.c
@@ -28,7 +28,7 @@ main(int argc, char** argv)
struct senc2d_descriptor* desc = NULL;
struct senc2d_enclosure* enc = NULL;
struct context ctx;
- unsigned count;
+ unsigned count, maxm;
unsigned indices[2];
double coord[2];
unsigned media[2];
@@ -61,12 +61,12 @@ main(int argc, char** argv)
CHK(senc2d_descriptor_ref_put(NULL) == RES_BAD_ARG);
CHK(senc2d_descriptor_ref_put(desc) == RES_OK);
- CHK(senc2d_descriptor_get_max_medium(NULL, &count) == RES_BAD_ARG);
+ CHK(senc2d_descriptor_get_max_medium(NULL, &maxm) == RES_BAD_ARG);
CHK(senc2d_descriptor_get_max_medium(desc, NULL) == RES_BAD_ARG);
- CHK(senc2d_descriptor_get_enclosure_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc2d_descriptor_get_max_medium(desc, &count) == RES_OK);
+ CHK(senc2d_descriptor_get_max_medium(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(count == 2);
+ CHK(maxm == 1);
CHK(senc2d_descriptor_get_enclosure_count(NULL, &count) == RES_BAD_ARG);
CHK(senc2d_descriptor_get_enclosure_count(desc, NULL) == RES_BAD_ARG);
diff --git a/src/test_senc2d_enclosure.c b/src/test_senc2d_enclosure.c
@@ -132,7 +132,16 @@ main(int argc, char** argv)
CHK(senc2d_enclosure_get_segment_global_id(NULL, nsegments, NULL)
== RES_BAD_ARG);
CHK(senc2d_enclosure_get_segment_global_id(enclosure, 0, &gid) == RES_OK);
-
+
+ CHK(senc2d_enclosure_get_medium(NULL, 0, medium) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(enclosure, 2, medium) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(enclosure, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(NULL, 2, medium) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(enclosure, 2, NULL) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(NULL, 2, NULL) == RES_BAD_ARG);
+ CHK(senc2d_enclosure_get_medium(enclosure, 0, medium) == RES_OK);
+
CHK(senc2d_enclosure_ref_put(enclosure) == RES_OK);
FOR_EACH(i, 0, ecount) {
@@ -144,7 +153,7 @@ main(int argc, char** argv)
CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
CHK(header.enclosure_id == i);
- CHK((header.enclosed_medium == 0) == header.is_infinite);
+ CHK(header.enclosed_media_count == 1);
CHK(header.segment_count == nsegments);
CHK(header.unique_segment_count == nsegments);
CHK(header.vertices_count == nvertices);
@@ -203,7 +212,7 @@ main(int argc, char** argv)
CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
CHK(header.enclosure_id == 0);
- CHK(header.enclosed_medium == 0);
+ CHK(header.enclosed_media_count == 1);
CHK(header.segment_count == 2 * header.unique_segment_count);
CHK(header.unique_segment_count == nsegments - 1);
CHK(header.vertices_count == nvertices);
diff --git a/src/test_senc2d_many_enclosures.c b/src/test_senc2d_many_enclosures.c
@@ -128,12 +128,15 @@ main(int argc, char** argv)
FOR_EACH(e, 0, count) {
struct senc2d_enclosure* enclosure;
struct senc2d_enclosure_header header;
+ unsigned m;
CHK(senc2d_descriptor_get_enclosure(desc, e, &enclosure) == RES_OK);
CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
+ CHK(header.enclosed_media_count == 1);
+ CHK(senc2d_enclosure_get_medium(enclosure, 0, &m) == RES_OK);
CHK(header.segment_count ==
- (e == 0 /* Outermost enclosure: NB_CIRC_1*NB_CIRC_1 circles */
+ (header.is_infinite /* Outermost enclosure: NB_CIRC_1*NB_CIRC_1 circles */
? NB_CIRC_1 * NB_CIRC_1 * circ_seg_count
- : (header.enclosed_medium == 0
+ : (m == 0
? circ_seg_count /* Innermost enclosures: 1 circle */
: 2 * circ_seg_count))); /* Other enclosures: 2 circles */
CHK(senc2d_enclosure_ref_put(enclosure) == RES_OK);
diff --git a/src/test_senc2d_scene.c b/src/test_senc2d_scene.c
@@ -27,7 +27,7 @@ main(int argc, char** argv)
struct senc2d_scene* scn = NULL;
struct senc2d_descriptor* desc = NULL;
struct context ctx;
- unsigned count, i;
+ unsigned count, i, maxm;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -129,11 +129,24 @@ main(int argc, char** argv)
CHK(senc2d_scene_create(dev, &scn) == RES_OK);
CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media,
get_global_id, nvertices, get_position, &ctx) == RES_OK);
- /* Medium mismatch between neighbour segments */
- CHK(senc2d_scene_analyze(scn, &desc) == RES_BAD_ARG);
- ctx.front_media = medium0;
+ /* Medium mismatch between neighbour segments, but OK */
+ CHK(senc2d_scene_analyze(scn, &desc) == RES_OK);
+
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(maxm == 3);
+ CHK(senc2d_descriptor_get_enclosure_count_by_medium(desc, 0, &count) == RES_OK);
+ CHK(count == 0); /* Medium 0 unused */
+ CHK(senc2d_descriptor_get_enclosure_count_by_medium(desc, 1, &count) == RES_OK);
+ CHK(count == 2); /* Medium 1 used twice */
+ CHK(senc2d_descriptor_get_enclosure_count_by_medium(desc, 2, &count) == RES_OK);
+ CHK(count == 0); /* Medium 2 unused */
+ CHK(senc2d_descriptor_get_enclosure_count_by_medium(desc, 3, &count) == RES_OK);
+ CHK(count == 1); /* Medium 3 used */
+ check_desc(desc);
+ ctx.front_media = medium0;
CHK(senc2d_scene_ref_put(scn) == RES_OK);
+ CHK(senc2d_descriptor_ref_put(desc) == RES_OK);
CHK(senc2d_scene_create(dev, &scn) == RES_OK);
CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media, NULL,
nvertices, get_position, &ctx) == RES_OK);
diff --git a/src/test_senc2d_square_behind_square.c b/src/test_senc2d_square_behind_square.c
@@ -18,30 +18,6 @@
#include <rsys/double2.h>
-void check_desc(struct senc2d_descriptor* desc) {
- unsigned mcount, ecount, i;
- CHK(senc2d_descriptor_get_max_medium(desc, &mcount) == RES_OK);
- CHK(mcount == 2);
- CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- FOR_EACH(i, 0, mcount) {
- unsigned j, ecount_bym;
- unsigned found = 0;
- senc2d_descriptor_get_enclosure_count_by_medium(desc, i, &ecount_bym);
- FOR_EACH(j, 0, ecount_bym) {
- struct senc2d_enclosure* enc;
- struct senc2d_enclosure_header h;
- CHK(senc2d_descriptor_get_enclosure_by_medium(desc, i, j, &enc) == RES_OK);
- CHK(senc2d_enclosure_get_header(enc, &h) == RES_OK);
- found += (h.enclosed_medium == i);
- CHK(senc2d_enclosure_ref_put(enc) == RES_OK);
- }
- ASSERT(found == ecount_bym); /* All the enclosures enclose medim i */
- ASSERT(ecount_bym);
- ecount -= ecount_bym;
- }
- ASSERT(ecount == 0);
-}
-
int
main(int argc, char** argv)
{
@@ -50,6 +26,7 @@ main(int argc, char** argv)
struct senc2d_device* dev = NULL;
struct senc2d_scene* scn = NULL;
struct context ctx;
+ unsigned i, ecount, maxm;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -83,13 +60,26 @@ main(int argc, char** argv)
CHK(senc2d_scene_analyze(scn, &desc) == RES_OK);
+ CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 3);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc2d_enclosure* enclosure;
+ struct senc2d_enclosure_header header;
+ CHK(senc2d_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
+ CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
+ ASSERT(header.enclosed_media_count == 1);
+ CHK(senc2d_enclosure_ref_put(enclosure) == RES_OK);
+ }
+
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(maxm == 1);
check_desc(desc);
/* Even further in +Y, even bigger */
d2(ctx.offset, -3, 30);
ctx.scale = 7;
- /* Front/back media have been exchanged: external enclosure shows 2 media
- * analyze will fail */
+ /* Front/back media have been exchanged: external enclosure shows 2 media */
ctx.front_media = medium1;
ctx.back_media = medium0;
@@ -99,7 +89,23 @@ main(int argc, char** argv)
if(desc) CHK(senc2d_descriptor_ref_put(desc) == RES_OK);
desc = NULL;
- CHK(senc2d_scene_analyze(scn, &desc) == RES_BAD_ARG);
+ CHK(senc2d_scene_analyze(scn, &desc) == RES_OK);
+
+ CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 4);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc2d_enclosure* enclosure;
+ struct senc2d_enclosure_header header;
+ CHK(senc2d_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
+ CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
+ ASSERT(header.enclosed_media_count == (header.is_infinite ? 2u : 1u));
+ CHK(senc2d_enclosure_ref_put(enclosure) == RES_OK);
+ }
+
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(maxm == 1);
+ check_desc(desc);
CHK(senc2d_scene_ref_put(scn) == RES_OK);
CHK(senc2d_device_ref_put(dev) == RES_OK);
diff --git a/src/test_senc2d_square_in_square.c b/src/test_senc2d_square_in_square.c
@@ -26,6 +26,7 @@ main(int argc, char** argv)
struct senc2d_device* dev = NULL;
struct senc2d_scene* scn = NULL;
struct context ctx;
+ unsigned i, ecount, maxm;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -62,14 +63,31 @@ main(int argc, char** argv)
CHK(senc2d_scene_analyze(scn, &desc) == RES_OK);
+ CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 3);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc2d_enclosure* enclosure;
+ struct senc2d_enclosure_header header;
+ CHK(senc2d_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
+ CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK);
+ ASSERT(header.enclosed_media_count == 1);
+ CHK(senc2d_enclosure_ref_put(enclosure) == RES_OK);
+ }
+
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(maxm == 1);
+ check_desc(desc);
+
d2(ctx.offset, -4, -4);
ctx.scale = 10;
ctx.reverse_vrtx = 1;
ctx.reverse_med = 1;
/* Biggest square exterior is medium 1 */
ctx.front_media = medium1;
- /* Biggest square interior is medium 0 */
- ctx.back_media = medium0; /* mismatch with square 2 */
+ /* Biggest square interior is medium 0
+ * interior/exterior media have been exchanged: external enclosure shows 2 media */
+ ctx.back_media = medium0;
/* Third square */
CHK(senc2d_scene_add_geometry(scn, nsegments, get_indices, get_media, NULL,
@@ -77,7 +95,14 @@ main(int argc, char** argv)
if(desc) CHK(senc2d_descriptor_ref_put(desc) == RES_OK);
desc = NULL;
- CHK(senc2d_scene_analyze(scn, &desc) == RES_BAD_ARG);
+ CHK(senc2d_scene_analyze(scn, &desc) == RES_OK);
+
+ CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 4);
+
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(maxm == 1);
+ check_desc(desc);
CHK(senc2d_scene_ref_put(scn) == RES_OK);
CHK(senc2d_device_ref_put(dev) == RES_OK);
diff --git a/src/test_senc2d_utils.h b/src/test_senc2d_utils.h
@@ -236,5 +236,43 @@ circle_release(struct context* ctx)
ctx->indices = NULL;
}
+
+/*******************************************************************************
+ * Check functions
+ ******************************************************************************/
+static INLINE void check_desc(struct senc2d_descriptor* desc)
+{
+ unsigned maxm, ecount, i;
+ size_t e_cpt = 0;
+ CHK(senc2d_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+ CHK(senc2d_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ for (i = 0; i <= maxm; i++) {
+ unsigned j, ecount_bym;
+ unsigned found = 0;
+ CHK(senc2d_descriptor_get_enclosure_count_by_medium(desc, i, &ecount_bym) == RES_OK);
+ /* Can be 0 if media numbering is not compact */
+ FOR_EACH(j, 0, ecount_bym) {
+ struct senc2d_enclosure* enc;
+ struct senc2d_enclosure_header h;
+ unsigned k;
+ int f = 0;
+ CHK(senc2d_descriptor_get_enclosure_by_medium(desc, i, j, &enc) == RES_OK);
+ CHK(senc2d_enclosure_get_header(enc, &h) == RES_OK);
+ ASSERT(h.enclosed_media_count);
+ FOR_EACH(k, 0, h.enclosed_media_count) {
+ unsigned m;
+ CHK(senc2d_enclosure_get_medium(enc, k, &m) == RES_OK);
+ found += (m == i);
+ f += (m == i);
+ }
+ ASSERT(f == 1); /* Single reference expected */
+ CHK(senc2d_enclosure_ref_put(enc) == RES_OK);
+ }
+ ASSERT(found == ecount_bym); /* All the enclosures enclose medim i */
+ e_cpt += ecount_bym;
+ }
+ ASSERT(e_cpt >= ecount); /* Every enc has been visited at least once */
+}
+
#endif /* TEST_UTILS2_H */