/** * Same as #interp_v3_v3v3_slerp buy uses fallback values * for opposite vectors. */ void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t) { if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, b, t))) { /* axis are aligned so any otho vector is acceptable */ float ab_ortho[3]; ortho_v3_v3(ab_ortho, a); normalize_v3(ab_ortho); if (t < 0.5f) { if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, ab_ortho, t * 2.0f))) { BLI_assert(0); copy_v3_v3(target, a); } } else { if (UNLIKELY(!interp_v3_v3v3_slerp(target, ab_ortho, b, (t - 0.5f) * 2.0f))) { BLI_assert(0); copy_v3_v3(target, b); } } } }
/** * Specialized slerp that uses a sphere defined by each points normal. */ static void interp_slerp_co_no_v3( const float co_a[3], const float no_a[3], const float co_b[3], const float no_b[3], const float no_dir[3], /* caller already knows, avoid normalize */ float fac, float r_co[3]) { /* center of the sphere defined by both normals */ float center[3]; BLI_assert(len_squared_v3v3(no_a, no_b) != 0); /* calculate sphere 'center' */ { /* use point on plane to */ float plane_a[4], plane_b[4], plane_c[4]; float no_mid[3], no_ortho[3]; /* pass this as an arg instead */ #if 0 float no_dir[3]; #endif float v_a_no_ortho[3], v_b_no_ortho[3]; add_v3_v3v3(no_mid, no_a, no_b); normalize_v3(no_mid); #if 0 sub_v3_v3v3(no_dir, co_a, co_b); normalize_v3(no_dir); #endif /* axis of slerp */ cross_v3_v3v3(no_ortho, no_mid, no_dir); normalize_v3(no_ortho); /* create planes */ cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a); cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b); project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho); project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho); plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho); plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho); plane_from_point_normal_v3(plane_c, co_b, no_ortho); /* find the sphere center from 3 planes */ if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) { /* pass */ } else { mid_v3_v3v3(center, co_a, co_b); } } /* calculate the final output 'r_co' */ { float ofs_a[3], ofs_b[3], ofs_slerp[3]; float dist_a, dist_b; sub_v3_v3v3(ofs_a, co_a, center); sub_v3_v3v3(ofs_b, co_b, center); dist_a = normalize_v3(ofs_a); dist_b = normalize_v3(ofs_b); if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) { madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac)); } else { interp_v3_v3v3(r_co, co_a, co_b, fac); } } }