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 d8f9b28fbbd7a20a3f231db809b3dc8fa5ae595e
parent 9c87673427c85a3940eb8cdaba15d0eb67b11956
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Sun, 28 Apr 2019 11:56:51 +0200

Merge branch 'release_0.3.1'

Diffstat:
MREADME.md | 8+++++++-
Mcmake/CMakeLists.txt | 2+-
Msrc/senc_descriptor.c | 4++--
Msrc/senc_descriptor_c.h | 5++---
Msrc/senc_device.c | 11+++++++++++
Msrc/senc_device_c.h | 12++++++++++++
Msrc/senc_internal_types.h | 5+++++
Msrc/senc_scene_analyze.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
8 files changed, 112 insertions(+), 22 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.1 + +- Performance Fix: when a connex component was canceled by a thread the + complexity was O(n^2). New algorithm is O(n). +- Output execution time for analysis steps in the log. + ### Version 0.3 - Add API calls to access to geometry frontiers. @@ -65,7 +71,7 @@ Release notes License ------- -StarEnclosures is Copyright (C) \\\|Meso\\\|Star&gt; 2018 +StarEnclosures is Copyright (C) |Méso|Star> 2018 (<a href="mailto:contact@meso-star.com" class="email">contact@meso-star.com</a>). It is free software released under the GPLv3+ license. You are welcome to redistribute it under certain conditions; refer to the COPYING files diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -48,7 +48,7 @@ endif() ################################################################################ set(VERSION_MAJOR 0) set(VERSION_MINOR 3) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SENC_FILES_SRC diff --git a/src/senc_descriptor.c b/src/senc_descriptor.c @@ -282,7 +282,7 @@ senc_descriptor_get_frontier_segments_count unsigned* count) { size_t tmp; - if (!desc || !count) + if(!desc || !count) return RES_BAD_ARG; tmp = darray_frontier_edge_size_get(&desc->frontiers); ASSERT(tmp < UINT_MAX); @@ -297,7 +297,7 @@ senc_descriptor_get_frontier_segment unsigned vrtx_id[2]) { const struct trg_edge* edge; - if (!vrtx_id || !desc + 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; diff --git a/src/senc_descriptor_c.h b/src/senc_descriptor_c.h @@ -106,12 +106,11 @@ set_edge { ASSERT(edge && reversed && vrtx0 != vrtx1); ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */ - if (vrtx0 < vrtx1) { + if(vrtx0 < vrtx1) { edge->vrtx0 = vrtx0; edge->vrtx1 = vrtx1; *reversed = 0; /* Non reversed edge */ - } - else { + } else { edge->vrtx0 = vrtx1; edge->vrtx1 = vrtx0; *reversed = 1; /* Reversed edge */ diff --git a/src/senc_device.c b/src/senc_device.c @@ -73,6 +73,17 @@ log_warn(struct senc_device* dev, const char* msg, ...) va_end(vargs_list); } +void +log_info(struct senc_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_OUTPUT, msg, vargs_list); + va_end(vargs_list); +} + /******************************************************************************* * Exported functions ******************************************************************************/ diff --git a/src/senc_device_c.h b/src/senc_device_c.h @@ -56,4 +56,16 @@ log_warn #endif ; +/* Conditionally log a message on the LOG_OUTPUT stream of the device logger, + * with respect to the device verbose flag */ +extern LOCAL_SYM void +log_info + (struct senc_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + #endif /* SENC_DEVICE_C_H */ diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h @@ -123,6 +123,11 @@ TRGSIDE_2_SIDEFLAG(side_id_t s) { return (s & 1) ? FLAG_BACK : FLAG_FRONT; } +static FINLINE enum side_flag +SIDE_CANCELED_FLAG(enum side_flag f) { + return ((unsigned char)f) << 4; +} + static FINLINE side_id_t TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum side_id i) { ASSERT((((size_t)t << 1) | (i == SIDE_BACK)) < SIDE_MAX__); diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -26,6 +26,7 @@ #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> #include <rsys/dynamic_array_uchar.h> +#include <rsys/clock_time.h> #include <star/s3d.h> @@ -228,7 +229,7 @@ extract_connex_components vrtx_id_t max_z_vrtx_id = VRTX_NULL__; struct cc_descriptor *cc; double max_z = -DBL_MAX; - + component_canceled = 0; ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris); darray_side_id_clear(&current_component); @@ -310,22 +311,28 @@ extract_connex_components *trg_used |= (unsigned char)crt_side_flag; } - /* Store neighbour' sides in a waiting stack */ + /* Store neighbour's sides in a waiting stack */ FOR_EACH(i, 0, 3) { side_id_t neighbour_id = crt_side->facing_side_id[i]; trg_id_t nbour_trg_id = TRGSIDE_2_TRG(neighbour_id); enum side_flag nbour_side_id = TRGSIDE_2_SIDEFLAG(neighbour_id); unsigned char* nbour_used = processed + nbour_trg_id; const struct trgside* neighbour = trgsides + neighbour_id; - if(*nbour_used & nbour_side_id) continue; /* Already processed */ - if(neighbour->medium < m) { - /* Not the same medium. + if(neighbour->medium < m + || (*nbour_used & (unsigned char)SIDE_CANCELED_FLAG(nbour_side_id))) + { + /* 1) Not the same medium. * Neighbour's medium id is less than current medium: the whole * component is to be processed by another thread (possibly the one - * associated with neighbour's medium). */ + * associated with neighbour's medium). + * 2) Neighbour was canceled: no need to replay the component + * again as it will eventually rediscover the side with low medium + * id and recancel all the work in progress */ component_canceled = 1; darray_side_id_clear(&stack); - /* Reverse the used flag for sides in cancelled component */ + /* Don't cancel used flags as all these sides will get us back to + * (at least) the neighbour side we have just discovered, that will + * cancel them again and again */ sz = darray_side_id_size_get(&current_component); FOR_EACH(ii, 0, sz) { side_id_t used_side @@ -335,10 +342,14 @@ extract_connex_components = 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; + /* Set the used flag for sides in cancelled component as leading + * to further cancellations */ + *used |= (unsigned char)SIDE_CANCELED_FLAG(used_side_flag); } + goto canceled; } + if(*nbour_used & nbour_side_id) continue; /* Already processed */ /* Mark neighbour as processed and stack it */ *nbour_used |= (unsigned char)nbour_side_id; OK2(darray_side_id_push_back(&stack, &neighbour_id)); @@ -377,15 +388,17 @@ extract_connex_components current_media = NULL; /* Write component membership in the global structure - * No need for sync here as an unique thread write a given side */ + * No need for sync here as an unique thread writes a given side */ {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]; - ASSERT(triangles_comp[TRGSIDE_2_TRG(s)].component[TRGSIDE_2_SIDE(s)] - == COMPONENT_NULL__); - triangles_comp[TRGSIDE_2_TRG(s)].component[TRGSIDE_2_SIDE(s)] - = cc->cc_id; + trg_id_t tid = TRGSIDE_2_TRG(s); + enum side_id sid = TRGSIDE_2_SIDE(s); + component_id_t* cmp = triangles_comp[tid].component; + ASSERT(cmp[sid] == COMPONENT_NULL__); + ASSERT(trgsides[s].medium >= m); + cmp[sid] = cc->cc_id; } /* Compute the normal at the max_z vertex. */ @@ -404,7 +417,7 @@ extract_connex_components darray_position_cdata_get(&scn->vertices); double edge0[3], edge1[3], normal[3], norm; - /* To garanty that triangles with 2 sides in the component total to 0 + /* To ensure 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); (void)s; @@ -1157,9 +1170,11 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) /* Atomic counters to share beetwen threads */ ATOMIC component_count = 0; ATOMIC next_enclosure_id = 1; + char dump[64]; + struct time t0, t1; res_T res = RES_OK; res_T res2 = RES_OK; - + if(!scn || !out_desc) return RES_BAD_ARG; desc = descriptor_create(scn); @@ -1170,6 +1185,11 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) if(!scn->nutris) goto exit; +#pragma omp single nowait + if(scn->dev->verbose) { + time_current(&t0); + } + darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp); triangles_tmp_initialized = 1; darray_frontier_edge_init(scn->dev->allocator, &frontiers); @@ -1234,6 +1254,15 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) goto error_; } + #pragma omp single nowait + if(scn->dev->verbose) { + time_sub(&t1, time_current(&t1), &t0); + time_current(&t0); + time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); + log_info(scn->dev, + "senc_scene_analyze: collect_and_link_neighbours step in %s\n", dump); + } + /* Step 2: extract triangle connex components */ extract_connex_components(desc, trgsides, &connex_components, &triangles_tmp, &triangles_comp, &s3d_view, &component_count, &res); @@ -1261,6 +1290,15 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) triangles_tmp_initialized = 0; } /* No barrier here */ + #pragma omp single nowait + if(scn->dev->verbose) { + time_sub(&t1, time_current(&t1), &t0); + time_current(&t0); + time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); + log_info(scn->dev, + "senc_scene_analyze: extract_connex_components step in %s\n", dump); + } + /* Step 3: group components */ group_connex_components(desc, trgsides, &triangles_comp, &connex_components, s3d_view, &next_enclosure_id, &res); @@ -1284,6 +1322,15 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) s3d_view = NULL; } /* No barrier here */ + #pragma omp single nowait + if(scn->dev->verbose) { + time_sub(&t1, time_current(&t1), &t0); + time_current(&t0); + time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); + log_info(scn->dev, + "senc_scene_analyze: group_connex_components step in %s\n", dump); + } + /* Step 4: Build result */ build_result(desc, &connex_components, &triangles_comp, &frontiers, &res); /* No barrier at the end of step 4: data used in step 4 cannot be @@ -1315,6 +1362,16 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) triangles_comp_initialized = 0; } } /* No barrier here */ + + #pragma omp single nowait + if(scn->dev->verbose) { + time_sub(&t1, time_current(&t1), &t0); + time_current(&t0); + time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); + log_info(scn->dev, + "senc_scene_analyze: build_result step in %s\n", dump); + } + error_: ; } /* Implicit barrier here */