star-camera

Camera models
git clone git://git.meso-star.fr/star-camera.git
Log | Files | Refs | README | LICENSE

test_scam_perspective_pinhole.c (6642B)


      1 /* Copyright (C) 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 */
     17 
     18 #include "scam.h"
     19 #include "test_scam_utils.h"
     20 
     21 #include <rsys/double3.h>
     22 #include <rsys/logger.h>
     23 #include <rsys/mem_allocator.h>
     24 
     25 #include <math.h>
     26 
     27 static void
     28 log_stream(const char* msg, void* ctx)
     29 {
     30   ASSERT(msg);
     31   (void)msg, (void)ctx;
     32   printf("%s", msg);
     33 }
     34 
     35 int
     36 main(int argc, char** argv)
     37 {
     38   struct logger logger;
     39   struct scam_perspective_args args = SCAM_PERSPECTIVE_ARGS_DEFAULT;
     40   struct scam_sample sample = SCAM_SAMPLE_NULL;
     41   struct scam_ray ray = SCAM_RAY_NULL;
     42   struct scam* cam = NULL;
     43   const size_t nsamps = 10000;
     44   double axis_x[3];
     45   double axis_y[3];
     46   double axis_z[3];
     47   double hori_hfov; /* horizontal half field of view */
     48   double sin_hori_hfov; /* Sinus of the horizontal half field of view */
     49   double sin_vert_hfov; /* Sinos of the vertical half field of view */
     50   double img_depth;
     51   double solid_angle;
     52   double ref;
     53   size_t i = 0;
     54   enum scam_type type = SCAM_NONE;
     55   (void)argc, (void)argv;
     56 
     57   CHK(scam_create_perspective(NULL, NULL, 0, NULL, &cam) == RES_BAD_ARG);
     58   CHK(scam_create_perspective(NULL, NULL, 0, &args, NULL) == RES_BAD_ARG);
     59   CHK(scam_create_perspective(NULL, NULL, 0, &args, &cam) == RES_OK);
     60 
     61   CHK(scam_get_type(NULL, &type) == RES_BAD_ARG);
     62   CHK(scam_get_type(cam, NULL) == RES_BAD_ARG);
     63   CHK(scam_get_type(cam, &type) == RES_OK);
     64   CHK(type == SCAM_PERSPECTIVE);
     65 
     66   CHK(scam_ref_get(NULL) == RES_BAD_ARG);
     67   CHK(scam_ref_get(cam) == RES_OK);
     68   CHK(scam_ref_put(NULL) == RES_BAD_ARG);
     69   CHK(scam_ref_put(cam) == RES_OK);
     70   CHK(scam_ref_put(cam) == RES_OK);
     71 
     72   CHK(logger_init(&mem_default_allocator, &logger) == RES_OK);
     73   logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
     74   logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
     75   logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
     76 
     77   CHK(scam_create_perspective(&logger, NULL, 0, &args, &cam) == RES_OK);
     78   CHK(scam_ref_put(cam) == RES_OK);
     79 
     80   CHK(scam_create_perspective(NULL, &mem_default_allocator, 0, &args, &cam) == RES_OK);
     81   CHK(scam_ref_put(cam) == RES_OK);
     82 
     83   d3_set(args.target, args.position);
     84   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     85 
     86   d3(args.position, 0, 0, 0);
     87   d3(args.target, 0, 1, 0);
     88   d3(args.up, 0, 1, 0);
     89   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     90 
     91   args = SCAM_PERSPECTIVE_ARGS_DEFAULT;
     92   args.aspect_ratio = 0;
     93   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     94 
     95   args = SCAM_PERSPECTIVE_ARGS_DEFAULT;
     96   args.field_of_view = 0;
     97   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     98   args.field_of_view = PI;
     99   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
    100   args.field_of_view = nextafter(0, PI);
    101   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
    102   CHK(scam_ref_put(cam) == RES_OK);
    103   args.field_of_view = nextafter(PI, 0);
    104   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
    105   CHK(scam_ref_put(cam) == RES_OK);
    106 
    107   args.position[0] = rand_canonical();
    108   args.position[1] = rand_canonical();
    109   args.position[2] = rand_canonical();
    110   args.target[0] = rand_canonical();
    111   args.target[1] = rand_canonical();
    112   args.target[2] = rand_canonical();
    113   args.up[0] = rand_canonical();
    114   args.up[1] = rand_canonical();
    115   args.up[2] = rand_canonical();
    116   args.field_of_view = PI/2.0;
    117   args.aspect_ratio = 1.0;
    118 
    119   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
    120   CHK(scam_perspective_get_solid_angle(NULL, &solid_angle) == RES_BAD_ARG);
    121   CHK(scam_perspective_get_solid_angle(cam, NULL) == RES_BAD_ARG);
    122   CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK);
    123 
    124   ref = args.field_of_view * 2*sin(args.field_of_view/2);
    125   CHK(eq_eps(solid_angle, ref, 1.e-6));
    126   CHK(scam_ref_put(cam) == RES_OK);
    127 
    128   args.aspect_ratio = 4.0/3.0;
    129   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
    130 
    131   CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK);
    132   ref = 2.6227869472431911;
    133   CHK(eq_eps(solid_angle, ref, 1.e-6));
    134 
    135   /* Precompute some view frustum constants */
    136   d3_normalize(axis_z, d3_sub(axis_z, args.target, args.position));
    137   d3_normalize(axis_x, d3_cross(axis_x, axis_z, args.up));
    138   d3_normalize(axis_y, d3_cross(axis_y, axis_z, axis_x));
    139   img_depth = 1.0/tan(args.field_of_view*0.5);
    140   hori_hfov = atan(args.aspect_ratio / img_depth);
    141   sin_hori_hfov = sin(hori_hfov);
    142   sin_vert_hfov = sin(args.field_of_view*0.5);
    143 
    144   CHK(scam_generate_ray(NULL, &sample, &ray) == RES_BAD_ARG);
    145   CHK(scam_generate_ray(cam, NULL, &ray) == RES_BAD_ARG);
    146   CHK(scam_generate_ray(cam, &sample, NULL) == RES_BAD_ARG);
    147 
    148   sample.film[0] = nextafterf(0, -1);
    149   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    150   sample.film[0] = 1;
    151   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    152   sample.film[0] = 0;
    153   sample.film[1] = nextafterf(0, -1);
    154   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    155   sample.film[1] = 1;
    156   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    157   sample.film[0] = 0;
    158   sample.film[1] = nextafterf(1, 0);
    159   CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK);
    160 
    161   FOR_EACH(i, 0, nsamps) {
    162     double cos_ray_axis_x;
    163     double cos_ray_axis_y;
    164     double cos_ray_axis_z;
    165     sample.film[0] = rand_canonical();
    166     sample.film[1] = rand_canonical();
    167     CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK);
    168 
    169     /* Check the ray origin */
    170     CHK(d3_eq(ray.org, args.position));
    171 
    172     /* Check that the generated ray is in the view frustum */
    173     CHK(d3_is_normalized(ray.dir));
    174     cos_ray_axis_x = d3_dot(ray.dir, axis_x);
    175     cos_ray_axis_y = d3_dot(ray.dir, axis_y);
    176     cos_ray_axis_z = d3_dot(ray.dir, axis_z);
    177     CHK(cos_ray_axis_z >= 0);
    178     CHK(cos_ray_axis_y <= sin_vert_hfov);
    179     CHK(cos_ray_axis_x <= sin_hori_hfov);
    180   }
    181   CHK(scam_ref_put(cam) == RES_OK);
    182 
    183   logger_release(&logger);
    184   CHK(mem_allocated_size() == 0);
    185   return 0;
    186 }