commit 5efb3c7593d69e470471f977c7848a43ccf97c67
parent e549288a9cf508096ae610aaa89fa321cb82382e
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Sat, 4 Jul 2020 17:23:21 +0200
Add reporting of overlapping segments
When a scene includes overlapping segments, scene API calls related to enclosures now return RES_BAD_OP
Diffstat:
10 files changed, 315 insertions(+), 45 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -154,6 +154,7 @@ if(NOT NO_TEST)
new_test(test_senc2d_device)
new_test(test_senc2d_enclosure)
new_test(test_senc2d_inconsistant_square)
+ new_test(test_senc2d_invalid_scenes)
new_test(test_senc2d_sample_enclosure)
new_test(test_senc2d_scene)
new_test(test_senc2d_some_enclosures)
@@ -168,7 +169,6 @@ if(NOT NO_TEST)
rcmake_copy_runtime_libraries(test_senc2d_many_enclosures test_senc2d_utils2.h)
rcmake_copy_runtime_libraries(test_senc2d_many_segments test_senc2d_utils2.h)
-
rcmake_copy_runtime_libraries(test_senc2d_sample_enclosure)
if(HUGE_ADDITIONAL_TESTS)
diff --git a/src/senc2d.h b/src/senc2d.h
@@ -108,7 +108,7 @@ struct senc2d_enclosure_header {
* SENC2D_CONVENTION_NORMAL_FRONT => Ng points toward the front side,
* SENC2D_CONVENTION_NORMAL_BACK => Ng points toward the back side.
*
- * Additionaly the user can set the convention used to output enclosures
+ * Additionally the user can set the convention used to output enclosures
* so that Ng points toward the enclosure or on the opposite direction
* (for a closed enclosure Ng points toward the inside or toward the outside)
* by using the flags :
@@ -170,6 +170,8 @@ senc2d_device_ref_put
/******************************************************************************
* star-enclosures-2d scene. A scene is a collection of segments. Each segment
* is defined with a medium on each side.
+ * Scenes with overlapping segments are considered ill-formed and any
+ * enclosure-related API call on such a scene will return RES_BAD_OP.
*****************************************************************************/
/* Creates a scene from some vertices and segments.
* Neither vertices nor segments can include duplicates.
@@ -301,6 +303,25 @@ senc2d_scene_get_frontier_vertex
unsigned vrtx_id[SENC2D_GEOMETRY_DIMENSION-1],
unsigned* seg_id);
+/* Returns the number of overlapping segments.
+ * A model including overlapping segments cannot be split into enclosures
+ * unequivocally and will probably be ruled invalid by most softwares.
+ * As a consequence, one cannot query enclosure-related information on a model
+ * with overlapping segments.
+ * The library currently only detects overlapping segments that share a
+ * vertex. */
+SENC2D_API res_T
+senc2d_scene_get_overlapping_segments_count
+ (const struct senc2d_scene* scene,
+ unsigned* count);
+
+/* Returns the idx_th overlapping triangle id. */
+SENC2D_API res_T
+senc2d_scene_get_overlapping_segment
+ (const struct senc2d_scene* scene,
+ const unsigned idx,
+ unsigned* id);
+
SENC2D_API res_T
senc2d_scene_ref_get
(struct senc2d_scene* scene);
diff --git a/src/senc2d_descriptor.c b/src/senc2d_descriptor.c
@@ -29,6 +29,8 @@ senc2d_scene_get_max_medium
(const struct senc2d_scene* scn, medium_id_t* max_medium_id)
{
if(!scn || !max_medium_id) return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
*max_medium_id = scn->next_medium_idx - 1;
return RES_OK;
}
@@ -38,6 +40,8 @@ senc2d_scene_get_enclosure_count
(const struct senc2d_scene* scn, enclosure_id_t* count)
{
if(!scn || !count) return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
ASSERT(scn->analyze.enclosures_count ==
darray_enclosure_size_get(&scn->analyze.enclosures));
*count = scn->analyze.enclosures_count;
@@ -56,6 +60,8 @@ senc2d_scene_get_enclosure_count_by_medium
if(!scn || !count
|| (imed != SENC2D_UNSPECIFIED_MEDIUM && imed >= scn->next_medium_idx))
return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
ASSERT(darray_enc_ids_array_size_get(&scn->analyze.enc_ids_array_by_medium)
== 1 + scn->next_medium_idx);
m_idx = medium_id_2_medium_idx(imed);
@@ -74,8 +80,10 @@ senc2d_scene_get_enclosure
struct senc2d_enclosure** out_enc)
{
struct senc2d_enclosure* enc;
- if(!scn || idx >= darray_enclosure_size_get(&scn->analyze.enclosures)
- || !out_enc)
+ if(!scn || !out_enc) return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
+ if(idx >= darray_enclosure_size_get(&scn->analyze.enclosures))
return RES_BAD_ARG;
enc = enclosure_create(scn, idx);
if(!enc) return RES_MEM_ERR;
@@ -96,6 +104,8 @@ senc2d_scene_get_enclosure_by_medium
if(!scn || !out_enc
|| (imed != SENC2D_UNSPECIFIED_MEDIUM && imed >= scn->next_medium_idx))
return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
ASSERT(darray_enc_ids_array_size_get(&scn->analyze.enc_ids_array_by_medium)
== 1 + scn->next_medium_idx);
m_idx = medium_id_2_medium_idx(imed);
@@ -114,8 +124,10 @@ senc2d_scene_get_segment_enclosures
{
const struct segment_enc* seg;
int i;
- if(!enclosures || !scn
- || iseg >= darray_segment_enc_size_get(&scn->analyze.segments_enc))
+ if(!enclosures || !scn) return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
+ if(iseg >= darray_segment_enc_size_get(&scn->analyze.segments_enc))
return RES_BAD_ARG;
seg = darray_segment_enc_cdata_get(&scn->analyze.segments_enc) + iseg;
FOR_EACH(i, 0, 2) enclosures[i] = seg->enclosure[i];
@@ -130,6 +142,8 @@ senc2d_scene_get_frontier_vertice_count
size_t tmp;
if(!scn || !count)
return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
tmp = darray_frontier_vertex_size_get(&scn->analyze.frontiers);
ASSERT(tmp <= VRTX_MAX__);
*count = (vrtx_id_t)tmp; /* Back to API type */
@@ -147,8 +161,37 @@ senc2d_scene_get_frontier_vertex
if(!vrtx_id || !scn || !seg_id
|| iver >= darray_frontier_vertex_size_get(&scn->analyze.frontiers))
return RES_BAD_ARG;
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_OP;
vrtx = darray_frontier_vertex_cdata_get(&scn->analyze.frontiers) + iver;
*vrtx_id = vrtx->vrtx;
*seg_id = vrtx->seg;
return RES_OK;
}
+
+res_T
+senc2d_scene_get_overlapping_segments_count
+ (const struct senc2d_scene* scn,
+ vrtx_id_t* count)
+{
+ size_t tmp;
+ if(!scn || !count)
+ return RES_BAD_ARG;
+ tmp = darray_seg_id_size_get(&scn->analyze.overlapping_ids);
+ ASSERT(tmp <= VRTX_MAX__);
+ *count = (seg_id_t)tmp; /* Back to API type */
+ return RES_OK;
+}
+
+res_T
+senc2d_scene_get_overlapping_segment
+ (const struct senc2d_scene* scn,
+ const unsigned idx,
+ unsigned* trg_id)
+{
+ if(!scn || !trg_id
+ || idx >= darray_seg_id_size_get(&scn->analyze.overlapping_ids))
+ return RES_BAD_ARG;
+ *trg_id = darray_seg_id_cdata_get(&scn->analyze.overlapping_ids)[idx];
+ return RES_OK;
+}
diff --git a/src/senc2d_internal_types.h b/src/senc2d_internal_types.h
@@ -1,17 +1,17 @@
/* Copyright (C) |Meso|Star> 2018-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 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/>. */
#ifndef SENC2D_INTERNAL_TYPES_H
#define SENC2D_INTERNAL_TYPES_H
@@ -61,6 +61,14 @@ typedef unsigned seg_id_t;
#define SEG_MAX__ (UINT_MAX/2)
#define SEG_NULL__ UINT_MAX
#define PRTF_SEG "%u"
+static INLINE int
+cmp_seg_id
+ (const void* ptr1, const void* ptr2)
+{
+ const seg_id_t* t1 = ptr1;
+ const seg_id_t* t2 = ptr2;
+ return (int)(*t1) - (int)(*t2);
+}
/* Side IDs type use the same base type than Segment IDs */
typedef seg_id_t side_id_t;
diff --git a/src/senc2d_scene.c b/src/senc2d_scene.c
@@ -43,6 +43,7 @@ scene_release(ref_T * ref)
darray_enclosure_release(&scn->analyze.enclosures);
darray_enc_ids_array_release(&scn->analyze.enc_ids_array_by_medium);
darray_frontier_vertex_release(&scn->analyze.frontiers);
+ darray_seg_id_release(&scn->analyze.overlapping_ids);
MEM_RM(dev->allocator, scn);
SENC2D(device_ref_put(dev));
@@ -115,6 +116,7 @@ senc2d_scene_create
/* Enclosure 0 is always defined for infinite */
OK(darray_enclosure_resize(&scn->analyze.enclosures, 1));
scn->analyze.enclosures_count = 1;
+ darray_seg_id_init(scn->dev->allocator, &scn->analyze.overlapping_ids);
OK(darray_position_reserve(&scn->vertices, scn->nverts));
OK(darray_segment_in_reserve(&scn->segments_in, scn->nsegs));
diff --git a/src/senc2d_scene_analyze.c b/src/senc2d_scene_analyze.c
@@ -54,6 +54,11 @@ const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
#define DARRAY_DATA component_id_t
#include <rsys/dynamic_array.h>
+#define HTABLE_NAME overlap
+#define HTABLE_KEY seg_id_t
+#define HTABLE_DATA char
+#include <rsys/hash_table.h>
+
/******************************************************************************
* Helper function
*****************************************************************************/
@@ -715,6 +720,7 @@ collect_and_link_neighbours
struct segside* segsides,
struct darray_segment_tmp* segments_tmp_array,
struct darray_frontier_vertex* frontiers,
+ struct htable_overlap* overlaps,
/* Shared error status.
* We accept to overwrite an error with a different error */
res_T* res)
@@ -726,6 +732,7 @@ collect_and_link_neighbours
const union double2* vertices;
const int thread_count = omp_get_num_threads();
const int rank = omp_get_thread_num();
+ const int front = ((scn->convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0);
/* Array to keep neighbourhood of vertices
* Resize/Push operations on neighbourhood_by_vertex are valid in the
* openmp block because a given neighbourhood is only processed
@@ -826,36 +833,35 @@ collect_and_link_neighbours
/* Compute rotation angle around common vertex (in world system) */
d2_sub(disp, vertices[other_vrtx].vec, vertices[common_vrtx].vec);
ASSERT(disp[0] || disp[1]);
- neighbour_info->angle = atan2(disp[1], disp[0]);
+ neighbour_info->angle = atan2(disp[1], disp[0]); /* in ]-pi + pi]*/
if(is_reversed)
d2(n.vec, +disp[1], -disp[0]);
else
d2(n.vec, -disp[1], +disp[0]);
- if(neighbour_info->angle < 0) neighbour_info->angle += 2 * PI;
/* Normal orientation calculation. */
- if(neighbour_info->angle <= PI / 4) {
+ if(neighbour_info->angle > 3 * PI / 4) {
ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
- } else if(neighbour_info->angle <= 3 * PI / 4) {
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
+ } else if(neighbour_info->angle > PI / 4) {
ASSERT(n.pos.x);
neighbour_info->normal_toward_next_neighbour = (n.pos.x < 0);
- } else if(neighbour_info->angle <= 5 * PI / 4) {
+ } else if(neighbour_info->angle > -PI / 4) {
ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
- } else if(neighbour_info->angle <= 7 * PI / 4) {
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ } else if(neighbour_info->angle > -3 * PI / 4) {
ASSERT(n.pos.x);
neighbour_info->normal_toward_next_neighbour = (n.pos.x > 0);
} else {
ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
}
}
/* Sort segments by rotation angle */
qsort(darray_neighbour_data_get(neighbourhood), neighbour_count,
sizeof(struct neighbour_info), neighbour_cmp);
- /* Link sides.
- * Create cycles of sides by neighbourhood around common vertex. */
+ /* Link sides.
+ * Create cycles of sides by neighbourhood around common vertex. */
a = -DBL_MAX;
FOR_EACH(i, 0, neighbour_count) {
/* Neighbourhood info for current pair of segments */
@@ -873,12 +879,12 @@ collect_and_link_neighbours
const seg_id_t crt_id = current->seg_id;
const seg_id_t ccw_id = ccw_neighbour->seg_id;
/* Facing sides of segments */
- const int front = ((scn->convention & SENC2D_CONVENTION_NORMAL_FRONT) != 0);
const enum senc2d_side crt_side
- = current->normal_toward_next_neighbour == front ? SENC2D_FRONT : SENC2D_BACK;
+ = (current->normal_toward_next_neighbour == front)
+ ? SENC2D_FRONT : SENC2D_BACK;
const enum senc2d_side ccw_side
- = ccw_neighbour->normal_toward_next_neighbour == front ?
- SENC2D_BACK : SENC2D_FRONT;
+ = (ccw_neighbour->normal_toward_next_neighbour == front)
+ ? SENC2D_BACK : SENC2D_FRONT;
/* Index of sides in segsides */
const side_id_t crt_side_idx = SEGIDxSIDE_2_SEGSIDE(crt_id, crt_side);
const side_id_t ccw_side_idx = SEGIDxSIDE_2_SEGSIDE(ccw_id, ccw_side);
@@ -888,17 +894,19 @@ collect_and_link_neighbours
/* Check that angle is a discriminant property */
ASSERT(a <= current->angle); /* Is sorted */
if(a == current->angle) {
- /* Two consecutive segments with same angle! */
+ /* Two consecutive segments with same angle! Store them */
const struct neighbour_info* previous;
seg_id_t prev_id;
- ASSERT(i > 0);
previous = darray_neighbour_cdata_get(neighbourhood) + i - 1;
prev_id = previous->seg_id;
- log_err(scn->dev,
- LIB_NAME":%s: found 2 overlying segments ("PRTF_SEG" & "PRTF_SEG").\n",
- FUNC_NAME, crt_id, prev_id);
- tmp_res = RES_BAD_OP;
- goto tmp_error;
+ #pragma omp critical
+ {
+ char one = 1;
+ tmp_res = htable_overlap_set(overlaps, &crt_id, &one);
+ if(tmp_res == RES_OK)
+ tmp_res = htable_overlap_set(overlaps, &prev_id, &one);
+ }
+ if(tmp_res != RES_OK) goto tmp_error;
}
a = current->angle;
/* Link sides */
@@ -922,7 +930,7 @@ collect_and_link_neighbours
* - different media on its sides */
if(neighbour_count == 1
&& p_crt_side->medium != p_ccw_side->medium)
-#pragma omp critical
+ #pragma omp critical
{
struct frontier_vertex frontier_vertex;
frontier_vertex.seg = crt_id;
@@ -931,6 +939,7 @@ collect_and_link_neighbours
}
}
}
+
tmp_error:
if(tmp_res != RES_OK) *res = tmp_res;
/* Threads are allowed to return whitout sync. */
@@ -1194,6 +1203,9 @@ scene_analyze
/* Array of frontier vertices */
struct darray_frontier_vertex frontiers;
char frontiers_initialized = 0;
+ /* Htable used to store overlapping segments */
+ struct htable_overlap overlaps;
+ char overlaps_initialized = 0;
/* Store by-segment components */
struct darray_segment_comp segments_comp;
char segments_comp_initialized = 0;
@@ -1215,6 +1227,8 @@ scene_analyze
segments_tmp_initialized = 1;
darray_frontier_vertex_init(scn->dev->allocator, &frontiers);
frontiers_initialized = 1;
+ htable_overlap_init(scn->dev->allocator, &overlaps);
+ overlaps_initialized = 1;
OK(darray_segment_tmp_resize(&segments_tmp, scn->nsegs));
segsides
@@ -1238,7 +1252,7 @@ scene_analyze
{
/* Step 1: build neighbourhoods */
collect_and_link_neighbours(scn, segsides, &segments_tmp, &frontiers,
- &res);
+ &overlaps, &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 */
@@ -1262,6 +1276,38 @@ scene_analyze
}
/* Implicit barrier here: constraints on step 1 data are now met */
+ #pragma omp single
+ {
+ res_T tmp_res = RES_OK;
+ /* Save all the overlapping segments in a darray */
+ ASSERT(overlaps_initialized);
+ struct htable_overlap_iterator it, end;
+ htable_overlap_begin(&overlaps, &it);
+ htable_overlap_end(&overlaps, &end);
+ tmp_res = darray_seg_id_reserve(&scn->analyze.overlapping_ids,
+ htable_overlap_size_get(&overlaps));
+ if(tmp_res != RES_OK) goto tmp_error2;
+ while (!htable_overlap_iterator_eq(&it, &end)) {
+ tmp_res = darray_seg_id_push_back(&scn->analyze.overlapping_ids,
+ htable_overlap_iterator_key_get(&it));
+ if(tmp_res != RES_OK) goto tmp_error2;
+ htable_overlap_iterator_next(&it);
+ }
+ qsort(darray_seg_id_data_get(&scn->analyze.overlapping_ids),
+ darray_seg_id_size_get(&scn->analyze.overlapping_ids),
+ sizeof(*darray_seg_id_cdata_get(&scn->analyze.overlapping_ids)),
+ cmp_seg_id);
+ htable_overlap_release(&overlaps);
+ overlaps_initialized = 0;
+ tmp_error2:
+ if (tmp_res != RES_OK) res2 = tmp_res;
+ }
+
+ if(darray_seg_id_size_get(&scn->analyze.overlapping_ids)) {
+ /* Stop analysis here as the model is ill-formed */
+ goto end_;
+ }
+
if(res != RES_OK || res2 != RES_OK) {
#pragma omp single nowait
{
@@ -1366,6 +1412,7 @@ scene_analyze
}
} /* No barrier here */
+end_:
error_:
;
} /* Implicit barrier here */
@@ -1377,8 +1424,8 @@ exit:
if(s2d_view) S2D(scene_view_ref_put(s2d_view));
if(segments_tmp_initialized) darray_segment_tmp_release(&segments_tmp);
if(segments_comp_initialized) darray_segment_comp_release(&segments_comp);
- if(frontiers_initialized)
- darray_frontier_vertex_release(&frontiers);
+ if(frontiers_initialized) darray_frontier_vertex_release(&frontiers);
+ if(overlaps_initialized) htable_overlap_release(&overlaps);
if(segsides) MEM_RM(scn->dev->allocator, segsides);
return res;
diff --git a/src/senc2d_scene_c.h b/src/senc2d_scene_c.h
@@ -217,6 +217,10 @@ seg_key_eq(const union vrtx_id2* k1, const union vrtx_id2* k2)
#define HTABLE_KEY_FUNCTOR_EQ seg_key_eq
#include <rsys/hash_table.h>
+#define DARRAY_NAME seg_id
+#define DARRAY_DATA seg_id_t
+#include <rsys/dynamic_array.h>
+
struct descriptor {
enclosure_id_t enclosures_count;
/* Store by-segment enclosures */
@@ -226,6 +230,8 @@ struct descriptor {
struct darray_enc_ids_array enc_ids_array_by_medium;
/* Store frontiers */
struct darray_frontier_vertex frontiers;
+ /* Store overlapping segments */
+ struct darray_seg_id overlapping_ids;
};
struct senc2d_scene {
diff --git a/src/test_senc2d_invalid_scenes.c b/src/test_senc2d_invalid_scenes.c
@@ -0,0 +1,128 @@
+/* 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>
+
+/*
+ 2 squares with some edges overlapping
+ */
+
+/* Dump of star-geometry-2d 'invalid'. */
+static const unsigned invalid_vertices_count = 6;
+static const double invalid_vertices[12] =
+{
+ 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1,
+ 2, 0,
+ 2, 1
+};
+static const unsigned invalid_segments_count = 7;
+static const unsigned invalid_segments[14] =
+{
+ 0, 2,
+ 2, 3,
+ 3, 1,
+ 1, 0,
+ 2, 5,
+ 5, 4,
+ 4, 0
+};
+static const unsigned invalid_properties[21] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0
+};
+
+static const unsigned degenerated_segments_count = 1;
+static const unsigned degenerated_vertices_count = 2;
+static const unsigned degenerated[2] = { 0, 0 };
+static const double degenerated_vertices[9] = { 0, 0 };
+static const unsigned degenerated_properties[3] = { 0, 0, 0 };
+
+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 count, 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 segment: duplicated vertex */
+ ctx.positions = degenerated_vertices;
+ ctx.indices = degenerated;
+ ctx.properties = degenerated_properties;
+ BA(senc2d_scene_create(dev,
+ SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_INSIDE,
+ degenerated_segments_count, get_indices, get_media_from_properties,
+ degenerated_vertices_count, get_position, &ctx, &scn));
+
+ /* Degenerated scene: overlapping segments */
+ ctx.positions = invalid_vertices;
+ ctx.indices = invalid_segments;
+ ctx.properties = invalid_properties;
+ OK(senc2d_scene_create(dev,
+ SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_INSIDE,
+ invalid_segments_count, get_indices, get_media_from_properties,
+ invalid_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc2d_scene_get_segments_count(scn, &scount));
+ FOR_EACH(s, 0, scount) {
+ unsigned ids[2];
+ BO(senc2d_scene_get_segment_enclosures(scn, s, ids));
+ }
+ BO(senc2d_scene_get_enclosure_count(scn, &count));
+ BO(senc2d_scene_get_enclosure(scn, 0, &enc));
+
+ OK(senc2d_scene_get_overlapping_segments_count(scn, &count));
+ FOR_EACH(e, 0, count) {
+ OK(senc2d_scene_get_overlapping_segment(scn, e, &s));
+ ASSERT(s < scount);
+ }
+ CHK(count == 4);
+ OK(senc2d_scene_get_overlapping_segment(scn, 0, &s));
+ BA(senc2d_scene_get_overlapping_segment(scn, count, &s));
+
+ 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;
+}
+
diff --git a/src/test_senc2d_scene.c b/src/test_senc2d_scene.c
@@ -210,6 +210,20 @@ main(int argc, char** argv)
BA(senc2d_scene_get_frontier_vertex(scn, UINT_MAX, NULL, NULL));
BA(senc2d_scene_get_frontier_vertex(NULL, UINT_MAX, NULL, NULL));
+ BA(senc2d_scene_get_overlapping_segments_count(NULL, NULL));
+ BA(senc2d_scene_get_overlapping_segments_count(scn, NULL));
+ BA(senc2d_scene_get_overlapping_segments_count(NULL, &count));
+ OK(senc2d_scene_get_overlapping_segments_count(scn, &count));
+ CHK(count == 0);
+
+ BA(senc2d_scene_get_overlapping_segment(NULL, 0, &seg));
+ BA(senc2d_scene_get_overlapping_segment(scn, UINT_MAX, &seg));
+ BA(senc2d_scene_get_overlapping_segment(scn, 0, NULL));
+ BA(senc2d_scene_get_overlapping_segment(NULL, UINT_MAX, &seg));
+ BA(senc2d_scene_get_overlapping_segment(NULL, 0, NULL));
+ BA(senc2d_scene_get_overlapping_segment(scn, UINT_MAX, NULL));
+ BA(senc2d_scene_get_overlapping_segment(NULL, UINT_MAX, NULL));
+
BA(senc2d_scene_ref_get(NULL));
OK(senc2d_scene_ref_get(scn));
BA(senc2d_scene_ref_put(NULL));
diff --git a/src/test_senc2d_utils.h b/src/test_senc2d_utils.h
@@ -25,6 +25,7 @@
#define OK(Expr) CHK((Expr) == RES_OK)
#define BA(Expr) CHK((Expr) == RES_BAD_ARG)
+#define BO(Expr) CHK((Expr) == RES_BAD_OP)
/******************************************************************************
* Geometry