star-enclosures-2d

Extract enclosures from 2D geometry
git clone git://git.meso-star.fr/star-enclosures-2d.git
Log | Files | Refs | README | LICENSE

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:
Mcmake/CMakeLists.txt | 2+-
Msrc/senc2d.h | 23++++++++++++++++++++++-
Msrc/senc2d_descriptor.c | 51+++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/senc2d_internal_types.h | 34+++++++++++++++++++++-------------
Msrc/senc2d_scene.c | 2++
Msrc/senc2d_scene_analyze.c | 99++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/senc2d_scene_c.h | 6++++++
Asrc/test_senc2d_invalid_scenes.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_senc2d_scene.c | 14++++++++++++++
Msrc/test_senc2d_utils.h | 1+
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