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 9e1ae5f08663305b09824130af2134c486b5ef90
parent 49facacc9e3231bce0050e470d4f0ccd9f509b31
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 11 Feb 2019 16:07:34 +0100

Merge branch 'feature_frontiers' into develop

Diffstat:
Msrc/senc.h | 11+++++++++++
Msrc/senc_descriptor.c | 32++++++++++++++++++++++++++++++++
Msrc/senc_descriptor_c.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/senc_enclosure_data.h | 2+-
Msrc/senc_scene_analyze.c | 40++++++++++++++++++++++++++++------------
Msrc/senc_scene_analyze_c.h | 56+-------------------------------------------------------
Msrc/test_senc_descriptor.c | 30+++++++++++++++++++++++++++++-
7 files changed, 164 insertions(+), 69 deletions(-)

diff --git a/src/senc.h b/src/senc.h @@ -279,6 +279,17 @@ senc_descriptor_get_global_triangle_global_id unsigned* gid); SENC_API res_T +senc_descriptor_get_frontier_segments_count + (const struct senc_descriptor* descriptor, + unsigned* count); /* Number of frontiers segments. */ + +SENC_API res_T +senc_descriptor_get_frontier_segment + (const struct senc_descriptor* descriptor, + const unsigned iseg, + unsigned vrtx_id[2]); + +SENC_API res_T senc_descriptor_ref_get (struct senc_descriptor* descriptor); diff --git a/src/senc_descriptor.c b/src/senc_descriptor.c @@ -37,6 +37,7 @@ descriptor_release(ref_T * ref) darray_triangle_enc_release(&desc->triangles_enc); darray_enclosure_release(&desc->enclosures); darray_enc_ids_array_release(&desc->enc_ids_array_by_medium); + darray_frontier_edge_release(&desc->frontiers); MEM_RM(scn->dev->allocator, desc); SENC(scene_ref_put(scn)); @@ -61,6 +62,7 @@ descriptor_create(struct senc_scene* scn) darray_enc_ids_array_init(scn->dev->allocator, &desc->enc_ids_array_by_medium); OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium, scn->nmeds)); + darray_frontier_edge_init(scn->dev->allocator, &desc->frontiers); /* Enclosure 0 is always defined for infinite */ OK(darray_enclosure_resize(&desc->enclosures, 1)); desc->enclosures_count = 1; @@ -275,6 +277,36 @@ senc_descriptor_get_global_triangle_global_id } res_T +senc_descriptor_get_frontier_segments_count + (const struct senc_descriptor* desc, + unsigned* count) +{ + size_t tmp; + if (!desc || !count) + return RES_BAD_ARG; + tmp = darray_frontier_edge_size_get(&desc->frontiers); + ASSERT(tmp < UINT_MAX); + *count = (unsigned)tmp; + return RES_OK; +} + +res_T +senc_descriptor_get_frontier_segment + (const struct senc_descriptor* desc, + const unsigned iseg, + unsigned vrtx_id[2]) +{ + const struct trg_edge* edge; + if (!vrtx_id || !desc + || iseg >= darray_frontier_edge_size_get(&desc->frontiers)) + return RES_BAD_ARG; + edge = darray_frontier_edge_cdata_get(&desc->frontiers) + iseg; + vrtx_id[0] = (unsigned)edge->vrtx0; /* Back to API type */ + vrtx_id[1] = (unsigned)edge->vrtx1; /* Back to API type */ + return RES_OK; +} + +res_T senc_descriptor_ref_get(struct senc_descriptor* desc) { if(!desc) return RES_BAD_ARG; diff --git a/src/senc_descriptor_c.h b/src/senc_descriptor_c.h @@ -84,6 +84,66 @@ triangle_enc_init(struct mem_allocator* alloc, struct triangle_enc* trg) { #define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_enc_id_copy_and_release #include <rsys/dynamic_array.h> +/* Triangle edge struct and basic functions */ +struct trg_edge { + vrtx_id_t vrtx0, vrtx1; +}; + +static FINLINE int +edge_ok(const struct trg_edge* edge) { + return(edge + && edge->vrtx0 <= VRTX_MAX__ + && edge->vrtx1 <= VRTX_MAX__ + && edge->vrtx0 < edge->vrtx1); +} + +static FINLINE void +set_edge +(const vrtx_id_t vrtx0, + const vrtx_id_t vrtx1, + struct trg_edge* edge, + unsigned char* reversed) +{ + ASSERT(edge && reversed && vrtx0 != vrtx1); + ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */ + if (vrtx0 < vrtx1) { + edge->vrtx0 = vrtx0; + edge->vrtx1 = vrtx1; + *reversed = 0; /* Non reversed edge */ + } + else { + edge->vrtx0 = vrtx1; + edge->vrtx1 = vrtx0; + *reversed = 1; /* Reversed edge */ + } + ASSERT(edge_ok(edge)); +} + +static FINLINE int +edge_eq(const struct trg_edge* e1, const struct trg_edge* e2) +{ + ASSERT(edge_ok(e1) && edge_ok(e2)); + return e1->vrtx0 == e2->vrtx0 && e1->vrtx1 == e2->vrtx1; +} + +/* Information kept during the building of side groups. */ +struct trgside { + /* Rank of the trgside facing this trgside through its edges */ + side_id_t facing_side_id[3]; + /* Id of this trgside's medium */ + medium_id_t medium; + + /* Implicit information that we don't need to store: + * - triangle_id + * - side + * This is due to the memory layout of the elt darray: + * front(trg_0), back(trg_0), front(trg_1), back(trg_1), ... */ +}; + +#define DARRAY_NAME frontier_edge +#define DARRAY_DATA struct trg_edge +#include <rsys/dynamic_array.h> + struct senc_descriptor { struct senc_scene* scene; enclosure_id_t enclosures_count; @@ -94,6 +154,8 @@ struct senc_descriptor { struct darray_enc_ids_array enc_ids_array_by_medium; trg_id_t triangle_count; vrtx_id_t vertices_count; + /* Store frontiers */ + struct darray_frontier_edge frontiers; ref_T ref; }; diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h @@ -97,7 +97,7 @@ bool_array_of_media_to_darray_media ASSERT(sz <= MEDIUM_MAX__); darray_media_clear(dst); if(res != RES_OK) goto error; - FOR_EACH(i, 0, (medium_id_t) sz) { + FOR_EACH(i, 0, (medium_id_t)sz) { if(!data[i]) continue; res = darray_media_push_back(dst, &i); if(res != RES_OK) goto error; diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -14,7 +14,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "senc.h" -#include "senc_descriptor_c.h" #include "senc_device_c.h" #include "senc_scene_c.h" #include "senc_scene_analyze_c.h" @@ -673,6 +672,7 @@ collect_and_link_neighbours (struct senc_scene* scn, struct trgside* trgsides, struct darray_triangle_tmp* triangles_tmp_array, + struct darray_frontier_edge* frontiers, /* Shared error status. * We accept to overwrite an error with a different error */ res_T* res) @@ -698,7 +698,7 @@ collect_and_link_neighbours size_t sz; res_T tmp_res; - ASSERT(scn && trgsides && triangles_tmp_array && res); + ASSERT(scn && trgsides && triangles_tmp_array && frontiers && res); ASSERT((size_t)scn->nuverts + (size_t)scn->nutris + 2 <= EDGE_MAX__); htable_edge_id_init(scn->dev->allocator, &edge_ids); @@ -906,13 +906,15 @@ collect_and_link_neighbours * - different media on its sides */ if(neighbour_count == 1 && p_crt_side->medium != p_ccw_side->medium) +#pragma omp critical { + struct trg_edge disc; log_warn(scn->dev, - "%s: found possible hole involving triangle %lu.\n" - " Edge: %g %g %g -- %g %g %g\n", - FUNC_NAME, (unsigned long)triangles_in[crt_id].global_id, - SPLIT3(vertices[v0].vec), - SPLIT3(vertices[v1].vec)); + "%s: found frontier involving triangle %lu.\n", + FUNC_NAME, (unsigned long)triangles_in[crt_id].global_id); + disc.vrtx0 = v0; + disc.vrtx1 = v1; + darray_frontier_edge_push_back(frontiers, &disc); } } } @@ -928,6 +930,7 @@ build_result (struct senc_descriptor* desc, const struct darray_ptr_component_descriptor* connex_components, const struct darray_triangle_comp* triangles_comp_array, + struct darray_frontier_edge* frontiers, /* Shared error status. * We accept to overwrite an error with a different error */ res_T* res) @@ -946,7 +949,7 @@ build_result int64_t tt; int64_t ee; - ASSERT(desc && connex_components && triangles_comp_array); + ASSERT(desc && connex_components && triangles_comp_array && frontiers && res); alloc = descriptor_get_allocator(desc); scn = desc->scene; @@ -954,7 +957,8 @@ build_result normals_front = (scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0; normals_back = (scn->convention & SENC_CONVENTION_NORMAL_BACK) != 0; ASSERT(normals_back != normals_front); - ASSERT(output_normal_in != ((scn->convention & SENC_CONVENTION_NORMAL_OUTSIDE) != 0)); + ASSERT(output_normal_in + != ((scn->convention & SENC_CONVENTION_NORMAL_OUTSIDE) != 0)); ASSERT(darray_ptr_component_descriptor_size_get(connex_components) <= COMPONENT_MAX__); cc_descriptors = darray_ptr_component_descriptor_cdata_get(connex_components); @@ -973,7 +977,7 @@ build_result /* Build global enclosure information */ #pragma omp for - for(tt = 0; tt < (int64_t) scn->nutris; tt++) { + for(tt = 0; tt < (int64_t)scn->nutris; tt++) { trg_id_t t = (trg_id_t)tt; const component_id_t cf_id = triangles_comp[t].component[SIDE_FRONT]; const component_id_t cb_id = triangles_comp[t].component[SIDE_BACK]; @@ -1121,6 +1125,10 @@ build_result *res = tmp_res; } /* No barrier here */ htable_vrtx_id_release(&vtable); + /* The first thread here copies frontiers into descriptor */ +#pragma omp single nowait + darray_frontier_edge_copy_and_clear(&desc->frontiers, frontiers); + /* No barrier here */ } /******************************************************************************* @@ -1137,6 +1145,9 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) * They are refered to by arrays of ids. */ struct darray_ptr_component_descriptor connex_components; char connex_components_initialized = 0; + /* Array of frontiers edges */ + struct darray_frontier_edge frontiers; + char frontiers_initialized = 0; /* Store by-triangle components */ struct darray_triangle_comp triangles_comp; char triangles_comp_initialized = 0; @@ -1161,6 +1172,8 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp); triangles_tmp_initialized = 1; + darray_frontier_edge_init(scn->dev->allocator, &frontiers); + frontiers_initialized = 1; OK(darray_triangle_tmp_resize(&triangles_tmp, scn->nutris)); trgsides @@ -1183,7 +1196,8 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) #pragma omp parallel num_threads(scn->dev->nthreads) { /* Step 1: build neighbourhoods */ - collect_and_link_neighbours(scn, trgsides, &triangles_tmp, &res); + collect_and_link_neighbours(scn, trgsides, &triangles_tmp, &frontiers, + &res); /* No barrier at the end of step 1: data used in step 1 cannot be * released / data produced by step 1 cannot be used * until next sync point */ @@ -1271,7 +1285,7 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) } /* No barrier here */ /* Step 4: Build result */ - build_result(desc, &connex_components, &triangles_comp, &res); + build_result(desc, &connex_components, &triangles_comp, &frontiers, &res); /* No barrier at the end of step 4: data used in step 4 cannot be * released / data produced by step 4 cannot be used * until next sync point */ @@ -1312,6 +1326,8 @@ exit: if(s3d_view) S3D(scene_view_ref_put(s3d_view)); if(triangles_tmp_initialized) darray_triangle_tmp_release(&triangles_tmp); if(triangles_comp_initialized) darray_triangle_comp_release(&triangles_comp); + if(frontiers_initialized) + darray_frontier_edge_release(&frontiers); if(trgsides) MEM_RM(scn->dev->allocator, trgsides); if(desc) *out_desc = desc; diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h @@ -18,66 +18,12 @@ #include "senc_scene_c.h" #include "senc_internal_types.h" +#include "senc_descriptor_c.h" #include <rsys/mem_allocator.h> #include <rsys/hash_table.h> #include <rsys/double3.h> -/* Triangle edge struct and basic functions */ -struct trg_edge { - vrtx_id_t vrtx0, vrtx1; -}; - -static FINLINE int -edge_ok(const struct trg_edge* edge) { - return(edge - && edge->vrtx0 <= VRTX_MAX__ - && edge->vrtx1 <= VRTX_MAX__ - && edge->vrtx0 < edge->vrtx1); -} - -static FINLINE void -set_edge - (const vrtx_id_t vrtx0, - const vrtx_id_t vrtx1, - struct trg_edge* edge, - unsigned char* reversed) -{ - ASSERT(edge && reversed && vrtx0 != vrtx1); - ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */ - if(vrtx0 < vrtx1) { - edge->vrtx0 = vrtx0; - edge->vrtx1 = vrtx1; - *reversed = 0; /* Non reversed edge */ - } else { - edge->vrtx0 = vrtx1; - edge->vrtx1 = vrtx0; - *reversed = 1; /* Reversed edge */ - } - ASSERT(edge_ok(edge)); -} - -static FINLINE int -edge_eq(const struct trg_edge* e1, const struct trg_edge* e2) -{ - ASSERT(edge_ok(e1) && edge_ok(e2)); - return e1->vrtx0 == e2->vrtx0 && e1->vrtx1 == e2->vrtx1; -} - -/* Information kept during the building of side groups. */ -struct trgside { - /* Rank of the trgside facing this trgside through its edges */ - side_id_t facing_side_id[3]; - /* Id of this trgside's medium */ - medium_id_t medium; - - /* Implicit information that we don't need to store: - * - triangle_id - * - side - * This is due to the memory layout of the elt darray: - * front(trg_0), back(trg_0), front(trg_1), back(trg_1), ... */ -}; - static FINLINE void init_trgside(struct mem_allocator* alloc, struct trgside* data) { diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c @@ -188,10 +188,38 @@ main(int argc, char** argv) nvertices, get_position, &ctx) == RES_BAD_ARG); CHK(senc_scene_ref_put(scn) == RES_OK); - CHK(senc_device_ref_put(dev) == RES_OK); if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); + desc = NULL; CHK(senc_enclosure_ref_put(enc) == RES_OK); + /* Same cube with a hole (last triangle is missing) */ + CHK(senc_scene_create(dev, + SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) + == RES_OK); + + CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media, + NULL, nvertices, get_position, &ctx) == RES_OK); + + CHK(senc_scene_analyze(scn, &desc) == RES_OK); + + CHK(senc_descriptor_get_frontier_segments_count(NULL, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segments_count(desc, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segments_count(NULL, &count) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segments_count(desc, &count) == RES_OK); + + CHK(senc_descriptor_get_frontier_segment(NULL, count, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(desc, count, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(NULL, 0, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(NULL, count, indices) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(desc, 0, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(desc, count, indices) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(NULL, 0, indices) == RES_BAD_ARG); + CHK(senc_descriptor_get_frontier_segment(desc, 0, indices) == RES_OK); + + CHK(senc_scene_ref_put(scn) == RES_OK); + CHK(senc_device_ref_put(dev) == RES_OK); + if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); + check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHK(mem_allocated_size() == 0);