star-enclosures-3d

Extract enclosures from 3D geometry
git clone git://git.meso-star.fr/star-enclosures-3d.git
Log | Files | Refs | README | LICENSE

commit 2f347c293c77c9f1538d56ebcf4b4e840497c23e
parent d89475a09cd79c60cc0d1f872456273456b5084e
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 19 Jun 2024 11:32:26 +0200

BugFix: grouping of connex components

Grouping could associate a wrong component after rejecting the correct
one. The rejection was caused by same Z coordinate between origin and
hit on component, not meeting the "upward-only" rule for grouping.
This rule is in-place to avoid creating loops when grouping, and should
not be removed. Also one should avoid introducing different rules for
distant (d > 0) hits on inner and outer components.

The selected fix rely on using the max Z coordinate of the hit
components instead of hit.z, as this remains effictive in avoiding
loops, and is not affected by numerical accuracy concerns.

Diffstat:
Msrc/senc3d_scene_analyze.c | 49+++++++++++++++++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c @@ -344,6 +344,12 @@ self_hit_filter const int log_components = ctx->scn->convention & SENC3D_LOG_COMPONENTS_INFORMATION; const component_id_t oc = ctx->origin_component; + /* Links must be upward to avoid creating loops + * Instead of comparing hit.z VS origin.z, compare max_Z of components + * Here we keep max_z of the origin component that will be used for these + * comparisons */ + const double org_z = vertices[comp_descriptors[oc]->max_z_vrtx_id].pos.z; + vrtx_id_t other_id; ASSERT(hit->prim.prim_id < darray_triangle_comp_size_get(ctx->triangles_comp)); @@ -439,7 +445,7 @@ self_hit_filter } else { /* c is an inner component */ vrtx_id_t c_z_id; - double org_z, v; + double v; /* If we've already found a valid outer component, inner components * should not be considered anymore */ if(log_components) { @@ -458,7 +464,6 @@ self_hit_filter * another inner component if (at least partly) above it and not * inside */ c_z_id = comp_descriptors[c]->max_z_vrtx_id; - org_z = vertices[comp_descriptors[oc]->max_z_vrtx_id].pos.z; ASSERT(c_z_id < darray_position_size_get(&ctx->scn->vertices)); ASSERT(vertices[c_z_id].pos.z >= org_z); if(vertices[c_z_id].pos.z == org_z) { @@ -499,18 +504,19 @@ self_hit_filter } return 1; } - ASSERT(hit->distance > 0); - - if(ray_dir[2] <= 0) { - /* Not upward */ - if(log_components) { - printf("Component #%u: not upward => reject\n", oc); - } - return 1; - } + ASSERT(hit->distance > 0); if(hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK]) { /* Easy case and hit component is known */ + other_id = comp_descriptors[hit_comp[SENC3D_FRONT]]->max_z_vrtx_id; + ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices)); + if(vertices[other_id].pos.z <= org_z) { + if(log_components) { + printf("Component #%u: 2 sides, not (even in part) above: reject\n", + oc); + } + return 1; + } ctx->hit_component = hit_comp[SENC3D_FRONT]; ctx->s = 1; f3_set(ctx->hit_dir, ray_dir); @@ -551,6 +557,16 @@ self_hit_filter if(fabsf(s) < DOT_THRESHOLD) { /* We cannot know for sure which side to consider */ + vrtx_id_t i1 = comp_descriptors[hit_comp[SENC3D_FRONT]]->max_z_vrtx_id; + vrtx_id_t i2 = comp_descriptors[hit_comp[SENC3D_BACK]]->max_z_vrtx_id; + double possible_z = MMAX(vertices[i1].pos.z, vertices[i2].pos.z); + if(possible_z <= org_z) { + if(log_components) { + printf("Component #%u: tiny s, not (even in part) above: reject\n", + oc); + } + return 1; + } ctx->hit_component = COMPONENT_NULL__; ctx->s = s; f3_set(ctx->hit_dir, ray_dir); @@ -571,13 +587,22 @@ self_hit_filter * the Star3D hit normal is left-handed while star-enclosures-3d uses * right-handed convention */ ? SENC3D_BACK : SENC3D_FRONT; + other_id = comp_descriptors[hit_comp[hit_side]]->max_z_vrtx_id; + ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices)); + if(vertices[other_id].pos.z <= org_z) { + if(log_components) { + printf("Component #%u: standard s, not (even in part) above: reject\n", + oc); + } + return 1; + } ctx->hit_component = hit_comp[hit_side]; ctx->s = s; f3_set(ctx->hit_dir, ray_dir); ctx->hit_dist = hit->distance; ctx->hit_prim = hit->prim; if(log_components) { - printf("Component #%u: standard s (%g): keep component #%u\n", + printf("Component #%u: standard s, (%g): keep component #%u\n", oc, s, ctx->hit_component); } return 1;