commit f49564ed4db5ef5d670cc656c346e16c59b046db
parent 61bf2f7516ab20d5176f3e6f98367910c995704f
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 18 Dec 2020 17:02:00 +0100
BugFix: closest point returned wrong hit
Diffstat:
2 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/src/s2d_scene_view_closest_point.c b/src/s2d_scene_view_closest_point.c
@@ -61,7 +61,7 @@ closest_point_segment
/* Orthogonally project the point onto the segment */
f2_sub(v, p, v0);
segment_len = f2_len(E);
- dst = f2_dot(v, E);
+ dst = f2_dot(v, E) / segment_len;
/* Check if the closest point is the segment vertex 'v0' */
if(dst <= 0) {
@@ -75,8 +75,9 @@ closest_point_segment
}
/* 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 / segment_len;
+ ASSERT(*s == CLAMP(*s, 0, 1));
+ return f2_add(closest_pt, f2_mulf(closest_pt, E, *s), v0);
}
static bool
diff --git a/src/test_s2d_closest_point.c b/src/test_s2d_closest_point.c
@@ -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);
@@ -366,7 +366,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,7 +383,7 @@ 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;
@@ -403,6 +403,52 @@ 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];
+ /* Randomly generate a segment AB on the X axis */
+ A[0] = -5 + rand_canonic() * 10;
+ B[0] = -5 + rand_canonic() * 10;
+ 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);
+ pos[0] = 0; pos[1] = 1;
+ 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, 1.e-4f));
+ if(A[0] > pos[0] && B[0] > pos[0]) {
+ CHK(f2_eq_eps(closest_pos, (A[0] > B[0] ? B : A), 1.e-4f));
+ }
+ else if(A[0] < pos[0] && B[0] < pos[0]) {
+ CHK(f2_eq_eps(closest_pos, (A[0] < B[0] ? B : A), 1.e-4f));
+ } else {
+ float expected[2] = { 0, 0 };
+ CHK(f2_eq_eps(closest_pos, expected, 1.e-4f));
+ }
+
+ 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);
+ }
}
/*******************************************************************************