star-enclosures-2d

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

test_senc2d_utils.h (8353B)


      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 #ifndef TEST_SENC2_UTILS_H
     17 #define TEST_SENC2_UTILS_H
     18 
     19 #include <rsys/rsys.h>
     20 #include <rsys/mem_allocator.h>
     21 #include <rsys/stretchy_array.h>
     22 #include <rsys/double2.h>
     23 
     24 #include <stdio.h>
     25 
     26 #define OK(Expr) CHK((Expr) == RES_OK)
     27 #define BA(Expr) CHK((Expr) == RES_BAD_ARG)
     28 #define BO(Expr) CHK((Expr) == RES_BAD_OP)
     29 
     30 /******************************************************************************
     31  * Geometry
     32  *****************************************************************************/
     33 /* Distorded square */
     34 static const double
     35 box_vertices[4/*#vertices*/ * 2/*#coords per vertex*/] = {
     36   0.1, 0.0,
     37   1.0, 0.0,
     38   0.0, 1.1,
     39   1.0, 1.0
     40 };
     41 /* Need a true square for some tests */
     42 static const double
     43 square_vertices[4/*#vertices*/ * 2/*#coords per vertex*/] = {
     44   0.0, 0.0,
     45   1.0, 0.0,
     46   0.0, 1.0,
     47   1.0, 1.0
     48 };
     49 static const unsigned
     50 nvertices = sizeof(box_vertices) / (2 * sizeof(*box_vertices));
     51 STATIC_ASSERT(sizeof(box_vertices) == sizeof(square_vertices),
     52   The_2_geometries_must_have_the_same_number_of_vertices);
     53 
     54 /* The following array lists the indices toward the 2D vertices of each
     55  * segment.
     56  *                   Y
     57  *    2----3         |
     58  *    |    |         0----X
     59  *    |    |
     60  *    0----1
     61  */
     62 static const unsigned
     63 box_indices[4/*#segments*/ * 2/*#indices per segment*/] = {
     64   0, 2,
     65   2, 3,
     66   3, 1,
     67   1, 0
     68 };
     69 static const unsigned
     70 nsegments = sizeof(box_indices) / (2 * sizeof(*box_indices));
     71 
     72 struct context {
     73   const double* positions;
     74   const unsigned* indices;
     75   const unsigned* front_media;
     76   const unsigned* back_media;
     77   const unsigned* properties;
     78   void* custom;
     79   double offset[2];
     80   double scale;
     81   char reverse_vrtx, reverse_med;
     82 };
     83 #define CONTEXT_NULL__ {\
     84   NULL, NULL, NULL, NULL, NULL, NULL, {0,0}, 1, 0, 0\
     85 }
     86 
     87 static const unsigned medium0[4] = { 0, 0, 0, 0 };
     88 static const unsigned medium1[4] = { 1, 1, 1, 1 };
     89 static const unsigned medium2[4] = { 2, 2, 2, 2 };
     90 static const unsigned medium1_3[4] = { 1, 1, 3, 1 };
     91 static const unsigned medium1_back0[4] = { 1, 1, 1, 0 };
     92 static const unsigned medium1_front0[4] = { 1, 0, 1, 1 };
     93 
     94 static INLINE void
     95 get_indices(const unsigned iseg, unsigned ids[2], void* context)
     96 {
     97   const struct context* ctx = context;
     98   ASSERT(ids && ctx);
     99   ids[ctx->reverse_vrtx ? 1 : 0] = ctx->indices[iseg * 2 + 0];
    100   ids[ctx->reverse_vrtx ? 0 : 1] = ctx->indices[iseg * 2 + 1];
    101 }
    102 
    103 static INLINE void
    104 get_position(const unsigned ivert, double pos[2], void* context)
    105 {
    106   const struct context* ctx = context;
    107   ASSERT(pos && ctx);
    108   pos[0] = ctx->positions[ivert * 2 + 0] * ctx->scale + ctx->offset[0];
    109   pos[1] = ctx->positions[ivert * 2 + 1] * ctx->scale + ctx->offset[1];
    110 }
    111 
    112 static INLINE void
    113 get_media(const unsigned iseg, unsigned medium[2], void* context)
    114 {
    115   const struct context* ctx = context;
    116   ASSERT(medium && ctx);
    117   medium[ctx->reverse_med ? 1 : 0] = ctx->front_media[iseg];
    118   medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[iseg];
    119 }
    120 
    121 static INLINE void
    122 get_media_from_properties(const unsigned iseg, unsigned medium[2], void* context)
    123 {
    124   const struct context* ctx = context;
    125   ASSERT(medium && ctx);
    126   medium[ctx->reverse_med ? 1 : 0] = ctx->properties[3 * iseg + 0];
    127   medium[ctx->reverse_med ? 0 : 1] = ctx->properties[3 * iseg + 1];
    128 }
    129 
    130 /******************************************************************************
    131  * Miscellaneous
    132  *****************************************************************************/
    133 static INLINE void
    134 dump_global
    135   (struct senc2d_scene* scn,
    136    const char* name)
    137 {
    138   FILE* stream;
    139   unsigned segments_count, vertices_count, i;
    140 
    141   ASSERT(scn && name);
    142 
    143   OK(senc2d_scene_get_vertices_count(scn, &vertices_count));
    144   OK(senc2d_scene_get_segments_count(scn, &segments_count));
    145 
    146   stream = fopen(name, "w");
    147   CHK(stream);
    148   FOR_EACH(i, 0, vertices_count) {
    149     double tmp[2];
    150     OK(senc2d_scene_get_vertex(scn, i, tmp));
    151     fprintf(stream, "v %g %g\n", SPLIT2(tmp));
    152   }
    153   FOR_EACH(i, 0, segments_count) {
    154     unsigned indices[2];
    155     OK(senc2d_scene_get_segment(scn, i, indices));
    156     fprintf(stream, "l %u %u\n", 1 + indices[0], 1 + indices[1]);
    157   }
    158   fclose(stream);
    159 }
    160 
    161 static INLINE void
    162 dump_enclosure
    163   (struct senc2d_scene* scn,
    164    const unsigned enc,
    165    const char* name)
    166 {
    167   struct senc2d_enclosure* enclosure;
    168   struct senc2d_enclosure_header header;
    169   FILE* stream;
    170   unsigned count, i;
    171 
    172   ASSERT(scn && name);
    173 
    174   SENC2D(scene_get_enclosure_count(scn, &count));
    175   ASSERT(enc < count);
    176   OK(senc2d_scene_get_enclosure(scn, enc, &enclosure));
    177   OK(senc2d_enclosure_get_header(enclosure, &header));
    178 
    179   stream = fopen(name, "w");
    180   CHK(stream);
    181   FOR_EACH(i, 0, header.vertices_count) {
    182     double tmp[2];
    183     OK(senc2d_enclosure_get_vertex(enclosure, i, tmp));
    184     fprintf(stream, "v %g %g\n", SPLIT2(tmp));
    185   }
    186   FOR_EACH(i, 0, header.primitives_count) {
    187     unsigned indices[2];
    188     OK(senc2d_enclosure_get_segment(enclosure, i, indices));
    189     fprintf(stream, "l %u %u\n", 1+indices[0], 1+indices[1]);
    190   }
    191   OK(senc2d_enclosure_ref_put(enclosure));
    192   fclose(stream);
    193 }
    194 
    195 static INLINE void
    196 check_memory_allocator(struct mem_allocator* allocator)
    197 {
    198   if(MEM_ALLOCATED_SIZE(allocator)) {
    199     char dump[1024];
    200     MEM_DUMP(allocator, dump, sizeof(dump));
    201     fprintf(stderr, "%s\n", dump);
    202     FATAL("Memory leaks.\n");
    203   }
    204 }
    205 
    206 /******************************************************************************
    207  * Circle functions
    208  *****************************************************************************/
    209 static INLINE void
    210 create_circle
    211   (const double radius,
    212    const unsigned nslices,
    213    struct context* ctx)
    214 {
    215   double step_theta;
    216   unsigned itheta;
    217   unsigned islice;
    218   double* d = NULL;
    219   unsigned* u = NULL;
    220   ASSERT(radius > 0 && nslices >= 3 && ctx);
    221 
    222   step_theta = 2 * PI / (double)nslices;
    223   FOR_EACH(itheta, 0, nslices) {
    224     const double theta = (double)itheta * step_theta;
    225     const double x = cos(theta);
    226     const double y = sin(theta);
    227     sa_push(d, x * radius);
    228     sa_push(d, y * radius);
    229   }
    230   ctx->positions = d;
    231 
    232   FOR_EACH(islice, 0, nslices) {
    233     const unsigned v0 = islice;
    234     const unsigned v1 = ((islice + 1) % nslices);
    235     sa_push(u, v0);
    236     sa_push(u, v1);
    237   }
    238   ctx->indices = u;
    239 }
    240 
    241 static INLINE void
    242 circle_release(struct context* ctx)
    243 {
    244   ASSERT(ctx);
    245   sa_release(ctx->positions);
    246   sa_release(ctx->indices);
    247   ctx->positions = NULL;
    248   ctx->indices = NULL;
    249 }
    250 
    251 /******************************************************************************
    252  * Check functions
    253  *****************************************************************************/
    254 /* Compare the iseg-th segment of enclosure with a segment described by seg2 & vertices2 */
    255 static INLINE void
    256 cmp_seg
    257   (const unsigned iseg,
    258    const struct senc2d_enclosure* enclosure,
    259    const unsigned seg2[2],
    260    const double* vertices2,
    261    int* seg_eq,
    262    int* seg_reversed)
    263 {
    264   unsigned seg1[2];
    265   double s1[2][2];
    266   double s2[2][2];
    267   unsigned seg1_eq[2] = { 2, 2 };
    268   unsigned i, j;
    269 
    270   ASSERT(enclosure && seg2 && vertices2 && seg_eq && seg_reversed);
    271 
    272   OK(senc2d_enclosure_get_segment(enclosure, iseg, seg1));
    273   FOR_EACH(i, 0, 2) {
    274     OK(senc2d_enclosure_get_vertex(enclosure, seg1[i], s1[i]));
    275     d2_set(s2[i], vertices2 + (2 * seg2[i]));
    276   }
    277   FOR_EACH(i, 0, 2) {
    278     FOR_EACH(j, 0, 2) {
    279       if(d2_eq(s1[i], s2[j])) {
    280         seg1_eq[i] = j;
    281         break;
    282       }
    283     }
    284   }
    285   FOR_EACH(i, 0, 2) {
    286     if(seg1_eq[i] == 2) {
    287       *seg_eq = 0;
    288       return;
    289     }
    290     if(seg1_eq[i] == seg1_eq[(i + 1) % 2]) {
    291       *seg_eq = 0;
    292       return;
    293     }
    294   }
    295   /* Same 2 vertices */
    296   *seg_eq = 1;
    297 
    298   *seg_reversed = (0 != seg1_eq[0]);
    299   ASSERT(*seg_reversed == (1 != seg1_eq[1]));
    300 }
    301 
    302 #endif /* TEST_SENC2_UTILS_H */