diff options
Diffstat (limited to 'source/blender/blenlib/intern/math_geom.c')
-rw-r--r-- | source/blender/blenlib/intern/math_geom.c | 230 |
1 files changed, 197 insertions, 33 deletions
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index bfe1aefcbbd..d3080e5530f 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -619,6 +619,152 @@ float dist_squared_ray_to_seg_v3( return len_squared_v3(t) - SQUARE(*r_depth); } +/* -------------------------------------------------------------------- */ +/** \name dist_squared_to_ray_to_aabb and helpers + * \{ */ + +void dist_squared_ray_to_aabb_v3_precalc( + struct DistRayAABB_Precalc *neasrest_precalc, + const float ray_origin[3], const float ray_direction[3]) +{ + copy_v3_v3(neasrest_precalc->ray_origin, ray_origin); + copy_v3_v3(neasrest_precalc->ray_direction, ray_direction); + + for (int i = 0; i < 3; i++) { + neasrest_precalc->ray_inv_dir[i] = + (neasrest_precalc->ray_direction[i] != 0.0f) ? + (1.0f / neasrest_precalc->ray_direction[i]) : FLT_MAX; + neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f); + } +} + +/** + * Returns the distance from a ray to a bound-box (projected on ray) + */ +float dist_squared_ray_to_aabb_v3( + const struct DistRayAABB_Precalc *data, + const float bb_min[3], const float bb_max[3], + float r_point[3], float *r_depth) +{ + // bool r_axis_closest[3]; + float local_bvmin[3], local_bvmax[3]; + if (data->sign[0]) { + local_bvmin[0] = bb_max[0]; + local_bvmax[0] = bb_min[0]; + } + else { + local_bvmin[0] = bb_min[0]; + local_bvmax[0] = bb_max[0]; + } + if (data->sign[1]) { + local_bvmin[1] = bb_max[1]; + local_bvmax[1] = bb_min[1]; + } + else { + local_bvmin[1] = bb_min[1]; + local_bvmax[1] = bb_max[1]; + } + if (data->sign[2]) { + local_bvmin[2] = bb_max[2]; + local_bvmax[2] = bb_min[2]; + } + else { + local_bvmin[2] = bb_min[2]; + local_bvmax[2] = bb_max[2]; + } + + const float tmin[3] = { + (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0], + (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1], + (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2], + }; + const float tmax[3] = { + (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0], + (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1], + (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2], + }; + /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */ + float va[3], vb[3]; + /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */ + float rtmin, rtmax; + int main_axis; + + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + rtmax = tmax[0]; + va[0] = vb[0] = local_bvmax[0]; + main_axis = 3; + // r_axis_closest[0] = data->sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + rtmax = tmax[1]; + va[1] = vb[1] = local_bvmax[1]; + main_axis = 2; + // r_axis_closest[1] = data->sign[1]; + } + else { + rtmax = tmax[2]; + va[2] = vb[2] = local_bvmax[2]; + main_axis = 1; + // r_axis_closest[2] = data->sign[2]; + } + + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + rtmin = tmin[0]; + va[0] = vb[0] = local_bvmin[0]; + main_axis -= 3; + // r_axis_closest[0] = !data->sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + rtmin = tmin[1]; + va[1] = vb[1] = local_bvmin[1]; + main_axis -= 1; + // r_axis_closest[1] = !data->sign[1]; + } + else { + rtmin = tmin[2]; + va[2] = vb[2] = local_bvmin[2]; + main_axis -= 2; + // r_axis_closest[2] = !data->sign[2]; + } + if (main_axis < 0) { + main_axis += 3; + } + + /* if rtmin <= rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { + float dvec[3]; + copy_v3_v3(r_point, local_bvmax); + sub_v3_v3v3(dvec, local_bvmax, data->ray_origin); + *r_depth = dot_v3v3(dvec, data->ray_direction); + return 0.0f; + } + + if (data->sign[main_axis]) { + va[main_axis] = local_bvmax[main_axis]; + vb[main_axis] = local_bvmin[main_axis]; + } + else { + va[main_axis] = local_bvmin[main_axis]; + vb[main_axis] = local_bvmax[main_axis]; + } + + return dist_squared_ray_to_seg_v3( + data->ray_origin, data->ray_direction, va, vb, + r_point, r_depth); +} + +float dist_squared_ray_to_aabb_v3_simple( + const float ray_origin[3], const float ray_direction[3], + const float bbmin[3], const float bbmax[3], + float r_point[3], float *r_depth) +{ + struct DistRayAABB_Precalc data; + dist_squared_ray_to_aabb_v3_precalc(&data, ray_origin, ray_direction); + return dist_squared_ray_to_aabb_v3(&data, bbmin, bbmax, r_point, r_depth); +} +/** \} */ + + /* Adapted from "Real-Time Collision Detection" by Christer Ericson, * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. * @@ -765,18 +911,29 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co return ISECT_LINE_LINE_NONE; } -/* get intersection point of two 2D segments and return intersection type: - * -1: collinear - * 1: intersection +/** + * Get intersection point of two 2D segments. + * + * \param endpoint_bias: Bias to use when testing for end-point overlap. + * A positive value considers intersections that extend past the endpoints, + * negative values contract the endpoints. + * Note the bias is applied to a 0-1 factor, not scaled to the length of segments. + * + * \returns intersection type: + * - -1: collinear. + * - 1: intersection. + * - 0: no intersection. */ -int isect_seg_seg_v2_point( +int isect_seg_seg_v2_point_ex( const float v0[2], const float v1[2], const float v2[2], const float v3[2], + const float endpoint_bias, float r_vi[2]) { float s10[2], s32[2], s30[2], d; const float eps = 1e-6f; - const float eps_sq = eps * eps; + const float endpoint_min = -endpoint_bias; + const float endpoint_max = endpoint_bias + 1.0f; sub_v2_v2v2(s10, v1, v0); sub_v2_v2v2(s32, v3, v2); @@ -790,8 +947,8 @@ int isect_seg_seg_v2_point( u = cross_v2v2(s30, s32) / d; v = cross_v2v2(s10, s30) / d; - if ((u >= -eps && u <= 1.0f + eps) && - (v >= -eps && v <= 1.0f + eps)) + if ((u >= endpoint_min && u <= endpoint_max) && + (v >= endpoint_min && v <= endpoint_max)) { /* intersection */ float vi_test[2]; @@ -810,7 +967,7 @@ int isect_seg_seg_v2_point( sub_v2_v2v2(s_vi_v2, vi_test, v2); v = (dot_v2v2(s32, s_vi_v2) / dot_v2v2(s32, s32)); #endif - if (v >= -eps && v <= 1.0f + eps) { + if (v >= endpoint_min && v <= endpoint_max) { copy_v2_v2(r_vi, vi_test); return 1; } @@ -828,7 +985,7 @@ int isect_seg_seg_v2_point( float u_a, u_b; if (equals_v2v2(v0, v1)) { - if (len_squared_v2v2(v2, v3) > eps_sq) { + if (len_squared_v2v2(v2, v3) > SQUARE(eps)) { /* use non-point segment as basis */ SWAP(const float *, v0, v2); SWAP(const float *, v1, v3); @@ -855,7 +1012,7 @@ int isect_seg_seg_v2_point( if (u_a > u_b) SWAP(float, u_a, u_b); - if (u_a > 1.0f + eps || u_b < -eps) { + if (u_a > endpoint_max || u_b < endpoint_min) { /* non-overlapping segments */ return -1; } @@ -871,6 +1028,15 @@ int isect_seg_seg_v2_point( } } +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]) +{ + const float endpoint_bias = 1e-6f; + return isect_seg_seg_v2_point_ex(v0, v1, v2, v3, endpoint_bias, r_vi); +} + bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) { #define CCW(A, B, C) \ @@ -3887,7 +4053,7 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const f /********************************* Normals **********************************/ -void accumulate_vertex_normals_tri( +void accumulate_vertex_normals_tri_v3( float n1[3], float n2[3], float n3[3], const float f_no[3], const float co1[3], const float co2[3], const float co3[3]) @@ -3921,7 +4087,7 @@ void accumulate_vertex_normals_tri( } } -void accumulate_vertex_normals( +void accumulate_vertex_normals_v3( float n1[3], float n2[3], float n3[3], float n4[3], const float f_no[3], const float co1[3], const float co2[3], const float co3[3], const float co4[3]) @@ -3965,7 +4131,7 @@ void accumulate_vertex_normals( /* Add weighted face normal component into normals of the face vertices. * Caller must pass pre-allocated vdiffs of nverts length. */ -void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3], +void accumulate_vertex_normals_poly_v3(float **vertnos, const float polyno[3], const float **vertcos, float vdiffs[][3], const int nverts) { int i; @@ -3996,7 +4162,7 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3], /********************************* Tangents **********************************/ -void tangent_from_uv( +void tangent_from_uv_v3( const float uv1[2], const float uv2[2], const float uv3[3], const float co1[3], const float co2[3], const float co3[3], const float n[3], @@ -4038,30 +4204,28 @@ void tangent_from_uv( /****************************** Vector Clouds ********************************/ /* vector clouds */ -/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight, - * float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) - * +/** * input - * ( - * int list_size - * 4 lists as pointer to array[list_size] - * 1. current pos array of 'new' positions - * 2. current weight array of 'new'weights (may be NULL pointer if you have no weights ) - * 3. reference rpos array of 'old' positions - * 4. reference rweight array of 'old'weights (may be NULL pointer if you have no weights ) - * ) + * + * \param list_size: 4 lists as pointer to array[list_size] + * \param pos: current pos array of 'new' positions + * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights) + * \param rpos: Reference rpos array of 'old' positions + * \param rweight: Reference rweight array of 'old'weights (may be NULL pointer if you have no weights). + * * output - * ( - * float lloc[3] center of mass pos - * float rloc[3] center of mass rpos - * float lrot[3][3] rotation matrix - * float lscale[3][3] scale matrix + * + * \param lloc: Center of mass pos. + * \param rloc: Center of mass rpos. + * \param lrot: Rotation matrix. + * \param lscale: Scale matrix. + * * pointers may be NULL if not needed - * ) */ -void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight, - float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) +void vcloud_estimate_transform_v3( + const int list_size, const float (*pos)[3], const float *weight, const float (*rpos)[3], const float *rweight, + float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) { float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f}; float accu_weight = 0.0f, accu_rweight = 0.0f; |