commit c7d9e8a3d80d7b944aaded0c7508bd0d5064267d
parent 521029ced8411fdfdae832bae693ad82ff01b110
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 12 Jan 2021 15:31:29 +0100
Continue improving accuracy tests
Diffstat:
2 files changed, 157 insertions(+), 128 deletions(-)
diff --git a/src/test_s2d_closest_point.c b/src/test_s2d_closest_point.c
@@ -332,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, j;
+ size_t a, i, j;
unsigned indices[2] = {0, 1};
f2(vertices+0, -0.5f, -0.3f);
@@ -386,7 +386,8 @@ test_single_segment(struct s2d_device* dev)
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 */
@@ -402,72 +403,81 @@ 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);
-
- FOR_EACH(i, 0, 100) {
- float A[2], B[2], tmp[2];
- const float amplitude = 10000;
+
+ /* 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;
- /* Randomly generate a segment AB on the X axis */
- A[0] = (rand_canonic() - 0.5f) * amplitude;
- do B[0] = (rand_canonic() - 0.5f) * amplitude;
- while(fabsf(A[0] - B[0]) < eps);
- A[1] = B[1] = 0;
-
- 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, 100) {
- /* Randomly generate a pos not on the segment */
- pos[0] = (rand_canonic() - 0.5f) * amplitude;
- do pos[1] = (rand_canonic() - 0.5f) * amplitude;
- while (fabsf(pos[1]) < 1e-5);
-
- /* 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);
-
- /* Cross check the closest point query result */
- closest_point_segment(pos, A, B, closest_pos);
- CHK(f2_eq_eps(closest_pos, attr.value, eps));
- if(A[0] > pos[0] && B[0] > pos[0]) {
- const float* X = (A[0] > B[0]) ? B : A;
- const float d = f2_len(f2_sub(tmp, pos, X));
- CHK(f2_eq_eps(closest_pos, X, eps));
- CHK(eq_epsf(hit.distance, d, eps));
- }
- else if(A[0] < pos[0] && B[0] < pos[0]) {
- const float* X = (A[0] < B[0]) ? B : A;
- const float d = f2_len(f2_sub(tmp, pos, X));
- CHK(f2_eq_eps(closest_pos, X, eps));
- CHK(eq_epsf(hit.distance, d, eps));
- } else {
- float expected[2];
- float d;
- f2(expected, pos[0], 0);
- d = f2_len(f2_sub(tmp, pos, expected));
- CHK(f2_eq_eps(closest_pos, expected, eps));
- CHK(eq_epsf(hit.distance, d, eps));
+ 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, 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));
+ }
}
- }
- 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);
+ 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_raytrace.c b/src/test_s2d_raytrace.c
@@ -49,7 +49,7 @@ test_single_segment(struct s2d_device* dev)
float vertices[4];
float v0[2], v1[2];
float pos[2];
- size_t i, j;
+ size_t a, i, j;
unsigned indices[2] = {0, 1};
f2(vertices+0, -0.5f, -0.3f);
@@ -75,71 +75,90 @@ 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);
-
- FOR_EACH(i, 0, 100) {
- float A[2], B[2], tmp[2];
- const float amplitude = 10000;
+
+ /* 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;
- /* Randomly generate a segment AB on the X axis */
- A[0] = (rand_canonic() - 0.5f) * amplitude;
- do B[0] = (rand_canonic() - 0.5f) * amplitude;
- while(fabsf(A[0] - B[0]) < eps);
- A[1] = B[1] = 0;
-
- 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, 100) {
- float l;
- float dir[3], range[2] = { 0, FLT_MAX };
-
- /* Randomly generate a pos not on the segment */
- pos[0] = (rand_canonic() - 0.5f) * amplitude;
- do pos[1] = (rand_canonic() - 0.5f) * amplitude;
- while (fabsf(pos[1]) < 1e-5);
-
- /* Raytrace towards the X axis (can hit or miss the segment) */
- f3(dir, 0, (pos[1] > 0 ? -1.f : 1.f), rand_canonic() - 0.5f);
- CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK);
- l = f3_normalize(dir, dir);
- CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit3) == RES_OK);
-
- /* Check the result */
- if((A[0] > pos[0] && B[0] > pos[0]) || (A[0] < pos[0] && B[0] < pos[0])) {
- CHK(S2D_HIT_NONE(&hit));
- CHK(S2D_HIT_NONE(&hit3));
- } else {
- float expected[2];
- float d = f2_len(f2_sub(tmp, pos, expected));
- f2(expected, pos[0], 0);
- d = f2_len(f2_sub(tmp, pos, expected));
- CHK(!S2D_HIT_NONE(&hit));
- CHK(eq_epsf(hit.distance, d, eps));
- CHK(eq_epsf(hit3.distance, d * l, eps));
- CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr) == RES_OK);
- CHK(f2_eq_eps(attr.value, expected, eps));
- CHK(s2d_primitive_get_attrib(&hit3.prim, S2D_POSITION, hit3.u, &attr) == RES_OK);
- CHK(f2_eq_eps(attr.value, expected, eps));
+ 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);
+ 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);
+ }
}
}