Math Lib: less complex convex quad check

This commit is contained in:
Campbell Barton
2016-03-11 23:41:50 +11:00
parent 59c47ecf90
commit 8accc19d5d

View File

@@ -4837,55 +4837,62 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
return contrib; return contrib;
} }
/* evaluate if entire quad is a proper convex quad */ /**
* Evaluate if entire quad is a proper convex quad
*/
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{ {
float nor[3], nor_a[3], nor_b[3], vec[4][2]; /**
float mat[3][3]; * Method projects points onto a plane and checks its convex using following method:
const bool is_ok_a = (normal_tri_v3(nor_a, v1, v2, v3) > FLT_EPSILON); *
const bool is_ok_b = (normal_tri_v3(nor_b, v1, v3, v4) > FLT_EPSILON); * - Create a plane from the cross-product of both diagonal vectors.
* - Project all points onto the plane.
* - Subtract for direction vectors.
* - Return true if all corners cross-products have the same relative direction as the plane
* (all positive or all negative).
*/
/* define projection, do both trias apart, quad is undefined! */ /* non-unit length normal, used as a projection plane */
float plane[3];
/* check normal length incase one size is zero area */ {
if (is_ok_a) { float v13[3], v24[3];
if (is_ok_b) {
/* use both, most common outcome */
/* when the face is folded over as 2 tris we probably don't want to create sub_v3_v3v3(v13, v1, v3);
* a quad from it, but go ahead with the intersection test since this sub_v3_v3v3(v24, v2, v4);
* isn't a function for degenerate faces */
if (UNLIKELY(dot_v3v3(nor_a, nor_b) < 0.0f)) {
/* flip so adding normals in the opposite direction
* doesn't give a zero length vector */
negate_v3(nor_b);
}
add_v3_v3v3(nor, nor_a, nor_b); cross_v3_v3v3(plane, v13, v24);
normalize_v3(nor);
} if (len_squared_v3(plane) < FLT_EPSILON) {
else { return false;
copy_v3_v3(nor, nor_a); /* only 'a' */
}
}
else {
if (is_ok_b) {
copy_v3_v3(nor, nor_b); /* only 'b' */
}
else {
return false; /* both zero, we can't do anything useful here */
} }
} }
axis_dominant_v3_to_m3(mat, nor); const float *quad_coords[4] = {v1, v2, v3, v4};
float quad_proj[4][3];
mul_v2_m3v3(vec[0], mat, v1); for (int i = 0; i < 4; i++) {
mul_v2_m3v3(vec[1], mat, v2); project_plane_v3_v3v3(quad_proj[i], quad_coords[i], plane);
mul_v2_m3v3(vec[2], mat, v3); }
mul_v2_m3v3(vec[3], mat, v4);
/* linetests, the 2 diagonals have to instersect to be convex */ float quad_dirs[4][3];
return (isect_seg_seg_v2(vec[0], vec[2], vec[1], vec[3]) > 0); for (int i = 0, j = 3; i < 4; j = i++) {
sub_v3_v3v3(quad_dirs[i], quad_proj[i], quad_proj[j]);
}
int test;
float test_dir[3];
#define CROSS_SIGNUM(dir_a, dir_b) \
((void)cross_v3_v3v3(test_dir, dir_a, dir_b), signum_i(dot_v3v3(plane, test_dir)))
/* first assignment, then compare all others match */
return ((test = CROSS_SIGNUM(quad_dirs[0], quad_dirs[1])) &&
(test == CROSS_SIGNUM(quad_dirs[1], quad_dirs[2])) &&
(test == CROSS_SIGNUM(quad_dirs[2], quad_dirs[3])) &&
(test == CROSS_SIGNUM(quad_dirs[3], quad_dirs[0])));
#undef CROSS_SIGNUM
} }
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])