diff options
Diffstat (limited to 'source/blender/blenlib/intern/math_geom.c')
-rw-r--r-- | source/blender/blenlib/intern/math_geom.c | 121 |
1 files changed, 100 insertions, 21 deletions
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index c4bdc73e0e3..6d8193e7675 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -1356,6 +1356,52 @@ bool isect_seg_seg_v2_simple(const float v1[2], } /** + * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE: + * <pre> + * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3) + * </pre> + * \returns intersection type: + * - ISECT_LINE_LINE_COLINEAR: collinear. + * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either. + * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint. + * - ISECT_LINE_LINE_NONE: no intersection. + * Also returns lambda and mu in r_lambda and r_mu. + */ +int isect_seg_seg_v2_lambda_mu_db(const double v1[2], + const double v2[2], + const double v3[2], + const double v4[2], + double *r_lambda, + double *r_mu) +{ + double div, lambda, mu; + + div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]); + if (fabs(div) < DBL_EPSILON) { + return ISECT_LINE_LINE_COLINEAR; + } + + lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div; + + mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div; + + if (r_lambda) { + *r_lambda = lambda; + } + if (r_mu) { + *r_mu = mu; + } + + if (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) { + if (lambda == 0.0 || lambda == 1.0 || mu == 0.0 || mu == 1.0) { + return ISECT_LINE_LINE_EXACT; + } + return ISECT_LINE_LINE_CROSS; + } + return ISECT_LINE_LINE_NONE; +} + +/** * \param l1, l2: Coordinates (point of line). * \param sp, r: Coordinate and radius (sphere). * \return r_p1, r_p2: Intersection coordinates. @@ -3011,19 +3057,21 @@ bool isect_line_line_strict_v3(const float v1[3], * * \note Neither directions need to be normalized. */ -bool isect_ray_ray_v3(const float ray_origin_a[3], - const float ray_direction_a[3], - const float ray_origin_b[3], - const float ray_direction_b[3], - float *r_lambda_a, - float *r_lambda_b) +bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3], + const float ray_direction_a[3], + const float ray_origin_b[3], + const float ray_direction_b[3], + const float epsilon, + float *r_lambda_a, + float *r_lambda_b) { BLI_assert(r_lambda_a || r_lambda_b); float n[3]; cross_v3_v3v3(n, ray_direction_b, ray_direction_a); const float nlen = len_squared_v3(n); - if (UNLIKELY(nlen == 0.0f)) { + /* `nlen` is the the square of the area formed by the two vectors. */ + if (UNLIKELY(nlen < epsilon)) { /* The lines are parallel. */ return false; } @@ -3045,6 +3093,22 @@ bool isect_ray_ray_v3(const float ray_origin_a[3], return true; } +bool isect_ray_ray_v3(const float ray_origin_a[3], + const float ray_direction_a[3], + const float ray_origin_b[3], + const float ray_direction_b[3], + float *r_lambda_a, + float *r_lambda_b) +{ + return isect_ray_ray_epsilon_v3(ray_origin_a, + ray_direction_a, + ray_origin_b, + ray_direction_b, + FLT_MIN, + r_lambda_a, + r_lambda_b); +} + bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], @@ -3187,6 +3251,26 @@ float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], return lambda; } +double closest_to_line_v2_db(double r_close[2], + const double p[2], + const double l1[2], + const double l2[2]) +{ + double h[2], u[2], lambda, denom; + sub_v2_v2v2_db(u, l2, l1); + sub_v2_v2v2_db(h, p, l1); + denom = dot_v2v2_db(u, u); + if (denom < DBL_EPSILON) { + r_close[0] = l1[0]; + r_close[1] = l1[1]; + return 0.0; + } + lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u); + r_close[0] = l1[0] + u[0] * lambda; + r_close[1] = l1[1] + u[1] * lambda; + return lambda; +} + float ray_point_factor_v3_ex(const float p[3], const float ray_origin[3], const float ray_direction[3], @@ -4707,29 +4791,24 @@ void projmat_from_subregion(const float projmat[4][4], float rect_width = (float)(x_max - x_min); float rect_height = (float)(y_max - y_min); + float x_sca = (float)win_size[0] / rect_width; + float y_sca = (float)win_size[1] / rect_height; + float x_fac = (float)((x_min + x_max) - win_size[0]) / rect_width; float y_fac = (float)((y_min + y_max) - win_size[1]) / rect_height; copy_m4_m4(r_projmat, projmat); - r_projmat[0][0] *= (float)win_size[0] / rect_width; - r_projmat[1][1] *= (float)win_size[1] / rect_height; + r_projmat[0][0] *= x_sca; + r_projmat[1][1] *= y_sca; -#if 0 /* TODO: check if this is more efficient. */ - r_projmat[2][0] -= x_fac * r_projmat[2][3]; - r_projmat[2][1] -= y_fac * r_projmat[2][3]; - - r_projmat[3][0] -= x_fac * r_projmat[3][3]; - r_projmat[3][1] -= y_fac * r_projmat[3][3]; -#else if (projmat[3][3] == 0.0f) { - r_projmat[2][0] += x_fac; - r_projmat[2][1] += y_fac; + r_projmat[2][0] = r_projmat[2][0] * x_sca + x_fac; + r_projmat[2][1] = r_projmat[2][1] * y_sca + y_fac; } else { - r_projmat[3][0] -= x_fac; - r_projmat[3][1] -= y_fac; + r_projmat[3][0] = r_projmat[3][0] * x_sca - x_fac; + r_projmat[3][1] = r_projmat[3][1] * y_sca - y_fac; } -#endif } static void i_multmatrix(float icand[4][4], float Vm[4][4]) |