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 9c87673427c85a3940eb8cdaba15d0eb67b11956
parent 29812324a77e30c230a35f68b3ab7221d487affa
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue, 12 Mar 2019 15:43:36 +0100

Merge branch 'release_0.3.0'

Diffstat:
MREADME.md | 6++++++
Mcmake/CMakeLists.txt | 4++--
Msrc/senc.h | 67++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/senc_descriptor.c | 32++++++++++++++++++++++++++++++++
Msrc/senc_descriptor_c.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/senc_enclosure_data.h | 2+-
Msrc/senc_scene_analyze.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/senc_scene_analyze_c.h | 59++++++-----------------------------------------------------
Msrc/test_senc_descriptor.c | 41++++++++++++++++++++++++++++++++++++++++-
Msrc/test_senc_scene.c | 2+-
10 files changed, 280 insertions(+), 83 deletions(-)

diff --git a/README.md b/README.md @@ -39,6 +39,12 @@ variable the install directories of its dependencies. Release notes ------------- +### Version 0.3 + +- Add API calls to access to geometry frontiers. +- Improve documentation in the header file. +- BugFix: wrong data cleaning on computation canceling. + ### Version 0.2.2 - BugFix when grouping components into enclosures. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -47,8 +47,8 @@ endif() # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 2) -set(VERSION_PATCH 2) +set(VERSION_MINOR 3) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SENC_FILES_SRC diff --git a/src/senc.h b/src/senc.h @@ -144,6 +144,7 @@ senc_device_ref_put * StarEnclosures scene. A scene is a collection of triangles. Each triangle is * defined with a medium on each side. ******************************************************************************/ +/* Creates an empty scene */ SENC_API res_T senc_scene_create (struct senc_device* device, @@ -155,7 +156,8 @@ senc_scene_create * Triangles can be duplicates as long as they constantly define the same * medium on both sides (or an error will be reported) and are deduplicated. * When deduplicating triangles, the first occurence is kept (with it original - * global_id). */ + * global_id). Users can provide their own global ids for triangles; these ids + * are not used by the library but are returned as-is by some API calls. */ SENC_API res_T senc_scene_add_geometry (struct senc_scene* scene, @@ -168,31 +170,39 @@ senc_scene_add_geometry void(*position)(const unsigned ivert, double pos[3], void* context), void* context); +/* Returns a descriptor of the scene that holds the analysis' result. */ SENC_API res_T senc_scene_analyze (struct senc_scene* scene, struct senc_descriptor** descriptor); +/* Returns the convention flags in use with the scene. */ SENC_API res_T senc_scene_get_convention (const struct senc_scene* scene, enum senc_convention* convention); +/* Returns the number of triangles in the scene. */ SENC_API res_T senc_scene_get_triangles_count (const struct senc_scene* scene, unsigned* count); +/* Returns the number of unique triangles in the scene (remaining + * triangles after deduplication). */ SENC_API res_T senc_scene_get_unique_triangles_count (const struct senc_scene* scene, unsigned* count); +/* Returns the number of vertices in the scene. */ SENC_API res_T senc_scene_get_vertices_count (const struct senc_scene* scene, unsigned* count); +/* Returns the number of unique vertices in the scene (remaining + * vertices after deduplication). */ SENC_API res_T senc_scene_get_unique_vertices_count (const struct senc_scene* scene, @@ -209,28 +219,36 @@ senc_scene_ref_put /******************************************************************************* * StarEnclosures descriptor. It is an handle toward an analyze result. ******************************************************************************/ +/* Returns the greater medium id found in added geometry. In API calls using a + * medium, any value in the [0 max_medium_id[ range is valid. However there can + * be unused ids (no geometry refered to this medium id). */ SENC_API res_T senc_descriptor_get_max_medium (const struct senc_descriptor* descriptor, unsigned* max_medium_id); +/* Returns the number of enclosures. */ SENC_API res_T senc_descriptor_get_enclosure_count (const struct senc_descriptor* descriptor, unsigned* count); +/* Returns the number of enclosures that have some geometry refering to the + * imed_th medium. */ SENC_API res_T senc_descriptor_get_enclosure_count_by_medium (const struct senc_descriptor* descriptor, - const unsigned imed, /* Must be in [0 max_medium_id] */ + const unsigned imed, unsigned* count); +/* Returns the idx_th enclosure. */ SENC_API res_T senc_descriptor_get_enclosure (struct senc_descriptor* descriptor, const unsigned idx, struct senc_enclosure** enclosure); +/* Returns the idx_th enclosure using the imed_th medium. */ SENC_API res_T senc_descriptor_get_enclosure_by_medium (struct senc_descriptor* descriptor, @@ -238,46 +256,75 @@ senc_descriptor_get_enclosure_by_medium const unsigned idx, struct senc_enclosure** enclosure); +/* Returns the number of unique triangles (no duplicates here) in the whole + * geometry. */ SENC_API res_T senc_descriptor_get_global_triangles_count (const struct senc_descriptor* descriptor, - unsigned* count); /* Number of unique triangles. */ + unsigned* count); +/* Returns the number of unique vertices (no duplicates here) in the whole + * geometry. */ SENC_API res_T senc_descriptor_get_global_vertices_count (const struct senc_descriptor* descriptor, unsigned* count); /* Number of unique vertices. */ +/* Returns the itri_th global unique triangles; the returned indices are global + * unique vertex indices. */ SENC_API res_T senc_descriptor_get_global_triangle (const struct senc_descriptor* descriptor, const unsigned itri, unsigned indices[3]); +/* Returns the coordinates of the ivert_th global unique vertex. */ SENC_API res_T senc_descriptor_get_global_vertex (const struct senc_descriptor* descriptor, const unsigned ivert, double coord[3]); +/* Returns the front and back media ids of the itri_th global unique + * triangles. */ SENC_API res_T senc_descriptor_get_global_triangle_media (const struct senc_descriptor* descriptor, const unsigned itri, unsigned media[2]); +/* Returns the enclosures the itri_th global unique triangles front and back + * sides are member of. */ SENC_API res_T senc_descriptor_get_global_triangle_enclosures (const struct senc_descriptor* descriptor, const unsigned itri, unsigned enclosures[2]); +/* Returns the global id of the itri_th global unique triangles, either the + * user provided one or the default one. */ SENC_API res_T senc_descriptor_get_global_triangle_global_id (const struct senc_descriptor* descriptor, const unsigned itri, unsigned* gid); +/* Returns the number of segments that are frontier segments: + * - that have arity 1 (single triangle using the segment) + * - that connect 2 different media */ +SENC_API res_T +senc_descriptor_get_frontier_segments_count + (const struct senc_descriptor* descriptor, + unsigned* count); + +/* Returns the iseg_th frontier segment; the returned indices are global unique + * vertex indices. */ +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); @@ -293,39 +340,49 @@ senc_descriptor_ref_put * An enclosure can list the "same" triangle twice if both sides are in. In this * case the 2 occurences of the triangle have reversed vertices order and * unique_triangle_count and triangle_count differ. + * Vertices and triangles numbering schemes are specific to each enclosure: + * the "same" item appearing in 2 different enclosures has no reason to get the + * same index twice or to have the same index in the global numbering scheme. * By-index API accesses of triangles (or properties) visit unique triangles - * for indexes in the [0 unique_triangle_count[ range and back-faces of the - * doubly-listed triangles in the [unique_triangle_count triangle_count[ range. + * for indices in the [0 unique_triangle_count[ range and back-faces of the + * doubly-included triangles in the [unique_triangle_count triangle_count[ range. ******************************************************************************/ +/* Returns the header of an enclosure. */ SENC_API res_T senc_enclosure_get_header (const struct senc_enclosure* enclosure, struct senc_enclosure_header* header); +/* Returns the itri_th triangle of an enclosure. */ SENC_API res_T senc_enclosure_get_triangle (const struct senc_enclosure* enclosure, const unsigned itri, unsigned indices[3]); +/* Returns the coordinates of the ivert_th vertex of an enclosure. */ SENC_API res_T senc_enclosure_get_vertex (const struct senc_enclosure* enclosure, const unsigned ivert, double coord[3]); +/* Returns the front and back side media ids of the itri_th triangle of an + * enclosure. */ SENC_API res_T senc_enclosure_get_triangle_media (const struct senc_enclosure* enclosure, const unsigned itri, unsigned medium[2]); +/* Returns the global id of the itri_th triangle of an enclosure. */ SENC_API res_T senc_enclosure_get_triangle_global_id (const struct senc_enclosure* enclosure, const unsigned itri, unsigned* gid); +/* Returns the id of the imed_th medium of an enclosure. */ SENC_API res_T senc_enclosure_get_medium (const struct senc_enclosure* enclosure, 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" @@ -143,7 +142,7 @@ extract_connex_components struct s3d_scene_view** s3d_view, ATOMIC* component_count, /* Shared error status. - * We accept to overwritte an error with a different error */ + * We accept to overwrite an error with a different error */ res_T* p_res) { /* This function is called from an omp parallel block and executed @@ -326,6 +325,18 @@ extract_connex_components * associated with neighbour's medium). */ component_canceled = 1; darray_side_id_clear(&stack); + /* Reverse the used flag for sides in cancelled component */ + sz = darray_side_id_size_get(&current_component); + FOR_EACH(ii, 0, sz) { + side_id_t used_side + = darray_side_id_cdata_get(&current_component)[ii]; + trg_id_t used_trg_id = TRGSIDE_2_TRG(used_side); + enum side_flag used_side_flag + = TRGSIDE_2_SIDEFLAG(used_side); + unsigned char* used = processed + used_trg_id; + ASSERT(*used & (unsigned char)used_side_flag); + *used &= 0xFF ^ (unsigned char)used_side_flag; + } goto canceled; } /* Mark neighbour as processed and stack it */ @@ -367,7 +378,7 @@ extract_connex_components /* Write component membership in the global structure * No need for sync here as an unique thread write a given side */ - STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free); + {STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free);} ASSERT(IS_ALIGNED(triangles_comp->component, sizeof(cc->cc_id))); FOR_EACH(ii, 0, sz) { const side_id_t s = darray_side_id_cdata_get(&current_component)[ii]; @@ -380,6 +391,7 @@ extract_connex_components /* Compute the normal at the max_z vertex. */ max_nz = 0; sz = darray_side_id_size_get(&ids_of_sides_around_max_z_vertex); + ASSERT(sz > 0); FOR_EACH(ii, 0, sz) { const side_id_t side_id = darray_side_id_cdata_get(&ids_of_sides_around_max_z_vertex)[ii]; @@ -395,7 +407,7 @@ extract_connex_components /* To garanty that triangles 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 == x can be false). */ - ASSERT(trg_comp->component[s] == cc->cc_id); + ASSERT(trg_comp->component[s] == cc->cc_id); (void)s; if(trg_comp->component[SIDE_FRONT] == trg_comp->component[SIDE_BACK]) continue; @@ -524,7 +536,7 @@ group_connex_components struct s3d_scene_view* s3d_view, ATOMIC* next_enclosure_id, /* Shared error status. - * We accept to overwritte an error with a different error */ + * We accept to overwrite an error with a different error */ res_T* res) { /* This function is called from an omp parallel block and executed @@ -595,8 +607,9 @@ group_connex_components enum side_id hit_side = ((hit.normal[2] < 0) /* Facing geometrical normal of hit */ == ((desc->scene->convention & SENC_CONVENTION_NORMAL_FRONT) != 0)) - /* Warning: Embree 2 convention for geometrical normals is - * left-handed and star-enclosure uses right-handed convention */ + /* Warning: following Embree 2 convention for geometrical normals, + * the Star3D hit normal is left-handed while star-enclosure uses + * right-handed convention */ ? SIDE_BACK : SIDE_FRONT; ASSERT(hit.normal[2] != 0); ASSERT(hit_trg_id < desc->scene->nutris); @@ -659,8 +672,9 @@ 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 overwritte an error with a different error */ + * We accept to overwrite an error with a different error */ res_T* res) { /* This function is called from an omp parallel block and executed @@ -684,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); @@ -769,7 +783,7 @@ collect_and_link_neighbours struct darray_neighbour* neighbour_list = &neighbourhood->neighbours; side_id_t i, neighbour_count; sz = darray_neighbour_size_get(neighbour_list); - ASSERT(sz <= SIDE_MAX__); + ASSERT(sz > 0 && sz <= SIDE_MAX__); neighbour_count = (side_id_t)sz; ASSERT(neighbour_count); v0 = neighbourhood->edge.vrtx0; @@ -866,16 +880,23 @@ collect_and_link_neighbours previous = darray_neighbour_cdata_get(neighbour_list) + i - 1; prev_id = previous->trg_id; log_err(scn->dev, - "%s: found 2 overlying triangles (%u & %u).\n", - FUNC_NAME, prev_id, crt_id); + "%s: found 2 overlying triangles (%lu & %lu).\n", FUNC_NAME, + (unsigned long)triangles_in[crt_id].global_id, + (unsigned long)triangles_in[prev_id].global_id); tmp_res = RES_BAD_OP; goto tmp_error; } a = current->angle; /* Link sides */ + ASSERT(p_crt_side->facing_side_id[crt_edge] == SIDE_NULL__); + ASSERT(p_ccw_side->facing_side_id[ccw_edge] == SIDE_NULL__); p_crt_side->facing_side_id[crt_edge] = ccw_side_idx; p_ccw_side->facing_side_id[ccw_edge] = crt_side_idx; /* Record media */ + ASSERT(p_crt_side->medium == MEDIUM_NULL__ + || p_crt_side->medium == triangles_in[crt_id].medium[crt_side]); + ASSERT(p_ccw_side->medium == MEDIUM_NULL__ + || p_ccw_side->medium == triangles_in[ccw_id].medium[ccw_side]); p_crt_side->medium = triangles_in[crt_id].medium[crt_side]; p_ccw_side->medium = triangles_in[ccw_id].medium[ccw_side]; ASSERT(p_crt_side->medium < scn->nmeds); @@ -885,10 +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 %u.\n", - FUNC_NAME, crt_id); + "%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); } } } @@ -904,8 +930,9 @@ 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 overwritte an error with a different error */ + * We accept to overwrite an error with a different error */ res_T* res) { /* This function is called from an omp parallel block and executed @@ -922,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; @@ -930,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); @@ -949,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]; @@ -1097,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 */ } /******************************************************************************* @@ -1113,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; @@ -1137,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 @@ -1145,13 +1182,22 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) res = RES_MEM_ERR; goto error; } +#ifndef NDEBUG + else { + /* Initialise trgsides to allow assert code */ + size_t i; + FOR_EACH(i, 0, 2 * scn->nutris) + init_trgside(scn->dev->allocator, trgsides + i); + } +#endif /* The end of the analyze is multithreaded */ ASSERT(scn->dev->nthreads > 0); #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 */ @@ -1239,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 */ @@ -1280,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,68 +18,21 @@ #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) +init_trgside(struct mem_allocator* alloc, struct trgside* data) { - 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; + int i; + ASSERT(data); (void)alloc; + FOR_EACH(i, 0, 3) data->facing_side_id[i] = SIDE_NULL__; + data->medium = MEDIUM_NULL__; } -/* 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; - /* The list containing the trgside; made of enum list_id flags */ - unsigned char list_id; - - /* 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 side_id #define DARRAY_DATA side_id_t #include <rsys/dynamic_array.h> diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c @@ -164,6 +164,17 @@ main(int argc, char** argv) CHK(enclosures[0] == 0 && enclosures[1] == 1); + CHK(senc_descriptor_get_global_triangle_global_id(NULL, 0, indices) + == RES_BAD_ARG); + CHK(senc_descriptor_get_global_triangle_global_id(NULL, nvertices, indices) + == RES_BAD_ARG); + CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, NULL) + == RES_BAD_ARG); + CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, indices) + == RES_OK); + /* No duplicates and no custom id: user id is unique vertex id */ + CHK(indices[0] == 0); + /* Add valid duplicate geometry */ CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; @@ -188,10 +199,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); diff --git a/src/test_senc_scene.c b/src/test_senc_scene.c @@ -206,7 +206,7 @@ main(int argc, char** argv) CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, nvertices, get_position, &ctx) == RES_BAD_ARG); - /* It is OK dd geometry after a failed add */ + /* It is OK add geometry after a failed add */ ctx.back_media = medium1; CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, nvertices, get_position, &ctx) == RES_OK);