commit 0b0766b91d8d4168795e7ee4776ab76fd96cfec4
parent 884625a61c4bd617f5e4ac38685c987cbcd2efac
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 25 Sep 2020 14:09:02 +0200
Merge branch 'release_0.5.2'
Diffstat:
4 files changed, 140 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
@@ -6,11 +6,11 @@ geometry. An enclosure is a set of segments enclosing a given area. The
enclosure notion extends to open enclosures for which there is no inside
or outside. For every detected enclosure, the library provides the set
of involved segment sides as well as the set of involved media and a few
-metrics (number of segments, ...).
+metrics (number of segments, volume, area, ...).
-The library allows geometry to be added by subsets of segments and
-manages vertices and segments duplicates as long as the duplicate
-information is coherent, easing the scene definition process.
+From release 0.5, the geometry has to be provided at once, with no
+duplicates nor zero-length segments. To help ensuring this constraints,
+one can rely on the star-geometry-2d library.
Also the convention regarding FRONT/BACK sides for input segments as
well as the convention regarding normals' orientation for output
@@ -26,7 +26,7 @@ depends on the [RSys](https://gitlab.com/vaplv/rsys/) and
one more library is needed to build tests
([Star-SP](https://gitlab.com/meso-star/star-sp/)).
-First ensure that CMake and a C compiler that implements the OpenMP 2.0
+First ensure that CMake and a C compiler that implements the OpenMP 2.0 API
are installed on your system. Then install the RCMake package as well as
all the aforementioned prerequisites. Finally generate the project from
the `cmake/CMakeLists.txt` file by appending to the `CMAKE_PREFIX_PATH`
@@ -42,18 +42,27 @@ in star-enclosures-3d but is still present in star-enclosures-2d.
Release notes
-------------
+### Version 0.5.2
+
+- BugFix: enclosures including multiple media could end with invalid
+ primitive count.
+
### Version 0.5.1
- Fix a warning
### Version 0.5
+This release breaks the API as geometry cannot be provided through calls
+to an add-like call anymore. Instead the whole geometry must be provided
+at once, with no duplicates (either vertices or segments) nor zero-area
+segments.
+
- Compute volume (in m^2) and surface (in m) of enclosures.
- Report overlapping segments.
Only segments with a common vertex are currently detected.
- Do not extract enclosures anymore when overlapping segments are
- detected.
+ Do not extract enclosures when overlapping segments are detected.
- Make enclosure IDs consistent across runs.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -64,7 +64,7 @@ endif()
################################################################################
set(VERSION_MAJOR 0)
set(VERSION_MINOR 5)
-set(VERSION_PATCH 1)
+set(VERSION_PATCH 2)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SENC2D_FILES_SRC
@@ -155,6 +155,7 @@ if(NOT NO_TEST)
new_test(test_senc2d_enclosure)
new_test(test_senc2d_inconsistant_square)
new_test(test_senc2d_invalid_scenes)
+ new_test(test_senc2d_multi_media)
new_test(test_senc2d_sample_enclosure)
new_test(test_senc2d_scene)
new_test(test_senc2d_some_enclosures)
diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c
@@ -215,6 +215,8 @@ extract_connex_components
side_id_t max_ny_side_id;
const side_id_t last_side = media_use->last;
int component_canceled = 0, max_y_is_2sided = 0, fst_ny = 1;
+ side_id_t cc_start_side_id = SIDE_NULL__;
+ side_id_t cc_last_side_id = SIDE_NULL__;
res_T tmp_res = RES_OK;
ATOMIC id;
@@ -225,25 +227,30 @@ extract_connex_components
ASSERT(darray_side_id_size_get(&stack) == 0);
ASSERT(darray_side_id_size_get(¤t_component) == 0);
for(;;) { /* Process all components for this medium */
- const side_id_t start_side_id = get_side_not_in_connex_component
+ side_id_t crt_side_id = get_side_not_in_connex_component
(last_side, segsides, processed, &first_side_not_in_component, medium);
- side_id_t crt_side_id = start_side_id;
- side_id_t last_side_id = start_side_id;
vrtx_id_t max_y_vrtx_id = VRTX_NULL__;
struct cc_descriptor *cc;
double max_y = -DBL_MAX;
component_canceled = 0;
- ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nsegs);
+ ASSERT(crt_side_id == SIDE_NULL__ || crt_side_id < 2 * scn->nsegs);
darray_side_id_clear(¤t_component);
if(*p_res != RES_OK) break;
- if(start_side_id == SIDE_NULL__)
+ if(crt_side_id == SIDE_NULL__)
break; /* start_side_id=SIDE_NULL__ => component done! */
+ if(cc_start_side_id == SIDE_NULL__) {
+ cc_start_side_id = cc_last_side_id = crt_side_id;
+ } else {
+ cc_start_side_id = MMIN(cc_start_side_id, crt_side_id);
+ cc_last_side_id = MMAX(cc_last_side_id, crt_side_id);
+ }
+
#ifndef NDEBUG
{
- seg_id_t sid = SEGSIDE_2_SEG(start_side_id);
- enum senc2d_side s = SEGSIDE_2_SIDE(start_side_id);
+ seg_id_t sid = SEGSIDE_2_SEG(crt_side_id);
+ enum senc2d_side s = SEGSIDE_2_SIDE(crt_side_id);
medium_id_t side_med
= darray_segment_in_data_get(&scn->segments_in)[sid].medium[s];
ASSERT(side_med == medium);
@@ -351,7 +358,8 @@ extract_connex_components
if(sz == 0) break; /* Empty stack => component is done! */
crt_side_id = darray_side_id_cdata_get(&stack)[sz - 1];
darray_side_id_pop_back(&stack);
- last_side_id = MMAX(last_side_id, crt_side_id);
+ cc_start_side_id = MMIN(cc_start_side_id, crt_side_id);
+ cc_last_side_id = MMAX(cc_last_side_id, crt_side_id);
}
canceled:
if(component_canceled) continue;
@@ -361,7 +369,6 @@ extract_connex_components
if(!cc) *p_res = RES_MEM_ERR;
if(*p_res != RES_OK) break;
- ASSERT(medium == segsides[start_side_id].medium);
ASSERT(max_y_vrtx_id != VRTX_NULL__);
cc_descriptor_init(alloc, cc);
id = ATOMIC_INCR(component_count) - 1;
@@ -370,14 +377,18 @@ extract_connex_components
sz = darray_side_id_size_get(¤t_component);
ASSERT(sz > 0 && sz <= SIDE_MAX__);
cc->side_count = (side_id_t)sz;
- cc->side_range.first = start_side_id;
- cc->side_range.last = last_side_id;
+ cc->side_range.first = cc_start_side_id;
+ cc->side_range.last = cc_last_side_id;
cc->max_y_vrtx_id = max_y_vrtx_id;
/* Tranfer ownership of the array to component */
ASSERT(!cc->media && current_media);
cc->media = current_media;
current_media = NULL;
+ /* Reset for next component */
+ cc_start_side_id = SIDE_NULL__;
+ cc_last_side_id = SIDE_NULL__;
+
/* Write component membership in the global structure
* 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);}
diff --git a/src/test_senc2d_multi_media.c b/src/test_senc2d_multi_media.c
@@ -0,0 +1,100 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_cube_on_cube. */
+
+#define _POSIX_C_SOURCE 200112L /* snprintf */
+
+#include "senc2d.h"
+#include "test_senc2d_utils.h"
+
+#include <rsys/double2.h>
+
+#include <stdio.h>
+
+static const unsigned multi_media_vertices_count = 4;
+static const double multi_media_vertices[8] =
+{
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1
+};
+static const unsigned multi_media_segments_count = 4;
+static const unsigned multi_media_segments[8] =
+{
+ 0, 2,
+ 2, 3,
+ 3, 1,
+ 1, 0
+};
+static const unsigned multi_media_properties[12] =
+{
+ 0, 4, 4,
+ 0, 3, 3,
+ 0, 2, 2,
+ 0, 1, 1
+};
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc2d_device* dev = NULL;
+ struct senc2d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned ecount, scount, s, e;
+ struct senc2d_enclosure* enc;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc2d_device_create(NULL, &allocator, SENC2D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Degenerated triangle: duplicated vertex */
+ ctx.positions = multi_media_vertices;
+ ctx.indices = multi_media_segments;
+ ctx.properties = multi_media_properties;
+ OK(senc2d_scene_create(dev,
+ SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_INSIDE,
+ multi_media_segments_count, get_indices, get_media_from_properties,
+ multi_media_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc2d_scene_get_segments_count(scn, &scount));
+ CHK(scount == multi_media_segments_count);
+ FOR_EACH(s, 0, scount) {
+ unsigned ids[2];
+ OK(senc2d_scene_get_segment_enclosures(scn, s, ids));
+ CHK(ids[0] == 0 && ids[1] == 1);
+ }
+ OK(senc2d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 2);
+ FOR_EACH(e, 0, ecount) {
+ struct senc2d_enclosure_header header;
+ OK(senc2d_scene_get_enclosure(scn, e, &enc));
+ OK(senc2d_enclosure_get_header(enc, &header));
+ CHK(header.primitives_count == multi_media_segments_count);
+ CHK(header.enclosed_media_count == (header.is_infinite ? 1u : 4u));
+ OK(senc2d_enclosure_ref_put(enc));
+ }
+
+ OK(senc2d_scene_ref_put(scn));
+ OK(senc2d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}