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 b2d37159c8dea260119c388e445b1655ca7806d8
parent 353063782dea3e65377dc5775b8f8d5fe38a9fb0
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 21 Jan 2019 19:09:13 +0100

BugFix when grouping components into enclosures

Diffstat:
Msrc/senc2d_scene_analyze.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/test_senc2d_enclosure.c | 4++--
2 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c @@ -206,7 +206,8 @@ extract_connex_components const struct side_range* media_use = darray_side_range_cdata_get(&scn->media_use) + m; side_id_t first_side_not_in_component = media_use->first; - double max_y_ny; + double max_ny; + side_id_t max_ny_side_id = SIDE_NULL__; const side_id_t last_side = media_use->last; int component_canceled = 0; res_T tmp_res = RES_OK; @@ -366,16 +367,20 @@ canceled: ASSERT(IS_ALIGNED(segments_comp->component, sizeof(cc->cc_id))); FOR_EACH(ii, 0, sz) { const side_id_t s = darray_side_id_cdata_get(&current_component)[ii]; - segments_comp[SEGSIDE_2_SEG(s)].component[SEGSIDE_2_SIDE(s)] = cc->cc_id; + ASSERT(segments_comp[SEGSIDE_2_SEG(s)].component[SEGSIDE_2_SIDE(s)] + == COMPONENT_NULL__); + segments_comp[SEGSIDE_2_SEG(s)].component[SEGSIDE_2_SIDE(s)] + = cc->cc_id; } /* Compute the normal at the max_y vertex. */ - max_y_ny = 0; + max_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); + enum side_id s = SEGSIDE_2_SIDE(side_id); const struct segment_in* seg_in = darray_segment_in_cdata_get(&scn->segments_in) + seg_id; struct segment_comp* seg_comp = segments_comp + seg_id; @@ -385,9 +390,8 @@ canceled: /* 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 - y == 0 can be false). */ - ASSERT(seg_comp->component[SIDE_FRONT] == cc->cc_id - || seg_comp->component[SIDE_BACK] == cc->cc_id); + * contribute (remember than x + y - y == x can be false). */ + ASSERT(seg_comp->component[s] == cc->cc_id); if(seg_comp->component[SIDE_FRONT] == seg_comp->component[SIDE_BACK]) continue; @@ -397,15 +401,22 @@ canceled: norm = d2_normalize(normal, normal); ASSERT(norm); (void)norm; - /* Orient the geometrical normal according to the convention */ - if(SEGSIDE_IS_FRONT(side_id) + if(fabs(max_ny) < fabs(normal[1])) { + max_ny_side_id = side_id; + max_ny = normal[1]; + } + } + if(max_ny == 0) cc->is_outer_border = 0; + else { + if(SEGSIDE_IS_FRONT(max_ny_side_id) == ((scn->convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0)) { - max_y_ny += normal[1]; + /* Geom normal points towards the component */ + cc->is_outer_border = (max_ny < 0); } else { - max_y_ny -= normal[1]; + /* Geom normal points away from the component */ + cc->is_outer_border = (max_ny > 0); } } - cc->is_outer_border = (max_y_ny < 0); /* Need to synchronize connex_components growth as this global structure * is accessed by multipe threads */ @@ -575,8 +586,13 @@ group_connex_components const seg_id_t hit_seg_id = (seg_id_t)hit.prim.prim_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; - + enum side_id hit_side = + ((hit.normal[1] < 0) /* Facing geometrical normal of hit */ + == ((desc->scene->convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0)) + /* Warning: Embree 2 convention for geometrical normals is + * left-handed and star-enclosure uses right-handed convention */ + ? SIDE_BACK : SIDE_FRONT; + ASSERT(hit.normal[1] != 0); ASSERT(hit_seg_id < desc->scene->nusegs); /* Not really the root until following links */ @@ -718,6 +734,7 @@ collect_and_link_neighbours vrtx_id_t other_vrtx; struct darray_neighbour* neighbourhood; side_id_t i, neighbour_count; + double a; size_t sz; /* Process only "my" neighbourhoods! */ if((int64_t)v % thread_count != rank) continue; @@ -776,6 +793,7 @@ collect_and_link_neighbours sizeof(struct neighbour_info), neighbour_cmp); /* Link sides. * Create cycles of sides by neighbourhood around common vertex. */ + a = -DBL_MAX; FOR_EACH(i, 0, neighbour_count) { /* Neighbourhood info for current pair of segments */ const struct neighbour_info* current @@ -804,6 +822,23 @@ collect_and_link_neighbours /* Side ptrs */ struct segside* const p_crt_side = segsides + crt_side_idx; struct segside* const p_ccw_side = segsides + ccw_side_idx; + /* Check that angle is a discriminant property */ + ASSERT(a <= current->angle); /* Is sorted */ + if(a == current->angle) { + /* Two consecutive segments with same angle! */ + const struct neighbour_info* previous; + seg_id_t prev_id; + ASSERT(i > 0); + previous = darray_neighbour_cdata_get(neighbourhood) + i - 1; + prev_id = previous->seg_id; + log_err(scn->dev, + "%s: found 2 overlying segments (%u & %u).\n", + FUNC_NAME, prev_id, crt_id); + /* TODO */ + *res = RES_BAD_OP; + return; + } + a = current->angle; /* Link sides */ p_crt_side->facing_side_id[crt_end] = ccw_side_idx; p_ccw_side->facing_side_id[ccw_end] = crt_side_idx; @@ -812,6 +847,16 @@ 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); + /* Detect segments that could surround a hole: + * - single segments on (one of) its end + * - different media on its sides */ + if(neighbour_count == 1 + && p_crt_side->medium != p_ccw_side->medium) + { + log_warn(scn->dev, + "%s: found possible hole involving segments %u.\n", + FUNC_NAME, crt_id); + } } } /* Threads are allowed to return whitout sync. */ diff --git a/src/test_senc2d_enclosure.c b/src/test_senc2d_enclosure.c @@ -213,7 +213,7 @@ test(enum senc2d_convention convention) ctx.scale = 1; d2(ctx.offset, 0, 0); ctx.front_media = medium0; - ctx.back_media = medium0; + ctx.back_media = medium1; CHK(senc2d_scene_add_geometry(scn, nsegments - 1, get_indices, get_media, NULL, nvertices, get_position, &ctx) == RES_OK); @@ -233,7 +233,7 @@ test(enum senc2d_convention convention) CHK(senc2d_enclosure_get_header(enclosure, &header) == RES_OK); CHK(header.enclosure_id == 0); - CHK(header.enclosed_media_count == 1); + CHK(header.enclosed_media_count == 2); CHK(header.segment_count == 2 * header.unique_segment_count); CHK(header.unique_segment_count == nsegments - 1); CHK(header.vertices_count == nvertices);