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 fe205d708689b01f2d47071ff6e4f19d0b684b25
parent ef70db214a639d840b26604be31de2e39701fe0a
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu, 26 Jul 2018 16:54:45 +0200

For saving purpose. Not finished

Diffstat:
Msrc/senc2d_descriptor_c.h | 16++++++++--------
Msrc/senc2d_internal_types.h | 12+++---------
Msrc/senc2d_scene_analyze.c | 705+++++++++++++++++++++++++------------------------------------------------------
Msrc/senc2d_scene_analyze_c.h | 70+---------------------------------------------------------------------
4 files changed, 237 insertions(+), 566 deletions(-)

diff --git a/src/senc2d_descriptor_c.h b/src/senc2d_descriptor_c.h @@ -26,22 +26,22 @@ struct senc2d_scene; struct mem_allocator; -struct segment_part { - /* The connex component part in which each side is. */ - part_id_t part[2]; +struct segment_comp { + /* The connex component in which each side is. */ + component_id_t component[2]; }; static void -segment_part_init(struct mem_allocator* alloc, struct segment_part* seg) { +segment_comp_init(struct mem_allocator* alloc, struct segment_comp* seg) { int i; (void)alloc; ASSERT(seg); - FOR_EACH(i, 0, 2) seg->part[i] = PART_NULL__; + FOR_EACH(i, 0, 2) seg->component[i] = COMPONENT_NULL__; } -#define DARRAY_NAME segment_part -#define DARRAY_DATA struct segment_part -#define DARRAY_FUNCTOR_INIT segment_part_init +#define DARRAY_NAME segment_comp +#define DARRAY_DATA struct segment_comp +#define DARRAY_FUNCTOR_INIT segment_comp_init #include <rsys/dynamic_array.h> struct segment_enc { diff --git a/src/senc2d_internal_types.h b/src/senc2d_internal_types.h @@ -81,21 +81,15 @@ 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__ (UINT32_MAX - 2) /* To allow special values */ +#define COMPONENT_MAX__ (UINT32_MAX - 3) /* To allow special values */ #define COMPONENT_NULL__ UINT32_MAX -/* Special part values */ +/* Special values */ #define CC_GROUP_ROOT_NONE UINT32_MAX #define CC_GROUP_ROOT_INFINITE (UINT32_MAX - 1) +#define CC_IN_STACK (UINT32_MAX - 2) #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 { SIDE_FRONT = 0, diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c @@ -32,12 +32,6 @@ #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,\ CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\ @@ -64,37 +58,39 @@ static FINLINE res_T add_side_to_stack (const struct senc2d_scene* scn, struct darray_side_id* stack, - struct segment_part* segments_part, + struct segment_comp* segments_comp, const side_id_t side_id) { (void)scn; - seg_id_t seg = SEGSIDE_2_SEG(side_id); - enum side_flag sf = SEGSIDE_2_SIDE(side_id); - ASSERT(scn && segments_part && stack + ASSERT(scn && segments_comp && stack && side_id < SIDE_MAX__ && side_id < 2 * scn->nusegs); - 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); + { + seg_id_t seg = SEGSIDE_2_SEG(side_id); + enum side_flag sf = SEGSIDE_2_SIDE(side_id); + ASSERT(segments_comp[seg].component[sf] == COMPONENT_NULL__); + segments_comp[seg].component[sf] = CC_IN_STACK; + return darray_side_id_push_back(stack, &side_id); + } } static side_id_t -get_side_not_in_connex_part +get_side_not_in_connex_component (const seg_id_t last_side, const struct segside* segsides, - const struct segment_part* segments_part, - side_id_t* first_side_not_in_part, + struct segment_comp* segments_comp, + side_id_t* first_side_not_in_component, const medium_id_t medium) { - ASSERT(segsides && segments_part && first_side_not_in_part); + ASSERT(segsides && segments_comp && first_side_not_in_component); { - side_id_t i = *first_side_not_in_part; + side_id_t i = *first_side_not_in_component; while(i <= last_side && (segsides[i].medium != medium - || (segments_part[SEGSIDE_2_SEG(i)].part[SEGSIDE_2_SIDE(i)] - <= PART_MAX__))) { + || (segments_comp[SEGSIDE_2_SEG(i)].component[SEGSIDE_2_SIDE(i)] + <= COMPONENT_MAX__))) { ++i; } - *first_side_not_in_part = i + 1; + *first_side_not_in_component = i + 1; if(i > last_side) return SIDE_NULL__; return i; } @@ -102,20 +98,21 @@ get_side_not_in_connex_part static FINLINE side_id_t get_side_from_stack - (const struct segment_part* segments_part, + (struct segment_comp* segments_comp, struct darray_side_id* stack) { - side_id_t id; - size_t sz; - (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(segments_part[SEGSIDE_2_SEG(id)].part[SEGSIDE_2_SIDE(id)] - == PART_IN_STACK); - darray_side_id_pop_back(stack); - return id; + ASSERT(segments_comp && stack); + (void)segments_comp; + { + side_id_t id; + size_t sz = darray_side_id_size_get(stack); + ASSERT(sz); + id = darray_side_id_cdata_get(stack)[sz - 1]; + ASSERT(segments_comp[SEGSIDE_2_SEG(id)].component[SEGSIDE_2_SIDE(id)] + == CC_IN_STACK); + darray_side_id_pop_back(stack); + return id; + } } static void @@ -138,22 +135,6 @@ 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, @@ -162,26 +143,19 @@ self_hit_filter void* ray_data, void* filter_data) { - 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; + const struct darray_segment_comp* segments_comp = filter_data; + const component_id_t* origin_component = ray_data; + const struct segment_comp* hit_seg_comp; enum side_id hit_side; - part_id_t hit_part; component_id_t hit_component; - (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) + (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) + hit->prim.prim_id; hit_side = (hit->normal[1] > 0) ? SIDE_FRONT : SIDE_BACK; - hit_part = hit_seg_part->part[hit_side]; - hit_component = part2comp(part2comp_table, hit_part); + hit_component = hit_seg_comp->component[hit_side]; /* If self hit, distance should be small */ ASSERT(hit_component != *origin_component || hit->distance < 1e-6); @@ -189,14 +163,14 @@ self_hit_filter } static void -extract_connex_parts +extract_connex_components (struct senc2d_descriptor* desc, struct segside* segsides, - struct darray_ptr_part_descriptor* connex_parts, + struct darray_ptr_component_descriptor* connex_components, const struct darray_segment_tmp* segments_tmp_array, - struct darray_segment_part* segments_part_array, + struct darray_segment_comp* segments_comp_array, struct s2d_scene_view** s2d_view, - ATOMIC* part_count, + ATOMIC* component_count, /* Shared error status. * We accept to overwritte an error with a different error */ res_T* res) @@ -210,24 +184,34 @@ extract_connex_parts struct darray_side_id ids_of_sides_around_max_y_vertex; const union double2* positions; const struct segment_tmp* segments_tmp; - struct segment_part* segments_part; - size_t sz; + size_t ii, sz; + res_T res2 = RES_OK; + /* Per-thread component table to allow sync-free access; to be merged */ + struct darray_segment_comp local_comp_array; + struct segment_comp* local_comp; - ASSERT(segsides && desc && connex_parts && segments_tmp_array - && segments_part_array && s2d_view && part_count && res); + ASSERT(segsides && desc && connex_components && segments_tmp_array + && segments_comp_array && s2d_view && component_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); + darray_segment_comp_init(alloc, &local_comp_array); + res2 = darray_segment_comp_resize(&local_comp_array, scn->nusegs); + if(res2 != RES_OK) { + *res = res2; + return; + } + local_comp = darray_segment_comp_data_get(&local_comp_array); + #ifndef NDEBUG #pragma omp single { seg_id_t s_; - ASSERT(darray_ptr_part_descriptor_size_get(connex_parts) == 0); + ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0); FOR_EACH(s_, 0, scn->nusegs) { const struct segment_in* seg_in = darray_segment_in_cdata_get(&scn->segments_in) + s_; @@ -243,26 +227,28 @@ extract_connex_parts } /* Implicit barrier here */ #endif - /* We loop on sides to build parts of 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; - struct part_descriptor* part; + struct cc_descriptor* cc; /* 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; - side_id_t first_side_not_in_part = media_use->first; + side_id_t first_side_not_in_component = media_use->first; + double max_y_ny; const seg_id_t last_side = media_use->last; + char one = 1; ATOMIC id; if(*res != RES_OK) continue; - if(first_side_not_in_part == SIDE_NULL__) + if(first_side_not_in_component == SIDE_NULL__) continue; /* Unused medium */ - ASSERT(first_side_not_in_part < 2 * scn->nusegs); + ASSERT(first_side_not_in_component < 2 * scn->nusegs); ASSERT(darray_side_id_size_get(&stack) == 0); - 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); + for(;;) { /* Process all components for this medium */ + const side_id_t start_side_id = get_side_not_in_connex_component + (last_side, segsides, local_comp, &first_side_not_in_component, m); side_id_t crt_side_id = start_side_id; side_id_t last_side_id = start_side_id; double max_y = -DBL_MAX; @@ -283,36 +269,37 @@ extract_connex_parts } #endif - /* Create and init a new part */ - part = MEM_ALLOC(alloc, sizeof(struct part_descriptor)); - if(!part) { + /* Create and init a new component */ + cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); + if(!cc) { *res = RES_MEM_ERR; continue; } - part_descriptor_init(alloc, part); + cc_descriptor_init(alloc, cc); ASSERT(m == segsides[start_side_id].medium); - 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 part */ + id = ATOMIC_INCR(component_count) - 1; + ASSERT(id <= COMPONENT_MAX__); + cc->cc_id = (component_id_t)id; + cc->side_range.first = start_side_id; + /* First medium of the component */ + htable_media_set(&cc->media, &m, &one); + + for(;;) { /* Process all sides of this component */ 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_part* seg_part = segments_part + crt_seg_id; + struct segment_comp* seg_comp = local_comp + crt_seg_id; const struct segment_tmp* const seg_tmp = segments_tmp + crt_seg_id; + res_T tmp_res; ASSERT(crt_seg_id < scn->nusegs); - 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 part in order + * Keep track of the appropriate vertex of the component 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. */ @@ -322,97 +309,135 @@ extract_connex_parts /* New vertex: reset list of sides */ darray_side_id_clear(&ids_of_sides_around_max_y_vertex); - /* Select one vertex with y == max_y */ + /* Select a vertex with y == max_y */ if(max_y == positions[seg_in->vertice_id[0]].pos.y) { - part->max_y_vrtx_id = seg_in->vertice_id[0]; + cc->max_y_vrtx_id = seg_in->vertice_id[0]; } else { ASSERT(max_y == positions[seg_in->vertice_id[1]].pos.y); - part->max_y_vrtx_id = seg_in->vertice_id[1]; + cc->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, + tmp_res = darray_side_id_push_back(&ids_of_sides_around_max_y_vertex, &crt_side_id); + if(tmp_res != RES_OK) *res = tmp_res; } else if(max_y == seg_tmp->max_y) { /* Does this segment use the currently selected max_y vertex? */ FOR_EACH(i, 0, 2) { - if(part->max_y_vrtx_id == seg_in->vertice_id[i]) { + if(cc->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, + tmp_res = darray_side_id_push_back(&ids_of_sides_around_max_y_vertex, &crt_side_id); + if(tmp_res != RES_OK) *res = tmp_res; break; } } } if(*res != RES_OK) break; - /* 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; + /* Record crt_side both as component and segment level */ + cc->side_count++; + ASSERT(seg_comp->component[crt_side_flag] > COMPONENT_MAX__); + seg_comp->component[crt_side_flag] = cc->cc_id; /* 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; + struct segment_comp* nbour_comp = local_comp + nbour_seg_id; const struct segside* neighbour = segsides + neighbour_id; - if(neighbour->medium != crt_side->medium) { - /* 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; - } + if(neighbour->medium < m) { + /* Not the same medium. + * Neighbour's medium id is less than current medium: the whole + * component is to be processed by another thread (possibly the one + * associated with neighbour's medium). */ + + + continue; } - if(nbour_part->part[nbour_side_id] != PART_NULL__) { + if(nbour_comp->component[nbour_side_id] != COMPONENT_NULL__) { #ifndef NDEBUG - /* 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); + /* If already affected must be to the same component */ + ASSERT(nbour_comp->component[nbour_side_id] == CC_IN_STACK + || nbour_comp->component[nbour_side_id] == cc->cc_id); #endif continue; /* Already processed */ } - *res = add_side_to_stack(scn, &stack, segments_part, neighbour_id); + tmp_res = add_side_to_stack(scn, &stack, local_comp, neighbour_id); + if(tmp_res != RES_OK) *res = tmp_res; if(*res != RES_OK) break; } if(*res != RES_OK) break; if(darray_side_id_size_get(&stack) == 0) - break; /* Empty stack => part is done! */ - crt_side_id = get_side_from_stack(segments_part, &stack); + break; /* Empty stack => component is done! */ + crt_side_id = get_side_from_stack(local_comp, &stack); last_side_id = MMAX(last_side_id, crt_side_id); } if(*res != RES_OK) { - MEM_RM(alloc, part); - part = NULL; + MEM_RM(alloc, cc); + cc = NULL; break; } - part->side_range.last = last_side_id; - /* Need to synchronize connex_parts growth as this global structure + /* 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 = local_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); + + /* Need to synchronize connex_components growth as this global structure * is accessed by multipe threads */ #pragma omp critical { - 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); + 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); 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 */ - parts = darray_ptr_part_descriptor_data_get(connex_parts); - ASSERT(parts[part->part_id] == NULL); - parts[part->part_id] = part; + components = + darray_ptr_component_descriptor_data_get(connex_components); + ASSERT(components[cc->cc_id] == NULL); + components[cc->cc_id] = cc; } } } @@ -445,7 +470,8 @@ extract_connex_parts 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, NULL); + s2d_line_segments_set_hit_filter_function(s2d_shp, self_hit_filter, + darray_segment_comp_data_get(segments_comp_array)); OK2(s2d_scene_attach_shape(s2d_scn, s2d_shp)); OK2(s2d_scene_view_create(s2d_scn, S2D_TRACE, s2d_view)); tmp_error: @@ -462,18 +488,19 @@ extract_connex_parts #pragma omp single { seg_id_t s_; - part_id_t p; - ASSERT(ATOMIC_GET(part_count) == - (int)darray_ptr_part_descriptor_size_get(connex_parts)); + component_id_t c; + ASSERT(ATOMIC_GET(component_count) == + (int)darray_ptr_component_descriptor_size_get(connex_components)); FOR_EACH(s_, 0, scn->nusegs) { - struct segment_part* seg_part = segments_part + s_; - ASSERT(seg_part->part[SIDE_FRONT] != PART_NULL__); - ASSERT(seg_part->part[SIDE_BACK] != PART_NULL__); + struct segment_comp* seg_comp = + darray_segment_comp_data_get(segments_comp_array) + s_; + ASSERT(seg_comp->component[SIDE_FRONT] != COMPONENT_NULL__); + ASSERT(seg_comp->component[SIDE_BACK] != COMPONENT_NULL__); } - 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); + 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); } ASSERT(desc->segment_count == scn->nusegs); } /* Implicit barrier here */ @@ -481,231 +508,13 @@ extract_connex_parts } 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 is called from an omp parallel block and executed - * concurrently. */ - 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_part* segments_part, + struct darray_segment_comp* segments_comp, 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, /* Shared error status. * We accept to overwritte an error with a different error */ res_T* res) @@ -717,12 +526,10 @@ group_connex_components size_t tmp; component_id_t cc_count; int64_t ccc; - struct filter_context context; - (void)segsides; - ASSERT(desc && segsides && segments_part && connex_components && part2comp_table - && s2d_view && next_enclosure_id && infinity_first_cc && res); + ASSERT(desc && segsides && segments_comp && connex_components + && s2d_view && next_enclosure_id && res); ASSERT(desc->enclosures_count == 1); descriptors = darray_ptr_component_descriptor_data_get(connex_components); @@ -730,8 +537,6 @@ 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 @@ -764,28 +569,23 @@ group_connex_components 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, - &context, &hit); + &self_hit_component, &hit); if(tmp_res != RES_OK) { *res = tmp_res; continue; } /* If no hit, the component is facing an infinite medium */ if(S2D_HIT_NONE(&hit)) { - struct cc_descriptor* inf_first_cc; cc->cc_group_root = CC_GROUP_ROOT_INFINITE; cc->enclosure_id = 0; - /* 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); } 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_part* hit_seg_part = - darray_segment_part_cdata_get(segments_part) + hit_seg_id; + const struct segment_comp* hit_seg_comp = + darray_segment_comp_cdata_get(segments_comp) + 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); */ @@ -793,8 +593,7 @@ group_connex_components ASSERT(hit_seg_id < desc->scene->nusegs); /* Not really the root until following links */ - cc->cc_group_root = - part2comp(part2comp_table, hit_seg_part->part[hit_side]); + cc->cc_group_root = hit_seg_comp->component[hit_side]; ASSERT(cc->cc_group_root < cc_count); } } @@ -1007,8 +806,7 @@ static void build_result (struct senc2d_descriptor* desc, const struct darray_ptr_component_descriptor* connex_components, - struct darray_component_id* part2comp_table, - const struct darray_segment_part* segments_part_array, + const struct darray_segment_comp* segments_comp_array, /* Shared error status. * We accept to overwritte an error with a different error */ res_T* res) @@ -1020,12 +818,12 @@ build_result struct enclosure_data* enclosures; const struct segment_in* segments_in; struct segment_enc* segments_enc; - const struct segment_part* segments_part; + const struct segment_comp* segments_comp; struct htable_vrtx_id vtable; int64_t sg; int64_t ee; - ASSERT(desc && connex_components && segments_part_array && res); + ASSERT(desc && connex_components && segments_comp_array && res); alloc = descriptor_get_allocator(desc); ASSERT(darray_ptr_component_descriptor_size_get(connex_components) @@ -1033,7 +831,7 @@ build_result 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_part = darray_segment_part_cdata_get(segments_part_array); + segments_comp = darray_segment_comp_cdata_get(segments_comp_array); #pragma omp single { res_T tmp_res = @@ -1047,10 +845,8 @@ build_result #pragma omp for for(sg = 0; sg < (int64_t)desc->scene->nusegs; sg++) { seg_id_t s = (seg_id_t)sg; - 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 component_id_t cf_id = segments_comp[s].component[SIDE_FRONT]; + const component_id_t cb_id = segments_comp[s].component[SIDE_BACK]; 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; @@ -1194,15 +990,11 @@ 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 parts */ - struct darray_segment_part segments_part; - char segments_part_initialized = 0; + /* Store by-segment components */ + struct darray_segment_comp segments_comp; + char segments_comp_initialized = 0; /* Array of vertices (segment ends). */ struct segside* segsides = NULL; struct s2d_scene_view* s2d_view = NULL; @@ -1210,13 +1002,8 @@ 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; res_T res = RES_OK; res_T res2 = RES_OK; @@ -1266,14 +1053,15 @@ senc2d_scene_analyze { res_T tmp_res = RES_OK; - 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; + darray_ptr_component_descriptor_init(scn->dev->allocator, + &connex_components); + connex_components_initialized = 1; /* Just a hint; to limit contention */ - OK2(darray_ptr_part_descriptor_reserve(&connex_parts, 2 * scn->nmeds)); + 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)); tmp_error: if(tmp_res != RES_OK) res2 = tmp_res; } @@ -1301,8 +1089,8 @@ senc2d_scene_analyze } /* No barrier here */ /* Step 2: extract segment connex components */ - extract_connex_parts(desc, segsides, &connex_parts, &segments_tmp, - &segments_part, &s2d_view, &part_count, &res); + extract_connex_components(desc, segsides, &connex_components, + &segments_tmp, &segments_comp, &s2d_view, &component_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 */ @@ -1319,51 +1107,19 @@ senc2d_scene_analyze goto error_; } - #pragma omp sections + /* One thread releases some data before going to step 3, + * the others go to step 3 without sync */ + #pragma omp single nowait { - /* 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 */ + darray_segment_tmp_release(&segments_tmp); + segments_tmp_initialized = 0; + } /* No barrier here */ - /* 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 */ + /* Step 3: group components */ + group_connex_components(desc, segsides, &segments_comp, &connex_components, + s2d_view, &next_enclosure_id, &res); + /* Barrier at the end of step 3: data used in step 3 can be released / + * data produced by step 3 can be used */ if(res != RES_OK) { #pragma omp single nowait @@ -1374,24 +1130,22 @@ senc2d_scene_analyze goto error_; } - /* One thread releases some data before going to step 5, - * the others go to step 5 without sync */ + /* One thread releases some data before going to step 4, + * the others go to step 4 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 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 + /* 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 * until next sync point */ #pragma omp barrier - /* Constraints on step 5 data are now met */ + /* Constraints on step 4 data are now met */ if(res != RES_OK) { #pragma omp single nowait @@ -1411,13 +1165,8 @@ senc2d_scene_analyze } #pragma omp section { - darray_segment_part_release(&segments_part); - segments_part_initialized = 0; - } -#pragma omp section - { - darray_component_id_release(&part2comp_table); - part2comp_table_initialized = 0; + darray_segment_comp_release(&segments_comp); + segments_comp_initialized = 0; } } /* No barrier here */ error_: @@ -1426,17 +1175,13 @@ 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_part_initialized) darray_segment_part_release(&segments_part); + if(segments_comp_initialized) darray_segment_comp_release(&segments_comp); 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 @@ -43,78 +43,10 @@ struct segside { * front(seg_0), back(seg_0), front(seg_1), back(seg_1), ... */ }; -#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; -} - -#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 @@ -129,7 +61,7 @@ struct cc_descriptor { component_id_t cc_id; component_id_t cc_group_root; enclosure_id_t enclosure_id; - /* Range of sides member of this part */ + /* Range of sides member of this component */ struct side_range side_range; /* Media used by this component */ struct htable_media media;