star-2d

Contour structuring for efficient 2D geometric queries
git clone git://git.meso-star.fr/star-2d.git
Log | Files | Refs | README | LICENSE

test_s2d_raytrace.c (7825B)


      1 /* Copyright (C) 2016-2021, 2023 |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 #define _POSIX_C_SOURCE 200112L /* nextafterf, exp2f, fabsf */
     17 
     18 #include "s2d.h"
     19 #include "test_s2d_utils.h"
     20 
     21 #include <rsys/float2.h>
     22 #include <rsys/float3.h>
     23 
     24 /*******************************************************************************
     25  * Single segment test
     26  ******************************************************************************/
     27 static void
     28 test_single_segment(struct s2d_device* dev)
     29 {
     30   struct s2d_vertex_data vdata = S2D_VERTEX_DATA_NULL;
     31   struct line_segments_desc desc;
     32   struct s2d_hit hit = S2D_HIT_NULL;
     33   struct s2d_hit hit3 = S2D_HIT_NULL;
     34   struct s2d_scene* scn = NULL;
     35   struct s2d_scene_view* view = NULL;
     36   struct s2d_shape* shape = NULL;
     37   struct s2d_attrib attr;
     38   float vertices[4];
     39   float v0[2], v1[2];
     40   float pos[2];
     41   size_t a, i, j;
     42   unsigned indices[2] = {0, 1};
     43 
     44   f2(vertices+0, -0.5f, -0.3f);
     45   f2(vertices+2, -0.4f,  0.2f);
     46 
     47   CHK(s2d_scene_create(dev, &scn) == RES_OK);
     48   CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK);
     49   CHK(s2d_scene_attach_shape(scn, shape) == RES_OK);
     50 
     51   vdata.usage = S2D_POSITION;
     52   vdata.type = S2D_FLOAT2;
     53   vdata.get = line_segments_get_position;
     54   desc.vertices = vertices;
     55   desc.indices = indices;
     56   CHK(s2d_line_segments_setup_indexed_vertices
     57     (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK);
     58 
     59   CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
     60 
     61   line_segments_get_position(0, v0, &desc);
     62   line_segments_get_position(1, v1, &desc);
     63 
     64   CHK(s2d_scene_view_ref_put(view) == RES_OK);
     65   CHK(s2d_shape_ref_put(shape) == RES_OK);
     66   CHK(s2d_scene_ref_put(scn) == RES_OK);
     67 
     68   /* Check accuracy on a configuration whose analytic distance is known */
     69   FOR_EACH(a, 0, 16) {
     70     const float amplitude = exp2f((float)a);
     71     const float eps = 1e-6f * amplitude;
     72     FOR_EACH(i, 0, 1000) {
     73       float A[2], B[2], AB[2], N[2];
     74       int n;
     75 
     76       /* Randomly generate a segment AB */
     77       FOR_EACH(n, 0, 2)
     78         A[n] = (rand_canonic() - 0.5f) * amplitude;
     79       do {
     80         FOR_EACH(n, 0, 2) B[n] = (rand_canonic() - 0.5f) * amplitude;
     81       } while (f2_eq_eps(A, B, eps));
     82 
     83       f2_sub(AB, B, A);
     84       f2(N, -AB[1], AB[0]);
     85       f2_normalize(N, N);
     86 
     87       f2_set(vertices + 0, A);
     88       f2_set(vertices + 2, B);
     89 
     90       CHK(s2d_scene_create(dev, &scn) == RES_OK);
     91       CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK);
     92       CHK(s2d_scene_attach_shape(scn, shape) == RES_OK);
     93 
     94       vdata.usage = S2D_POSITION;
     95       vdata.type = S2D_FLOAT2;
     96       vdata.get = line_segments_get_position;
     97       desc.vertices = vertices;
     98       desc.indices = indices;
     99       CHK(s2d_line_segments_setup_indexed_vertices
    100         (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK);
    101 
    102       CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
    103 
    104       FOR_EACH(j, 0, 1000) {
    105         float proj[2]; /* Projection of pos on the line */
    106         float u, h, l;
    107         float dir[3], range[2] = { 0, FLT_MAX };
    108 
    109         /* Randomly generate a pos not on the segment
    110          * with know position wrt the problem: pos = A + u.AB + k.N */
    111         u = 1.2f * rand_canonic() - 0.1f;
    112         h = (2 * rand_canonic() - 1) * amplitude;
    113         f2_add(proj, A, f2_mulf(proj, AB, u));
    114         f2_add(pos, proj, f2_mulf(pos, N, h));
    115 
    116         /* Raytrace from pos towards proj */
    117         f2_mulf(dir, N, (h > 0 ? -1.f : 1.f));
    118         CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit)
    119           == RES_OK);
    120         dir[2] = rand_canonic() - 0.5f;
    121         l = f3_normalize(dir, dir);
    122         CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit3)
    123           == RES_OK);
    124 
    125         /* Check result */
    126         if(u < 0 || u > 1) {
    127           if(!S2D_HIT_NONE(&hit) || !S2D_HIT_NONE(&hit3))
    128             CHK(u >= -FLT_EPSILON && u <= 1 + FLT_EPSILON);
    129         } else {
    130           if(S2D_HIT_NONE(&hit) || S2D_HIT_NONE(&hit3))
    131             CHK(u <= FLT_EPSILON || u >= 1 - FLT_EPSILON);
    132         }
    133         if(!S2D_HIT_NONE(&hit)) {
    134           CHK(eq_epsf(hit.distance, fabsf(h), eps));
    135           CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr)
    136             == RES_OK);
    137           CHK(f2_eq_eps(attr.value, proj, eps));
    138         }
    139         if(!S2D_HIT_NONE(&hit3)) {
    140           CHK(eq_epsf(hit3.distance, l * fabsf(h), eps));
    141           CHK(s2d_primitive_get_attrib(&hit3.prim, S2D_POSITION, hit3.u, &attr)
    142             == RES_OK);
    143           CHK(f2_eq_eps(attr.value, proj, eps));
    144         }
    145       }
    146 
    147       CHK(s2d_scene_view_ref_put(view) == RES_OK);
    148       CHK(s2d_shape_ref_put(shape) == RES_OK);
    149       CHK(s2d_scene_ref_put(scn) == RES_OK);
    150     }
    151   }
    152 }
    153 
    154 /*******************************************************************************
    155  * Miscellaneous test
    156  ******************************************************************************/
    157 static void
    158 test_api(struct s2d_device* dev)
    159 {
    160   struct s2d_hit hit = S2D_HIT_NULL;
    161   struct s2d_scene* scn = NULL;
    162   struct s2d_scene_view* view = NULL;
    163   float pos[3] = { 0 }, dir[3] = { 1 }, range[2] = { 0, 1 };
    164 
    165   CHK(s2d_scene_create(dev, &scn) == RES_OK);
    166   CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
    167 
    168   CHK(s2d_scene_view_trace_ray(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG);
    169   CHK(s2d_scene_view_trace_ray(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG);
    170   CHK(s2d_scene_view_trace_ray(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG);
    171   CHK(s2d_scene_view_trace_ray(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG);
    172   CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG);
    173   CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK);
    174   CHK(S2D_HIT_NONE(&hit));
    175 
    176   CHK(s2d_scene_view_trace_ray_3d(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG);
    177   CHK(s2d_scene_view_trace_ray_3d(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG);
    178   CHK(s2d_scene_view_trace_ray_3d(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG);
    179   CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG);
    180   CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG);
    181   CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit) == RES_OK);
    182   CHK(S2D_HIT_NONE(&hit));
    183 
    184   CHK(s2d_scene_view_ref_put(view) == RES_OK);
    185   CHK(s2d_scene_view_create(scn, S2D_SAMPLE, &view) == RES_OK);
    186   CHK(s2d_scene_view_closest_point(view, pos, 1.f, NULL, &hit) == RES_BAD_OP);
    187 
    188   CHK(s2d_scene_view_ref_put(view) == RES_OK);
    189   CHK(s2d_scene_ref_put(scn) == RES_OK);
    190 }
    191 
    192 /*******************************************************************************
    193  * Main function
    194  ******************************************************************************/
    195 int
    196 main(int argc, char** argv)
    197 {
    198   struct mem_allocator allocator;
    199   struct s2d_device* dev = NULL;
    200   (void)argc, (void)argv;
    201 
    202   mem_init_proxy_allocator(&allocator, &mem_default_allocator);
    203   CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK);
    204 
    205   test_api(dev);
    206   test_single_segment(dev);
    207 
    208   CHK(s2d_device_ref_put(dev) == RES_OK);
    209 
    210   check_memory_allocator(&allocator);
    211   mem_shutdown_proxy_allocator(&allocator);
    212   CHK(mem_allocated_size() == 0);
    213   return 0;
    214 }