star-enclosures-2d

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

senc2d_scene.c (9981B)


      1 /* Copyright (C) 2018-2021, 2023, 2024 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "senc2d.h"
     17 #include "senc2d_device_c.h"
     18 #include "senc2d_scene_c.h"
     19 #include "senc2d_scene_analyze_c.h"
     20 
     21 #include <rsys/rsys.h>
     22 #include <rsys/double2.h>
     23 #include <rsys/mem_allocator.h>
     24 
     25 #include <limits.h>
     26 
     27 /******************************************************************************
     28  * Helper function
     29  *****************************************************************************/
     30 static void
     31 scene_release(ref_T * ref)
     32 {
     33   struct senc2d_device* dev = NULL;
     34   struct senc2d_scene* scn = NULL;
     35   ASSERT(ref);
     36   scn = CONTAINER_OF(ref, struct senc2d_scene, ref);
     37   dev = scn->dev;
     38   darray_segment_in_release(&scn->segments_in);
     39   darray_position_release(&scn->vertices);
     40   darray_side_range_release(&scn->media_use);
     41 
     42   darray_segment_enc_release(&scn->analyze.segments_enc);
     43   darray_enclosure_release(&scn->analyze.enclosures);
     44   darray_enc_ids_array_release(&scn->analyze.enc_ids_array_by_medium);
     45   darray_frontier_vertex_release(&scn->analyze.frontiers);
     46   darray_seg_id_release(&scn->analyze.overlapping_ids);
     47 
     48   MEM_RM(dev->allocator, scn);
     49   SENC2D(device_ref_put(dev));
     50 }
     51 
     52 static INLINE int
     53 compatible_medium
     54   (const medium_id_t m1,
     55    const medium_id_t m2)
     56 {
     57   if(m1 == SENC2D_UNSPECIFIED_MEDIUM || m2 == SENC2D_UNSPECIFIED_MEDIUM)
     58     return 1;
     59   return (m1 == m2);
     60 }
     61 
     62 /******************************************************************************
     63  * Exported functions
     64  *****************************************************************************/
     65 res_T
     66 senc2d_scene_create
     67   (struct senc2d_device* dev,
     68    const int conv,
     69    const seg_id_t nsegs,
     70    void(*indices)(const seg_id_t, vrtx_id_t*, void*),
     71    void(*media)(const seg_id_t, medium_id_t*, void*),
     72    const vrtx_id_t nverts,
     73    void(*position)(const vrtx_id_t, double*, void* ctx),
     74    void* ctx,
     75    struct senc2d_scene** out_scn)
     76 {
     77   struct senc2d_scene* scn = NULL;
     78   /* Tables to detect duplicates */
     79   struct htable_vrtx unique_vertices;
     80   struct htable_seg unique_segments;
     81   vrtx_id_t nv;
     82   seg_id_t ns;
     83   res_T res = RES_OK;
     84 
     85   if(!dev || !out_scn || !indices || !position || !nverts || !nsegs
     86     /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */
     87     || !(conv & (SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_BACK))
     88     || !(conv & (SENC2D_CONVENTION_NORMAL_INSIDE | SENC2D_CONVENTION_NORMAL_OUTSIDE)))
     89     return RES_BAD_ARG;
     90 
     91   htable_vrtx_init(dev->allocator, &unique_vertices);
     92   htable_seg_init(dev->allocator, &unique_segments);
     93 
     94   scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc2d_scene));
     95   if(!scn) {
     96     log_err(dev, LIB_NAME":%s: could not allocate the star-enclosures-2d scene.\n",
     97       FUNC_NAME);
     98     res = RES_MEM_ERR;
     99     goto error;
    100   }
    101   ref_init(&scn->ref);
    102   SENC2D(device_ref_get(dev));
    103   scn->dev = dev;
    104   scn->convention = conv;
    105   scn->nsegs = nsegs;
    106   scn->next_medium_idx = 0;
    107   scn->nverts = nverts;
    108   darray_segment_in_init(dev->allocator, &scn->segments_in);
    109   darray_position_init(dev->allocator, &scn->vertices);
    110   darray_side_range_init(dev->allocator, &scn->media_use);
    111 
    112   darray_segment_enc_init(scn->dev->allocator, &scn->analyze.segments_enc);
    113   darray_enclosure_init(scn->dev->allocator, &scn->analyze.enclosures);
    114   darray_enc_ids_array_init(scn->dev->allocator,
    115     &scn->analyze.enc_ids_array_by_medium);
    116   darray_frontier_vertex_init(scn->dev->allocator, &scn->analyze.frontiers);
    117   /* Enclosure 0 is always defined for infinite */
    118   OK(darray_enclosure_resize(&scn->analyze.enclosures, 1));
    119   scn->analyze.enclosures_count = 1;
    120   darray_seg_id_init(scn->dev->allocator, &scn->analyze.overlapping_ids);
    121 
    122   OK(darray_position_reserve(&scn->vertices, scn->nverts));
    123   OK(darray_segment_in_reserve(&scn->segments_in, scn->nsegs));
    124   OK(htable_vrtx_reserve(&unique_vertices, scn->nverts));
    125   OK(htable_seg_reserve(&unique_segments, scn->nsegs));
    126 
    127   /* Get vertices */
    128   FOR_EACH(nv, 0, nverts) {
    129     vrtx_id_t* p_vrtx;
    130     union double2 tmp;
    131     position(nv, tmp.vec, ctx);
    132     p_vrtx = htable_vrtx_find(&unique_vertices, &tmp);
    133     if(p_vrtx) {
    134       /* Duplicate vertex */
    135       log_err(scn->dev, LIB_NAME":%s: vertex "PRTF_VRTX" is a duplicate.\n",
    136         FUNC_NAME, nv);
    137       res = RES_BAD_ARG;
    138       goto error;
    139     }
    140     /* New vertex */
    141     ASSERT(nv == htable_vrtx_size_get(&unique_vertices));
    142     OK(darray_position_push_back(&scn->vertices, &tmp));
    143     OK(htable_vrtx_set(&unique_vertices, &tmp, &nv));
    144   }
    145   /* Get segments */
    146   FOR_EACH(ns, 0, nsegs) {
    147     int j;
    148     seg_id_t s;
    149     medium_id_t med[2]
    150       = { SENC2D_UNSPECIFIED_MEDIUM, SENC2D_UNSPECIFIED_MEDIUM };
    151     vrtx_id_t ind[2];
    152     union vrtx_id2 seg_key;
    153     struct segment_in tmp;
    154     seg_id_t* p_seg;
    155     indices(ns, ind, ctx);
    156     FOR_EACH(j, 0, 2) {
    157       if(ind[j] >= nverts) {
    158         log_err(scn->dev,
    159           LIB_NAME":%s: segment "PRTF_SEG" uses invalid vertex id "PRTF_VRTX".\n",
    160           FUNC_NAME, ns, ind[j]);
    161         res = RES_BAD_ARG;
    162         goto error;
    163       }
    164       ASSERT(ind[j] <= VRTX_MAX__);
    165       tmp.vertice_id[j] = ind[j];
    166     }
    167     if(tmp.vertice_id[0] == tmp.vertice_id[1]) {
    168       log_err(scn->dev, LIB_NAME":%s: segment "PRTF_SEG" is degenerated.\n",
    169         FUNC_NAME, ns);
    170       res = RES_BAD_ARG;
    171       goto error;
    172     }
    173     /* Get media */
    174     if(media) {
    175       media(ns, med, ctx);
    176       for(s = SENC2D_FRONT; s <= SENC2D_BACK; s += SENC2D_BACK - SENC2D_FRONT) {
    177         if(med[s] == SENC2D_UNSPECIFIED_MEDIUM || med[s] <= MEDIUM_MAX__)
    178           continue;
    179         res = RES_BAD_ARG;
    180         goto error;
    181       }
    182     }
    183     seg_make_key(&seg_key, tmp.vertice_id);
    184     p_seg = htable_seg_find(&unique_segments, &seg_key);
    185     if(p_seg) {
    186       /* Duplicate segment */
    187       log_err(scn->dev, LIB_NAME":%s: segment "PRTF_SEG" is a duplicate.\n",
    188         FUNC_NAME, ns);
    189       res = RES_BAD_ARG;
    190       goto error;
    191     }
    192     /* New segment */
    193     ASSERT(ns == htable_seg_size_get(&unique_segments));
    194     OK(htable_seg_set(&unique_segments, &seg_key, &ns));
    195     for(s = SENC2D_FRONT; s <= SENC2D_BACK; s += SENC2D_BACK - SENC2D_FRONT) {
    196       struct side_range* media_use;
    197       size_t m_idx = medium_id_2_medium_idx(med[s]);
    198       tmp.medium[s] = med[s];
    199       if(m_idx >= scn->next_medium_idx) {
    200         medium_id_t medium;
    201         medium = (medium_id_t)m_idx;
    202         scn->next_medium_idx = medium;
    203         OK(darray_side_range_resize(&scn->media_use, 1 + m_idx));
    204       }
    205       /* media_use 0 is for SENC2D_UNSPECIFIED_MEDIUM */
    206       media_use = darray_side_range_data_get(&scn->media_use) + m_idx;
    207       media_use->first =
    208         MMIN(media_use->first, SEGIDxSIDE_2_SEGSIDE(ns, s));
    209       ASSERT(media_use->first < 2 * (scn->nsegs + 1));
    210       media_use->last =
    211         MMAX(media_use->last, SEGIDxSIDE_2_SEGSIDE(ns, s));
    212       ASSERT(media_use->last < 2 * (scn->nsegs + 1));
    213       ASSERT(media_use->first <= media_use->last);
    214     }
    215     OK(darray_segment_in_push_back(&scn->segments_in, &tmp));
    216   }
    217 
    218   OK(darray_enc_ids_array_resize(&scn->analyze.enc_ids_array_by_medium,
    219     1 + scn->next_medium_idx)); /* +1 is for undef */
    220   /* Proceed to the analyze */
    221   OK(scene_analyze(scn));
    222 
    223 exit:
    224   htable_vrtx_release(&unique_vertices);
    225   htable_seg_release(&unique_segments);
    226   if(scn) *out_scn = scn;
    227   return res;
    228 
    229 error:
    230   if(scn) {
    231     SENC2D(scene_ref_put(scn));
    232     scn = NULL;
    233   }
    234   goto exit;
    235 }
    236 
    237 res_T
    238 senc2d_scene_get_convention
    239   (const struct senc2d_scene* scn,
    240    int* convention)
    241 {
    242   if(!scn || !convention) return RES_BAD_ARG;
    243   *convention = scn->convention;
    244   return RES_OK;
    245 }
    246 
    247 res_T
    248 senc2d_scene_get_segments_count
    249   (const struct senc2d_scene* scn,
    250    seg_id_t* count)
    251 {
    252   if(!scn || !count) return RES_BAD_ARG;
    253   *count = scn->nsegs;
    254   return RES_OK;
    255 }
    256 
    257 res_T
    258 senc2d_scene_get_segment
    259   (const struct senc2d_scene* scn,
    260    const seg_id_t iseg,
    261    vrtx_id_t indices[2])
    262 {
    263   const struct segment_in* seg;
    264   int i;
    265   if(!scn || !indices
    266     || iseg >= darray_segment_in_size_get(&scn->segments_in))
    267     return RES_BAD_ARG;
    268   seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg;
    269   FOR_EACH(i, 0, 2) indices[i] = seg->vertice_id[i];
    270   return RES_OK;
    271 }
    272 
    273 res_T
    274 senc2d_scene_get_segment_media
    275   (const struct senc2d_scene* scn,
    276    const seg_id_t iseg,
    277    medium_id_t media[2])
    278 {
    279   const struct segment_in* seg;
    280   int i;
    281   if(!scn || !media
    282     || iseg >= darray_segment_in_size_get(&scn->segments_in))
    283     return RES_BAD_ARG;
    284   seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg;
    285   FOR_EACH(i, 0, 2) media[i] = seg->medium[i];
    286   return RES_OK;
    287 }
    288 
    289 res_T
    290 senc2d_scene_get_vertices_count
    291   (const struct senc2d_scene* scn,
    292    vrtx_id_t* count)
    293 {
    294   if(!scn || !count) return RES_BAD_ARG;
    295   *count = scn->nverts;
    296   return RES_OK;
    297 }
    298 
    299 res_T
    300 senc2d_scene_get_vertex
    301   (const struct senc2d_scene* scn,
    302    const vrtx_id_t ivert,
    303    double coord[2])
    304 {
    305   const union double2* v;
    306   if(!scn || !coord
    307     || ivert >= darray_position_size_get(&scn->vertices))
    308     return RES_BAD_ARG;
    309   v = darray_position_cdata_get(&scn->vertices) + ivert;
    310   d2_set(coord, v->vec);
    311   return RES_OK;
    312 }
    313 
    314 res_T
    315 senc2d_scene_ref_get(struct senc2d_scene* scn)
    316 {
    317   if(!scn) return RES_BAD_ARG;
    318   ref_get(&scn->ref);
    319   return RES_OK;
    320 }
    321 
    322 res_T
    323 senc2d_scene_ref_put(struct senc2d_scene* scn)
    324 {
    325   if(!scn) return RES_BAD_ARG;
    326   ref_put(&scn->ref, scene_release);
    327   return RES_OK;
    328 }