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 a2af89ce3227132aa08cdcde019b657593cbad53
parent 8938737e7fccbaa3fda6f5261a674c99cc887576
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu, 20 Aug 2020 15:31:34 +0200

BugFix: grouping of nested components in contact at a single vertex

Diffstat:
Msrc/senc3d_scene_analyze.c | 20+++++++++++++++-----
Msrc/test_senc3d_zero_distance.c | 258++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 251 insertions(+), 27 deletions(-)

diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c @@ -68,6 +68,7 @@ struct filter_ctx1 { struct darray_triangle_comp* triangles_comp; struct darray_ptr_component_descriptor* components; /* Result of hit */ + double current_6volume; component_id_t hit_component; }; @@ -184,7 +185,9 @@ self_hit_filter hit_comp = components[hit->prim.prim_id].component; if(hit_comp[SENC3D_FRONT] == ctx2->component || hit_comp[SENC3D_BACK] == ctx2->component) - ctx2->cpt++; + { + ctx2->cpt++; + } return 1; /* Reject to continue counting */ } @@ -293,8 +296,14 @@ self_hit_filter /* 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 origin_component is inside several components, the one we are + * looking for is the smallest one */ + if(v >= fctx->current_6volume) continue; fctx->hit_component = fctx2.c.ctx2.component; - return 0 /* origin_component is linked to c: keep */; + fctx->current_6volume = v; + /* Continue searching for a smaller component that includes + * origin_component */ } } return 1; /* Reject */ @@ -938,8 +947,10 @@ group_connex_components f3_set_d3(origin, max_vrtx); /* Self-hit data: self hit if hit this component "on the other side" */ fctx.c.ctx1.origin_component = cc->cc_id; + fctx.c.ctx1.current_6volume = DBL_MAX; + fctx.c.ctx1.hit_component = COMPONENT_NULL__; /* Limit search radius. Only upwards moves (+Z) will be considered. - * Ue a radius allowing to reach the closest top vertex of scene's AABB */ + * Use a radius allowing to reach the closest top vertex of scene's AABB */ FOR_EACH(i, 0, 2) { ASSERT(lower[i] <= origin[i] && origin[i] <= upper[i]); rrr[i] = MMIN(origin[i] - lower[i], upper[i] - origin[i]); @@ -952,9 +963,8 @@ group_connex_components *res = tmp_res; continue; } - ASSERT(fctx.c.ctx1.hit_component != COMPONENT_NULL__); /* If no hit, the component is facing an infinite medium */ - if(S3D_HIT_NONE(&hit)) { + if(fctx.c.ctx1.hit_component == COMPONENT_NULL__) { cc->cc_group_root = CC_GROUP_ROOT_INFINITE; cc->enclosure_id = 0; } else { diff --git a/src/test_senc3d_zero_distance.c b/src/test_senc3d_zero_distance.c @@ -25,7 +25,12 @@ #include <stdio.h> -/* Test created using -c option of stardis */ +/* Tests created using -c option of stardis */ + +/* zero_1 geometry is made of a big distorded cube, that as a single highest + * vertex V, and two internal shapes (highly distorded cubes) that joint at the + * same V vertex. Distance between the 6 components (inside and outside of each + * shape) is zero. */ #define zero_1_UNSPECIFIED_PROPERTY 4294967295 static const unsigned @@ -140,11 +145,201 @@ zero_1_properties[36][3] = { { 1, 0, zero_1_UNSPECIFIED_PROPERTY } }; -int +/* zero_2 geometry is made of 5 nested distorded cubes of decreasing sizes, that + * all join at a single vertex V (the highest vertex in the model). Distance between + * the 10 components (inside and outside of each shape) is zero. */ +#define zero_2_UNSPECIFIED_PROPERTY 4294967295 + +static const unsigned +zero_2_vertices_count = 36; + +static const unsigned +zero_2_triangles_count = 60; + +static const double +zero_2_vertices[36][3] = { + { 0, 10, 0 }, + { 0, 0, 0 }, + { 0, 10, 10 }, + { 0, 0, 10 }, + { 10, 0, 10 }, + { 10, 0, 0 }, + { 9, 9, 11 }, + { 10, 10, 0 }, + { 1, 9, 1 }, + { 1, 1, 1 }, + { 1, 9, 9 }, + { 1, 1, 9 }, + { 9, 1, 9 }, + { 9, 1, 1 }, + { 9, 9, 1 }, + { 2, 8, 2 }, + { 2, 2, 2 }, + { 2, 8, 8 }, + { 2, 2, 8 }, + { 8, 2, 8 }, + { 8, 2, 2 }, + { 8, 8, 2 }, + { 3, 7, 3 }, + { 3, 3, 3 }, + { 3, 7, 7 }, + { 3, 3, 7 }, + { 7, 3, 7 }, + { 7, 3, 3 }, + { 7, 7, 3 }, + { 4, 6, 4 }, + { 4, 4, 4 }, + { 4, 6, 6 }, + { 4, 4, 6 }, + { 6, 4, 6 }, + { 6, 4, 4 }, + { 6, 6, 4 } +}; + +static const unsigned +zero_2_triangles[60][3] = { + { 0, 1, 2 }, + { 1, 3, 2 }, + { 4, 5, 6 }, + { 5, 7, 6 }, + { 2, 3, 4 }, + { 6, 2, 4 }, + { 5, 1, 0 }, + { 7, 5, 0 }, + { 3, 1, 5 }, + { 4, 3, 5 }, + { 7, 0, 2 }, + { 6, 7, 2 }, + { 8, 9, 10 }, + { 9, 11, 10 }, + { 12, 13, 6 }, + { 13, 14, 6 }, + { 10, 11, 12 }, + { 6, 10, 12 }, + { 13, 9, 8 }, + { 14, 13, 8 }, + { 11, 9, 13 }, + { 12, 11, 13 }, + { 14, 8, 10 }, + { 6, 14, 10 }, + { 15, 16, 17 }, + { 16, 18, 17 }, + { 19, 20, 6 }, + { 20, 21, 6 }, + { 17, 18, 19 }, + { 6, 17, 19 }, + { 20, 16, 15 }, + { 21, 20, 15 }, + { 18, 16, 20 }, + { 19, 18, 20 }, + { 21, 15, 17 }, + { 6, 21, 17 }, + { 22, 23, 24 }, + { 23, 25, 24 }, + { 26, 27, 6 }, + { 27, 28, 6 }, + { 24, 25, 26 }, + { 6, 24, 26 }, + { 27, 23, 22 }, + { 28, 27, 22 }, + { 25, 23, 27 }, + { 26, 25, 27 }, + { 28, 22, 24 }, + { 6, 28, 24 }, + { 29, 30, 31 }, + { 30, 32, 31 }, + { 33, 34, 6 }, + { 34, 35, 6 }, + { 31, 32, 33 }, + { 6, 31, 33 }, + { 34, 30, 29 }, + { 35, 34, 29 }, + { 32, 30, 34 }, + { 33, 32, 34 }, + { 35, 29, 31 }, + { 6, 35, 31 } +}; + +static const unsigned +zero_2_properties[60][3] = { + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 0, zero_2_UNSPECIFIED_PROPERTY, 5 }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 1, 0, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 2, 1, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 3, 2, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY }, + { 4, 3, zero_2_UNSPECIFIED_PROPERTY } +}; + +/* Enclosures' order is consistent accross runs as they are sorted by triangle + * sides, thus allowing to expect a given order */ +struct expected { + unsigned enclosure_count; /* max 16 */ + double volume[16]; /* the volume of the expected enclosures */ + unsigned medium[16]; /* the single medium of the expected enclosures */ +}; + +static int test (const double* positions, const unsigned* indices, - const unsigned* properties) + const unsigned* properties, + const unsigned triangles_count, + const unsigned vertices_count, + const struct expected* expected) { struct mem_allocator allocator; struct senc3d_device* dev = NULL; @@ -153,7 +348,7 @@ test unsigned count, e, n; OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(senc3d_device_create(NULL, &allocator, 1, 1, &dev)); + OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev)); FOR_EACH(n, 0, 2) { /* Create a scene with 4 enclosures joining at a single vertex. */ @@ -170,20 +365,18 @@ test OK(senc3d_scene_create(dev, SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE, - zero_1_triangles_count, get_indices, get_media_from_properties, - zero_1_vertices_count, get_position, &ctx, &scn)); - - OK(senc3d_scene_get_enclosure_count(scn, &count)); - CHK(count == 4); + triangles_count, get_indices, get_media_from_properties, + vertices_count, get_position, &ctx, &scn)); OK(senc3d_scene_get_vertices_count(scn, &count)); - CHK(count == zero_1_vertices_count); + CHK(count == vertices_count); OK(senc3d_scene_get_triangles_count(scn, &count)); - CHK(count == zero_1_triangles_count); + CHK(count == triangles_count); OK(senc3d_scene_get_enclosure_count(scn, &count)); - CHK(count == 4); + CHK(count == expected->enclosure_count); + FOR_EACH(e, 0, count) { struct senc3d_enclosure* enclosure; struct senc3d_enclosure_header header; @@ -193,15 +386,8 @@ test OK(senc3d_enclosure_get_header(enclosure, &header)); CHK(header.enclosed_media_count == 1); OK(senc3d_enclosure_get_medium(enclosure, 0, &m)); - if (header.is_infinite) { - CHK(m == zero_1_UNSPECIFIED_PROPERTY); /* External */ - } - else if (header.primitives_count == 12) { - CHK(m == 1); /* Internal */ - } - else { - CHK(m == 0); /* In between */ - } + CHK(m == expected->medium[e]); + CHK(eq_eps(header.volume, expected->volume[e], 0.01)); OK(senc3d_enclosure_ref_put(enclosure)); #ifdef DUMP_ENCLOSURES snprintf(name, sizeof(name), "test_cube_on_cube_%u.obj", e); @@ -223,10 +409,38 @@ test int main(int argc, char** argv) { + struct expected expected; (void)argc, (void)argv; + expected.enclosure_count = 4; + expected.medium[0] = SENC3D_UNSPECIFIED_MEDIUM; + expected.volume[0] = -966.67; + expected.medium[1] = 0; + expected.volume[1] = 647.33; + expected.medium[2] = 1; + expected.volume[2] = 150; + expected.medium[3] = 1; + expected.volume[3] = 169.33; test((double *)zero_1_vertices, (unsigned*)zero_1_triangles, - (unsigned *)zero_1_properties); + (unsigned *)zero_1_properties, zero_1_triangles_count, + zero_1_vertices_count, &expected); + + expected.enclosure_count = 6; + expected.medium[0] = SENC3D_UNSPECIFIED_MEDIUM; + expected.volume[0] = -966.67; + expected.medium[1] = 0; + expected.volume[1] = 433.33; + expected.medium[2] = 1; + expected.volume[2] = 281.33; + expected.medium[3] = 2; + expected.volume[3] = 161.33; + expected.medium[4] = 3; + expected.volume[4] = 73.33; + expected.medium[5] = 4; + expected.volume[5] = 17.33; + test((double*)zero_2_vertices, (unsigned*)zero_2_triangles, + (unsigned*)zero_2_properties, zero_2_triangles_count, + zero_2_vertices_count, &expected); return 0; } \ No newline at end of file