star-2d

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

commit 6242f565eeda4587971c4af0ffe49f768c525146
parent 166331e25ace41eba1c5342b2099dcc53d055fc5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 15 Jun 2021 10:49:09 +0200

Merge branch 'release_0.4.1'

Diffstat:
MREADME.md | 9++++++++-
Mcmake/CMakeLists.txt | 6++++--
Msrc/s2d.h | 6+++---
Msrc/s2d_backend.h | 14+++++++++++++-
Msrc/s2d_buffer.h | 2+-
Msrc/s2d_c.h | 2+-
Msrc/s2d_device.c | 8+++-----
Msrc/s2d_device_c.h | 2+-
Msrc/s2d_geometry.c | 2+-
Msrc/s2d_geometry.h | 2+-
Msrc/s2d_line_segments.c | 2+-
Msrc/s2d_line_segments.h | 2+-
Msrc/s2d_primitive.c | 2+-
Msrc/s2d_scene.c | 2+-
Msrc/s2d_scene_c.h | 2+-
Msrc/s2d_scene_view.c | 6+++---
Msrc/s2d_scene_view_c.h | 2+-
Msrc/s2d_scene_view_closest_point.c | 69+++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/s2d_shape.c | 2+-
Msrc/s2d_shape_c.h | 2+-
Msrc/test_s2d_closest_point.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/test_s2d_device.c | 2+-
Msrc/test_s2d_primitive.c | 2+-
Asrc/test_s2d_raytrace.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_s2d_sample.c | 6+++---
Msrc/test_s2d_scene.c | 6+++---
Msrc/test_s2d_scene_view.c | 20++++++++++----------
Msrc/test_s2d_scene_view2.c | 2+-
Msrc/test_s2d_shape.c | 2+-
Msrc/test_s2d_trace_ray.c | 14+++++++-------
Msrc/test_s2d_trace_ray_3d.c | 4++--
Msrc/test_s2d_utils.h | 12++++++------
32 files changed, 433 insertions(+), 102 deletions(-)

diff --git a/README.md b/README.md @@ -97,6 +97,13 @@ with `<STAR2D_INSTALL_DIR>` the install directory of Star-2D and ## Release notes +### Vesion 0.4.1 + +- Improve the accuracy of the closest point query. +- Fix the closest point query: the returned hit was wrong. +- Fix the barycentric coordinates of the intersection of the ray onto the + segment: the coordinates could lie outside the segment. + ### Version 0.4 - Add the `s2d_scene_view_closest_point` function. This function retrieves the @@ -140,7 +147,7 @@ with `<STAR2D_INSTALL_DIR>` the install directory of Star-2D and ## License -Copyright (C) 2016-2020 |Meso|Star> (<contact@meso-star.com>). Star-2D is free +Copyright (C) 2016-2021 |Meso|Star> (<contact@meso-star.com>). Star-2D is free software released under the CeCILL v2.1 license. You are welcome to redistribute it under certain conditions; refer to the COPYING files for details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +# Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) # # This software is governed by the CeCILL license under French law and # abiding by the rules of distribution of free software. You can use, @@ -57,7 +57,7 @@ endif() ################################################################################ set(VERSION_MAJOR 0) set(VERSION_MINOR 4) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(S2D_FILES_SRC @@ -71,6 +71,7 @@ set(S2D_FILES_SRC s2d_shape.c) set(S2D_FILES_INC_API s2d.h) set(S2D_FILES_INC + s2d_backend.h s2d_buffer.h s2d_device_c.h s2d_geometry.h @@ -136,6 +137,7 @@ if(NOT NO_TEST) new_test(test_s2d_closest_point) new_test(test_s2d_device) new_test(test_s2d_primitive) + new_test(test_s2d_raytrace) new_test(test_s2d_sample) new_test(test_s2d_shape) new_test(test_s2d_scene) diff --git a/src/s2d.h b/src/s2d.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -123,7 +123,7 @@ static const struct s2d_vertex_data S2D_VERTEX_DATA_NULL = S2D_VERTEX_DATA_NULL_ /* Intersection point */ struct s2d_hit { struct s2d_primitive prim; /* Intersected primitive */ - float normal[2]; /* Unormalized geometry normal */ + float normal[2]; /* Unormalized geometry normal (left hand convention) */ float u; /* Barycentric coordinates onto `prim'. pos = (1 - u)*v0 + u*v1 */ float distance; /* Hit distance from the ray origin */ }; @@ -304,7 +304,7 @@ S2D_API res_T s2d_scene_view_closest_point (struct s2d_scene_view* scnview, const float pos[2], /* Position to query */ - const float radius, /* Search distance in ]0, radius[ */ + const float radius, /* Search distance in [0, radius[ */ void* query_data, /* User data sent to the hit filter func. May be NULL */ struct s2d_hit* hit); diff --git a/src/s2d_backend.h b/src/s2d_backend.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is a computer program whose purpose is to describe a * virtual 3D environment that can be ray-traced and sampled both robustly @@ -33,7 +33,19 @@ #ifndef S2D_BACKEND_H #define S2D_BACKEND_H +#include <rsys/rsys.h> /* COMPILER_CL */ + +#ifdef COMPILER_CL +/* Structure was padded due to alignment specifier */ +#pragma warning(push) +#pragma warning(disable: 4324) +#endif + #include <embree3/rtcore.h> +#ifdef COMPILER_CL +#pragma warning(pop) +#endif + #endif /* S2D_BACKEND_H */ diff --git a/src/s2d_buffer.h b/src/s2d_buffer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_c.h b/src/s2d_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_device.c b/src/s2d_device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -39,10 +39,8 @@ static INLINE void rtc_error_func(void* context, enum RTCError err, const char* str) { - char msg[128]; - (void)str, (void)err, (void)context; - snprintf(msg, sizeof(msg), "Embree:error: %s\n", rtc_error_string(err)); - FATAL(msg); + (void)str, (void)context; + VFATAL("Embree:error: %s\n", ARG1(rtc_error_string(err))); } static INLINE void diff --git a/src/s2d_device_c.h b/src/s2d_device_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_geometry.c b/src/s2d_geometry.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_geometry.h b/src/s2d_geometry.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_line_segments.c b/src/s2d_line_segments.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_primitive.c b/src/s2d_primitive.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene.c b/src/s2d_scene.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene_c.h b/src/s2d_scene_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene_view.c b/src/s2d_scene_view.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -166,8 +166,8 @@ hit_setup hit->prim.scene_prim_id = hit->prim.prim_id + geom->scene_prim_id_offset; /* The Embree "v" parametric coordinate of the extruded quad corresponds to - * the edge parametric coordinate */ - hit->u = ray_hit->hit.v; + * the edge parametric coordinate (handle Embree returning v out of range) */ + hit->u = CLAMP(ray_hit->hit.v, 0, 1); if(geom->flip_contour) { f2_minus(hit->normal, hit->normal); diff --git a/src/s2d_scene_view_c.h b/src/s2d_scene_view_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_scene_view_closest_point.c b/src/s2d_scene_view_closest_point.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -33,6 +33,7 @@ #include "s2d_scene_view_c.h" #include <rsys/float2.h> +#include <rsys/double2.h> struct point_query_context { struct RTCPointQueryContext rtc; @@ -45,38 +46,48 @@ struct point_query_context { ******************************************************************************/ static INLINE float* closest_point_segment - (const float p[2], /* Position */ - const float v0[2], /* 1st segment vertex */ - const float v1[2], /* 2nd segment vertex */ - const float E[2], /* v0 -> v1 vector */ - float closest_pt[2], /* Closest position */ - float* s) /* Parametric coordinate of the closest point onto [v0, v1] */ + (const float p_f[2], /* Position */ + const float v0_f[2], /* 1st segment vertex */ + const float v1_f[2], /* 2nd segment vertex */ + float closest_pt_f[2], /* Closest position */ + float* s_f) /* Parametric coordinate of the closest point onto [v0, v1] */ { - float v[2]; /* Vector from v0 to p */ - float segment_len; /* Length of the [v0, v1] */ - float dst; /* Dst from v0 to the orthogonal projection of p onto [v0, v1] */ - ASSERT(p && v0 && v1); - ASSERT(f2_eq(f2_sub(v, v1, v0), E)); + double v[2]; /* Vector from v0 to p */ + double E[2]; /* v0 -> v1 vector */ + double p[2], v0[2], v1[2], closest_pt[2]; + double segment_len2; /* Square length of the [v0, v1] */ + double dst_x_seglen; /* |p' v0| x |v0 v1| + * p' is the orthogonal projection of p onto [v0, v1] */ + double s; + ASSERT(p_f && v0_f && v1_f); + + d2_set_f2(v0, v0_f); + d2_set_f2(v1, v1_f); + d2_set_f2(p, p_f); + d2_sub(E, v1, v0); /* Orthogonally project the point onto the segment */ - f2_sub(v, p, v0); - segment_len = f2_len(E); - dst = f2_dot(v, E); + d2_sub(v, p, v0); + dst_x_seglen = d2_dot(v, E); /* Check if the closest point is the segment vertex 'v0' */ - if(dst <= 0) { - *s = 0; - return f2_set(closest_pt, v0); + if(dst_x_seglen <= 0) { + *s_f = 0; + return f2_set(closest_pt_f, v0_f); } /* Check if the closest point is the segment vertex 'v1' */ - if(dst >= segment_len) { - *s = 1; - return f2_set(closest_pt, v1); + segment_len2 = d2_dot(E, E); + if(dst_x_seglen >= segment_len2) { + *s_f = 1; + return f2_set(closest_pt_f, v1_f); } /* The closest point is on the segment */ - *s = CLAMP(dst / segment_len, 0, 1); - return f2_add(closest_pt, f2_mulf(closest_pt, E, dst/segment_len), v0); + s = dst_x_seglen / segment_len2; + d2_add(closest_pt, d2_muld(closest_pt, E, s), v0); + *s_f = (float)s; + ASSERT(*s_f == CLAMP(*s_f, 0, 1)); + return f2_set_d2(closest_pt_f, closest_pt); } static bool @@ -90,7 +101,6 @@ closest_point_line_segments struct hit_filter* filter = NULL; const uint32_t* ids = NULL; float v0[2], v1[2]; /* Segment vertices */ - float E[2]; /* Segment vector */ float N[2]; /* Segment normal */ float query_pos[2]; /* Submitted position */ float closest_point[2]; /* Computed closest point */ @@ -107,21 +117,20 @@ closest_point_line_segments ASSERT(geom->lines->attribs_type[S2D_POSITION] == S2D_FLOAT2); f2_set(v0, line_segments_get_pos(geom->lines)+ids[0]*2/*#coords per vertex */); f2_set(v1, line_segments_get_pos(geom->lines)+ids[1]*2/*#coords per vertex */); - f2_sub(E, v1, v0); query_pos[0] = args->query->x; query_pos[1] = args->query->y; - /* Compute the closest point ont the segment from the sumbitted query_pos */ - closest_point_segment(query_pos, v0, v1, E, closest_point, &s); + /* Compute the closest point on the segment from the submitted query_pos */ + closest_point_segment(query_pos, v0, v1, closest_point, &s); f2_sub(vec, closest_point, query_pos); dst = f2_len(vec); if(dst >= args->query->radius) return 0; - /* Compute the segment normal */ - N[0] = E[1]; - N[1] = E[0]; + /* Compute the segment normal (left hand convention) */ + N[0] = v1[1] - v0[1]; + N[1] = v0[0] - v1[0]; /* Flip the geometry normal wrt the flip line_segments flag */ if(geom->flip_contour) f2_minus(N, N); diff --git a/src/s2d_shape.c b/src/s2d_shape.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/s2d_shape_c.h b/src/s2d_shape_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_closest_point.c b/src/test_s2d_closest_point.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -72,8 +72,8 @@ closest_point_segment f2_sub(v, p, a); f2_sub(E, b, a); - dst = f2_dot(v, E); len = f2_len(E); + dst = f2_dot(v, E) / len; if(dst <= 0) return f2_set(pt, a); if(dst >= len) return f2_set(pt, b); @@ -121,8 +121,8 @@ closest_point_line_segments f2_set(pt->pos, closest_pt); pt->dst = dst; pt->iprim = iseg; - f2_sub(pt->normal, v1, v0); - SWAP(float, pt->normal[0], pt->normal[1]); + pt->normal[0] = v1[1] - v0[1]; + pt->normal[1] = -v1[0] + v0[0]; f2_normalize(pt->normal, pt->normal); } } @@ -308,7 +308,6 @@ test_square(struct s2d_device* dev) check_closest_point_square(pos, igeom, filter_ctx.prim_to_filter, &hit); } - /* Clean up */ CHK(s2d_shape_ref_put(shape) == RES_OK); CHK(s2d_scene_ref_put(scn) == RES_OK); @@ -333,7 +332,7 @@ test_single_segment(struct s2d_device* dev) float low[2], upp[2], mid[2]; float pos[2]; float closest_pos[2]; - size_t i; + size_t a, i, j; unsigned indices[2] = {0, 1}; f2(vertices+0, -0.5f, -0.3f); @@ -366,7 +365,7 @@ test_single_segment(struct s2d_device* dev) FOR_EACH(i, 0, 10000) { /* Randomly generate a point in a bounding box that is 10 times the size of - * the triangle AABB */ + * the segment AABB */ pos[0] = mid[0] + (rand_canonic() * 2 - 1) * (upp[0] - low[0]) * 5.f; pos[1] = mid[1] + (rand_canonic() * 2 - 1) * (upp[1] - low[1]) * 5.f; @@ -383,11 +382,12 @@ test_single_segment(struct s2d_device* dev) float radius; /* Randomly generate a point in a bounding box that is 10 times the size of - * the triangle AABB */ + * the segment AABB */ pos[0] = mid[0] + (rand_canonic() * 2 - 1) * (upp[0] - low[0]) * 5.f; pos[1] = mid[1] + (rand_canonic() * 2 - 1) * (upp[1] - low[1]) * 5.f; - CHK(s2d_scene_view_closest_point(view, pos, (float)INF, NULL, &hit) == RES_OK); + CHK(s2d_scene_view_closest_point(view, pos, (float)INF, NULL, &hit) + == RES_OK); CHK(!S2D_HIT_NONE(&hit)); /* Check that the radius is an exclusive upper bound */ @@ -403,6 +403,84 @@ test_single_segment(struct s2d_device* dev) CHK(s2d_scene_view_ref_put(view) == RES_OK); CHK(s2d_shape_ref_put(shape) == RES_OK); CHK(s2d_scene_ref_put(scn) == RES_OK); + + /* Check accuracy on a configuration whose analytic distance is known */ + FOR_EACH(a, 0, 19) { + const float amplitude = exp2f((float)a); + const float eps = 1e-6f * amplitude; + FOR_EACH(i, 0, 1000) { + float A[2], B[2], AB[2], N[2], hit_N[2]; + int n; + + /* Randomly generate a segment AB */ + FOR_EACH(n, 0, 2) + A[n] = (rand_canonic() - 0.5f) * amplitude; + do { + FOR_EACH(n, 0, 2) B[n] = (rand_canonic() - 0.5f) * amplitude; + } while (f2_eq_eps(A, B, eps)); + + f2_sub(AB, B, A); + f2(N, AB[1], -AB[0]); /* Left hand convention */ + f2_normalize(N, N); + + f2_set(vertices + 0, A); + f2_set(vertices + 2, B); + + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + + vdata.usage = S2D_POSITION; + vdata.type = S2D_FLOAT2; + vdata.get = line_segments_get_position; + desc.vertices = vertices; + desc.indices = indices; + CHK(s2d_line_segments_setup_indexed_vertices + (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK); + + CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); + + FOR_EACH(j, 0, 1000) { + float proj[2]; /* Projection of pos on the line */ + float u, h, tmp[2]; + + /* Randomly generate a pos not on the segment + * with know position wrt the problem: pos = A + u.AB + k.N */ + u = 3 * rand_canonic() - 1; + h = (2 * rand_canonic() - 1) * amplitude; + f2_add(proj, A, f2_mulf(proj, AB, u)); + f2_add(pos, proj, f2_mulf(pos, N, h)); + + /* Compute closest point */ + CHK(s2d_scene_view_closest_point(view, pos, (float)INF, NULL, &hit) + == RES_OK); + CHK(!S2D_HIT_NONE(&hit)); + CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr) + == RES_OK); + + /* Check result */ + if(u <= 0) { + const float d = f2_len(f2_sub(tmp, pos, A)); + CHK(f2_eq_eps(attr.value, A, eps)); + CHK(eq_epsf(hit.distance, d, eps)); + } + else if(u >= 1) { + const float d = f2_len(f2_sub(tmp, pos, B)); + CHK(f2_eq_eps(attr.value, B, eps)); + CHK(eq_epsf(hit.distance, d, eps)); + } else { + CHK(f2_eq_eps(attr.value, proj, eps)); + CHK(eq_epsf(hit.distance, fabsf(h), eps)); + } + f2_normalize(hit_N, hit.normal); + CHK(f2_eq_eps(N, hit_N, FLT_EPSILON)); + } + + CHK(s2d_scene_view_ref_put(view) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + } + } } /******************************************************************************* diff --git a/src/test_s2d_device.c b/src/test_s2d_device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_primitive.c b/src/test_s2d_primitive.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_raytrace.c b/src/test_s2d_raytrace.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "s2d.h" +#include "test_s2d_utils.h" + +#include <rsys/float2.h> +#include <rsys/float3.h> + +/******************************************************************************* + * Single segment test + ******************************************************************************/ +static void +test_single_segment(struct s2d_device* dev) +{ + struct s2d_vertex_data vdata = S2D_VERTEX_DATA_NULL; + struct line_segments_desc desc; + struct s2d_hit hit = S2D_HIT_NULL; + struct s2d_hit hit3 = S2D_HIT_NULL; + struct s2d_scene* scn = NULL; + struct s2d_scene_view* view = NULL; + struct s2d_shape* shape = NULL; + struct s2d_attrib attr; + float vertices[4]; + float v0[2], v1[2]; + float pos[2]; + size_t a, i, j; + unsigned indices[2] = {0, 1}; + + f2(vertices+0, -0.5f, -0.3f); + f2(vertices+2, -0.4f, 0.2f); + + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + + vdata.usage = S2D_POSITION; + vdata.type = S2D_FLOAT2; + vdata.get = line_segments_get_position; + desc.vertices = vertices; + desc.indices = indices; + CHK(s2d_line_segments_setup_indexed_vertices + (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK); + + CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); + + line_segments_get_position(0, v0, &desc); + line_segments_get_position(1, v1, &desc); + + CHK(s2d_scene_view_ref_put(view) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + + /* Check accuracy on a configuration whose analytic distance is known */ + FOR_EACH(a, 0, 16) { + const float amplitude = exp2f((float)a); + const float eps = 1e-6f * amplitude; + FOR_EACH(i, 0, 1000) { + float A[2], B[2], AB[2], N[2]; + int n; + + /* Randomly generate a segment AB */ + FOR_EACH(n, 0, 2) + A[n] = (rand_canonic() - 0.5f) * amplitude; + do { + FOR_EACH(n, 0, 2) B[n] = (rand_canonic() - 0.5f) * amplitude; + } while (f2_eq_eps(A, B, eps)); + + f2_sub(AB, B, A); + f2(N, -AB[1], AB[0]); + f2_normalize(N, N); + + f2_set(vertices + 0, A); + f2_set(vertices + 2, B); + + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); + CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); + + vdata.usage = S2D_POSITION; + vdata.type = S2D_FLOAT2; + vdata.get = line_segments_get_position; + desc.vertices = vertices; + desc.indices = indices; + CHK(s2d_line_segments_setup_indexed_vertices + (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK); + + CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); + + FOR_EACH(j, 0, 1000) { + float proj[2]; /* Projection of pos on the line */ + float u, h, l; + float dir[3], range[2] = { 0, FLT_MAX }; + + /* Randomly generate a pos not on the segment + * with know position wrt the problem: pos = A + u.AB + k.N */ + u = 1.2f * rand_canonic() - 0.1f; + h = (2 * rand_canonic() - 1) * amplitude; + f2_add(proj, A, f2_mulf(proj, AB, u)); + f2_add(pos, proj, f2_mulf(pos, N, h)); + + /* Raytrace from pos towards proj */ + f2_mulf(dir, N, (h > 0 ? -1.f : 1.f)); + CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) + == RES_OK); + dir[2] = rand_canonic() - 0.5f; + l = f3_normalize(dir, dir); + CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit3) + == RES_OK); + + /* Check result */ + if(u < 0 || u > 1) { + if(!S2D_HIT_NONE(&hit) || !S2D_HIT_NONE(&hit3)) + CHK(u >= -FLT_EPSILON && u <= 1 + FLT_EPSILON); + } else { + if(S2D_HIT_NONE(&hit) || S2D_HIT_NONE(&hit3)) + CHK(u <= FLT_EPSILON || u >= 1 - FLT_EPSILON); + } + if(!S2D_HIT_NONE(&hit)) { + CHK(eq_epsf(hit.distance, fabsf(h), eps)); + CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr) + == RES_OK); + CHK(f2_eq_eps(attr.value, proj, eps)); + } + if(!S2D_HIT_NONE(&hit3)) { + CHK(eq_epsf(hit3.distance, l * fabsf(h), eps)); + CHK(s2d_primitive_get_attrib(&hit3.prim, S2D_POSITION, hit3.u, &attr) + == RES_OK); + CHK(f2_eq_eps(attr.value, proj, eps)); + } + } + + CHK(s2d_scene_view_ref_put(view) == RES_OK); + CHK(s2d_shape_ref_put(shape) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); + } + } +} + +/******************************************************************************* + * Miscellaneous test + ******************************************************************************/ +static void +test_api(struct s2d_device* dev) +{ + struct s2d_hit hit = S2D_HIT_NULL; + struct s2d_scene* scn = NULL; + struct s2d_scene_view* view = NULL; + float pos[3] = { 0 }, dir[3] = { 1 }, range[2] = { 0, 1 }; + + CHK(s2d_scene_create(dev, &scn) == RES_OK); + CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); + + CHK(s2d_scene_view_trace_ray(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit)); + + CHK(s2d_scene_view_trace_ray_3d(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray_3d(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray_3d(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG); + CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit) == RES_OK); + CHK(S2D_HIT_NONE(&hit)); + + CHK(s2d_scene_view_ref_put(view) == RES_OK); + CHK(s2d_scene_view_create(scn, S2D_SAMPLE, &view) == RES_OK); + CHK(s2d_scene_view_closest_point(view, pos, 1.f, NULL, &hit) == RES_BAD_OP); + + CHK(s2d_scene_view_ref_put(view) == RES_OK); + CHK(s2d_scene_ref_put(scn) == RES_OK); +} + +/******************************************************************************* + * Main function + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct s2d_device* dev = NULL; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + + test_api(dev); + test_single_segment(dev); + + CHK(s2d_device_ref_put(dev) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_s2d_sample.c b/src/test_s2d_sample.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -120,7 +120,7 @@ main(int argc, char** argv) struct s2d_attrib attr_normal; const float u = rand_canonic(); const float v = rand_canonic(); - float N[2], P[2]; + float N[2], P[2], tmp[2]; CHK(s2d_scene_view_sample(scnview, u, v, &prim, &s) == RES_OK); CHK(S2D_PRIMITIVE_EQ(&prim, &S2D_PRIMITIVE_NULL) == 0); @@ -141,7 +141,7 @@ main(int argc, char** argv) case 3: f2(P, 1.f, -1.f*s + (1-s)* 1.f); f2(N,-1.f, 0.f); break; default: CHK(0 == 1); break; /* Invalid primitive id */ } - + f2_add(P, P, f2_splat(tmp, 10)); CHK(f2_eq_eps(P, attr_position.value, 1.e-6f)); CHK(f2_eq_eps(N, attr_normal.value, 1.e-6f)); } diff --git a/src/test_s2d_scene.c b/src/test_s2d_scene.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -128,8 +128,8 @@ main(int argc, char** argv) CHK(eq_epsf(area, 4.f, 1.e-6f)); CHK(s2d_scene_view_get_aabb(scnview, lower, upper) == RES_OK); - CHK(f2_eq_eps(lower, f2(tmp, -1.f, -1.f), 1.e-6f)); - CHK(f2_eq_eps(upper, f2(tmp, 1.f, 1.f), 1.e-6f)); + CHK(f2_eq_eps(lower, f2(tmp, 9.f, 9.f), 1.e-6f)); + CHK(f2_eq_eps(upper, f2(tmp, 11.f, 11.f), 1.e-6f)); CHK(s2d_scene_view_ref_put(scnview) == RES_OK); diff --git a/src/test_s2d_scene_view.c b/src/test_s2d_scene_view.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -110,7 +110,7 @@ test_trace_ray CHK(s2d_scene_view_create(scn, S2D_SAMPLE|S2D_GET_PRIMITIVE, &scnview) == RES_OK); - f2(org, 0.f, -0.25f); + f2(org, 10.f, 9.75f); f2(dir, 0.f, 1.f); f2(range, 0.f, FLT_MAX); CHK(s2d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit) == RES_BAD_OP); @@ -454,24 +454,24 @@ test_aabb CHK(s2d_scene_view_get_aabb(scnview, lower, NULL) == RES_BAD_ARG); CHK(s2d_scene_view_get_aabb(NULL, lower, upper) == RES_BAD_ARG); CHK(s2d_scene_view_get_aabb(scnview, lower, upper) == RES_OK); - CHK(lower[0] == -1.f && upper[0] == 1.f); - CHK(lower[1] == -1.f && upper[1] == 1.f); + CHK(lower[0] == 9.f && upper[0] == 11.f); + CHK(lower[1] == 9.f && upper[1] == 11.f); CHK(s2d_shape_enable(square, 0) == RES_OK); CHK(s2d_scene_view_get_aabb(scnview, lower, upper) == RES_OK); - CHK(lower[0] == -1.f && upper[0] == 1.f); - CHK(lower[1] == -1.f && upper[1] == 1.f); + CHK(lower[0] == 9.f && upper[0] == 11.f); + CHK(lower[1] == 9.f && upper[1] == 11.f); CHK(s2d_scene_view_ref_put(scnview) == RES_OK); CHK(s2d_scene_view_create(scn, S2D_GET_PRIMITIVE, &scnview) == RES_OK); CHK(s2d_scene_view_get_aabb(scnview, lower, upper) == RES_OK); - CHK(lower[0] == -1.f && upper[0] == 1.f); - CHK(lower[1] == 0.f && upper[1] == 0.f); + CHK(lower[0] == 9.f && upper[0] == 11.f); + CHK(lower[1] == 10.f && upper[1] == 10.f); CHK(s2d_scene_detach_shape(scn, line) == RES_OK); CHK(s2d_scene_view_get_aabb(scnview, lower, upper) == RES_OK); - CHK(lower[0] == -1.f && upper[0] == 1.f); - CHK(lower[1] == 0.f && upper[1] == 0.f); + CHK(lower[0] == 9.f && upper[0] == 11.f); + CHK(lower[1] == 10.f && upper[1] == 10.f); CHK(s2d_scene_view_ref_put(scnview) == RES_OK); CHK(s2d_scene_view_create(scn, S2D_GET_PRIMITIVE, &scnview) == RES_OK); diff --git a/src/test_s2d_scene_view2.c b/src/test_s2d_scene_view2.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_shape.c b/src/test_s2d_shape.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, diff --git a/src/test_s2d_trace_ray.c b/src/test_s2d_trace_ray.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -84,7 +84,7 @@ main(int argc, char** argv) CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); - f2(org, 0.f, 0.f); + f2(org, 10.f, 10.f); f2(dir, 0.f, -1.f); f2(range, 0, FLT_MAX); @@ -164,7 +164,7 @@ main(int argc, char** argv) prim2 = hit.prim; - f2(org, 0.f, 2.f); + f2(org, 10.f, 12.f); f2(dir, 0.f, -1.f); CHK(RT(scnview, org, dir, range, NULL, &hit) == RES_OK); CHK(S2D_HIT_NONE(&hit) == 0); @@ -174,7 +174,7 @@ main(int argc, char** argv) CHK(S2D_HIT_NONE(&hit) == 0); CHK(S2D_PRIMITIVE_EQ(&hit.prim, &prim) == 1); - f2_splat(org, 0.f); + f2_splat(org, 10.f); f2(dir, 1.f, 0.f); CHK(RT(scnview, org, dir, range, NULL, &hit) == RES_OK); CHK(S2D_HIT_NONE(&hit) == 0); @@ -195,21 +195,21 @@ main(int argc, char** argv) CHK(s2d_scene_view_ref_put(scnview) == RES_OK); CHK(s2d_scene_view_create(scn, S2D_TRACE, &scnview) == RES_OK); - f2_sub(dir, f2(dir, 0.75f, -1.f), org); + f2(dir, 0.75f, -1.f); f2_normalize(dir, dir); CHK(RT(scnview, org, dir, range, NULL, &hit) == RES_OK); CHK(S2D_HIT_NONE(&hit) == 0); CHK(eq_epsf(hit.u, 0.125f, 1.e-6f) == 1); CHK(eq_epsf(hit.distance, 1.25, 1.E-6f) == 1); - f2_sub(dir, f2(dir, -1.f, 0.25f), org); + f2(dir, -1.f, 0.25f); f2_normalize(dir, dir); CHK(RT(scnview, org, dir, range, NULL, &hit) == RES_OK); CHK(S2D_HIT_NONE(&hit) == 0); CHK(eq_epsf(hit.u, 0.625, 1.e-6f) == 1); CHK(eq_epsf(hit.distance, (float)sqrt(1.0625f), 1e-6f) == 1); - f2(org, -1.25f, 0.f); + f2(org, 8.75f, 10.f); f2(dir, -1, 0.f); CHK(RT(scnview, org, dir, range, NULL, &hit) == RES_OK); CHK(S2D_HIT_NONE(&hit) == 1); diff --git a/src/test_s2d_trace_ray_3d.c b/src/test_s2d_trace_ray_3d.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -63,7 +63,7 @@ main(int argc, char** argv) (shape, square_nsegs, line_segments_get_ids, square_nverts, &vdata, 1, (void*)&square_desc) == RES_OK); - f3_splat(org, 0.f); + f3_splat(org, 10.f); f3(dir, 1, 0, 0); f2(range, 0, FLT_MAX); diff --git a/src/test_s2d_utils.h b/src/test_s2d_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com) * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, @@ -41,10 +41,10 @@ struct line_segments_desc { * Geometries ******************************************************************************/ static const float square_verts[] = { - 1.f, -1.f, - -1.f, -1.f, - -1.f, 1.f, - 1.f, 1.f + 11.f, 9.f, + 9.f, 9.f, + 9.f, 11.f, + 11.f, 11.f }; const unsigned square_nverts = sizeof(square_verts)/sizeof(float[2]); @@ -58,7 +58,7 @@ const unsigned square_nsegs = sizeof(square_ids)/sizeof(unsigned[2]); static const struct line_segments_desc square_desc = { square_verts, square_ids }; -static const float line_verts[] = { -1.f, 0.f, 1.f, 0.f }; +static const float line_verts[] = { 9.f, 10.f, 11.f, 10.f }; const unsigned line_nverts = sizeof(line_verts)/sizeof(float[2]); const unsigned line_ids[] = { 0, 1 }; const unsigned line_nsegs = sizeof(line_ids)/sizeof(unsigned[2]);