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:
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(¤t_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);