From ec8e0336a99b5affc68ec38c65bbfb176a54ddbe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 23 Jun 2015 20:28:32 +1000 Subject: [PATCH] Cleanup: use 2d math funcs for line intersection --- source/blender/blenlib/BLI_math_geom.h | 2 +- source/blender/blenlib/intern/math_geom.c | 89 +++++++++++++---------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 4a75e83316e..b7a6f39473b 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -142,7 +142,7 @@ int isect_line_line_v2(const float a1[2], const float a2[2], const float b1[2], int isect_line_line_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]); int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3]); int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2]); -int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], float vi[2]); +int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]); bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); int isect_line_line_epsilon_v3( diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index f74e3114fb1..8754ad1a2ba 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -697,37 +697,55 @@ int isect_line_line_v2(const float v1[2], const float v2[2], const float v3[2], * -1: collinear * 1: intersection */ -int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], float vi[2]) +int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]) { - float a1, a2, b1, b2, c1, c2, d; - float u, v; + float s10[2], s32[2], s30[2], d; const float eps = 1e-6f; const float eps_sq = eps * eps; - a1 = v2[0] - v1[0]; - b1 = v4[0] - v3[0]; - c1 = v1[0] - v4[0]; + sub_v2_v2v2(s10, v1, v0); + sub_v2_v2v2(s32, v3, v2); + sub_v2_v2v2(s30, v3, v0); - a2 = v2[1] - v1[1]; - b2 = v4[1] - v3[1]; - c2 = v1[1] - v4[1]; + d = cross_v2v2(s10, s32); - d = a1 * b2 - a2 * b1; + if (d != 0) { + float u, v; - if (d == 0) { - if (a1 * c2 - a2 * c1 == 0.0f && b1 * c2 - b2 * c1 == 0.0f) { /* equal lines */ - float a[2], b[2], c[2]; - float u2; + u = cross_v2v2(s30, s32) / d; + v = cross_v2v2(s10, s30) / d; - if (equals_v2v2(v1, v2)) { - if (len_squared_v2v2(v3, v4) > eps_sq) { + if ((u >= -eps && u <= 1.0f + eps) && + (v >= -eps && v <= 1.0f + eps)) + { + /* intersection */ + madd_v2_v2v2fl(r_vi, v0, s10, u); + return 1; + } + + /* out of segment intersection */ + return -1; + } + else { + if ((cross_v2v2(s10, s30) == 0.0f) && + (cross_v2v2(s32, s30) == 0.0f)) + { + /* equal lines */ + float s20[2]; + float u_a, u_b; + + if (equals_v2v2(v0, v1)) { + if (len_squared_v2v2(v2, v3) > eps_sq) { /* use non-point segment as basis */ + SWAP(const float *, v0, v2); SWAP(const float *, v1, v3); - SWAP(const float *, v2, v4); + + sub_v2_v2v2(s10, v1, v0); + sub_v2_v2v2(s30, v3, v0); } else { /* both of segments are points */ - if (equals_v2v2(v1, v3)) { /* points are equal */ - copy_v2_v2(vi, v1); + if (equals_v2v2(v0, v2)) { /* points are equal */ + copy_v2_v2(r_vi, v0); return 1; } @@ -736,19 +754,21 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[ } } - sub_v2_v2v2(a, v3, v1); - sub_v2_v2v2(b, v2, v1); - sub_v2_v2v2(c, v2, v1); - u = dot_v2v2(a, b) / dot_v2v2(c, c); + sub_v2_v2v2(s20, v2, v0); - sub_v2_v2v2(a, v4, v1); - u2 = dot_v2v2(a, b) / dot_v2v2(c, c); + u_a = dot_v2v2(s20, s10) / dot_v2v2(s10, s10); + u_b = dot_v2v2(s30, s10) / dot_v2v2(s10, s10); - if (u > u2) SWAP(float, u, u2); + if (u_a > u_b) + SWAP(float, u_a, u_b); - if (u > 1.0f + eps || u2 < -eps) return -1; /* non-ovlerlapping segments */ - else if (max_ff(0.0f, u) == min_ff(1.0f, u2)) { /* one common point: can return result */ - interp_v2_v2v2(vi, v1, v2, max_ff(0, u)); + if (u_a > 1.0f + eps || u_b < -eps) { + /* non-overlapping segments */ + return -1; + } + else if (max_ff(0.0f, u_a) == min_ff(1.0f, u_b)) { + /* one common point: can return result */ + madd_v2_v2v2fl(r_vi, v0, s10, max_ff(0, u_a)); return 1; } } @@ -756,17 +776,6 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[ /* lines are collinear */ return -1; } - - u = (c2 * b1 - b2 * c1) / d; - v = (c1 * a2 - a1 * c2) / d; - - if (u >= -eps && u <= 1.0f + eps && v >= -eps && v <= 1.0f + eps) { /* intersection */ - interp_v2_v2v2(vi, v1, v2, u); - return 1; - } - - /* out of segment intersection */ - return -1; } bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])