commit 946a6f56457162ac5a549396460ba152b8ee319e
parent 2bfbf3e2a97d217b66724a7b0cea260a4c2d789b
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 5 Sep 2023 10:36:31 +0200
Fix a crash linked to numerical accuracy
Diffstat:
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c
@@ -163,17 +163,18 @@ self_hit_filter
{
struct filter_ctx* fctx_ = ray_data;
struct filter_ctx1* fctx;
- const struct triangle_comp* components;
+ const struct triangle_comp* trg_comp;
const component_id_t* hit_comp;
float s = 0;
enum senc3d_side hit_side;
int i;
- double mz = -INF;
+ double org_z, mz = -INF;
const struct triangle_in* triangles;
const struct triangle_in* trg = NULL;
const union double3* vertices;
+ struct cc_descriptor* const* comp_descriptors;
- (void)ray_org; (void)ray_dir; (void)ray_range; (void)filter_data;
+ (void)ray_dir; (void)ray_range; (void)filter_data;
ASSERT(hit && fctx_);
if(fctx_->type == FCTX2) {
@@ -182,8 +183,8 @@ self_hit_filter
struct filter_ctx2* ctx2 = &fctx_->c.ctx2;
ASSERT(hit->prim.prim_id
< darray_triangle_comp_size_get(ctx2->triangles_comp));
- components = darray_triangle_comp_cdata_get(ctx2->triangles_comp);
- hit_comp = components[hit->prim.prim_id].component;
+ trg_comp = darray_triangle_comp_cdata_get(ctx2->triangles_comp);
+ hit_comp = trg_comp[hit->prim.prim_id].component;
if(hit_comp[SENC3D_FRONT] == ctx2->component
|| hit_comp[SENC3D_BACK] == ctx2->component)
{
@@ -193,11 +194,11 @@ self_hit_filter
}
/* The filter is called from a point query on successive hits found from
- * ray_org, that belongs to origin_component. It can keep or reject the hit.
+ * ray_org, that belongs to origin_component. It can keep or reject the hit.
* Hits are only submitted inside a certain radius from ray_org, that is
* decreased to the hit distance for every hit that is kept.
* At the end, the last kept hit (= the closest), determines a component to
- * which origin_component is linked. At a later stage the algorithm proceeds
+ * which origin_component is linked. At a later stage the algorithm process
* linked components to determine their relative inclusions.
*
* For each hit, the filter computes if the hit is on a component above
@@ -211,8 +212,9 @@ self_hit_filter
* and remains undetected by star enclosures). */
ASSERT(fctx_->type == FCTX1);
fctx = &fctx_->c.ctx1;
- components = darray_triangle_comp_cdata_get(fctx->triangles_comp);
- hit_comp = components[hit->prim.prim_id].component;
+ comp_descriptors = darray_ptr_component_descriptor_cdata_get(fctx->components);
+ trg_comp = darray_triangle_comp_cdata_get(fctx->triangles_comp);
+ hit_comp = trg_comp[hit->prim.prim_id].component;
triangles = darray_triangle_in_cdata_get(&fctx->scn->triangles_in);
vertices = darray_position_cdata_get(&fctx->scn->vertices);
ASSERT(hit->prim.prim_id
@@ -228,8 +230,6 @@ self_hit_filter
if(hit->distance == 0) {
/* origin_component is in contact with some other components
* We will need further exploration to know if they should be considered */
- struct cc_descriptor* const* descriptors
- = darray_ptr_component_descriptor_cdata_get(fctx->components);
int n;
/* If same component, process only once */
@@ -242,14 +242,14 @@ self_hit_filter
struct s3d_hit hit2 = S3D_HIT_NULL;
struct filter_ctx fctx2;
ASSERT(c < darray_ptr_component_descriptor_size_get(fctx->components));
- if(descriptors[c]->is_outer_border) {
- if(fabs(descriptors[c]->_6volume)
- <= fabs(descriptors[fctx->origin_component]->_6volume))
+ if(comp_descriptors[c]->is_outer_border) {
+ if(fabs(comp_descriptors[c]->_6volume)
+ <= fabs(comp_descriptors[fctx->origin_component]->_6volume))
/* Component is not large enough to include origin_component */
continue;
} else {
- vrtx_id_t c_z_id = descriptors[c]->max_z_vrtx_id;
- vrtx_id_t o_z_id = descriptors[fctx->origin_component]->max_z_vrtx_id;
+ vrtx_id_t c_z_id = comp_descriptors[c]->max_z_vrtx_id;
+ vrtx_id_t o_z_id = comp_descriptors[fctx->origin_component]->max_z_vrtx_id;
ASSERT(c_z_id < darray_position_size_get(&fctx->scn->vertices));
ASSERT(o_z_id < darray_position_size_get(&fctx->scn->vertices));
if(vertices[c_z_id].pos.z <= vertices[o_z_id].pos.z)
@@ -260,14 +260,14 @@ self_hit_filter
* overlap, testing a single point is OK, as long as the point is not on
* c boundary (can be on origin_component boundary, though).
* As this case is supposed to be rare, we go for a basic algorithm */
- for(side = descriptors[fctx->origin_component]->side_range.first;
- side <= descriptors[fctx->origin_component]->side_range.last;
+ for(side = comp_descriptors[fctx->origin_component]->side_range.first;
+ side <= comp_descriptors[fctx->origin_component]->side_range.last;
side++)
{
/* Find a triangle on origin_component boundary that is not on c
* boundary (the 2 components cannot share all their triangles) */
trg_id_t t = TRGSIDE_2_TRG(side);
- const component_id_t* candidate_comp = components[t].component;
+ const component_id_t* candidate_comp = trg_comp[t].component;
if(candidate_comp[SENC3D_FRONT] != fctx->origin_component
&& candidate_comp[SENC3D_BACK] != fctx->origin_component)
continue;
@@ -296,8 +296,8 @@ self_hit_filter
ASSERT(S3D_HIT_NONE(&hit2)); /* The ray is supposed to go to infinity */
/* origin_component is linked_to an outer component if cpt is odd,
* linked_to an inner component if cpt is even */
- if(descriptors[c]->is_outer_border == (fctx2.c.ctx2.cpt % 2)) {
- double v = fabs(descriptors[c]->_6volume);
+ if(comp_descriptors[c]->is_outer_border == (fctx2.c.ctx2.cpt % 2)) {
+ double v = fabs(comp_descriptors[c]->_6volume);
/* If origin_component is inside several components, the one we are
* looking for is the smallest one */
if(v >= fctx->current_6volume) continue;
@@ -324,7 +324,10 @@ self_hit_filter
ASSERT(v < darray_position_size_get(&fctx->scn->vertices));
if(i == 0 || mz < p->pos.z) mz = p->pos.z;
}
- if(mz <= ray_org[2])
+ /* Don't use org[2] as, being float, it would lead to a float VS double
+ * comparison that causes accuracy problems. */
+ org_z = vertices[comp_descriptors[fctx->origin_component]->max_z_vrtx_id].pos.z;
+ if(mz <= org_z)
return 1; /* Hit triangle is below ray_org: reject */
if(hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK]) {