#include #include "angle.h" #include "versor.h" const BGC_FP32_Versor BGC_FP32_IDLE_VERSOR = { 1.0f, 0.0f, 0.0f, 0.0f }; const BGC_FP64_Versor BGC_FP64_IDLE_VERSOR = { 1.0, 0.0, 0.0, 0.0 }; extern inline void bgc_fp32_versor_reset(BGC_FP32_Versor* versor); extern inline void bgc_fp64_versor_reset(BGC_FP64_Versor* versor); extern inline void bgc_fp32_versor_make(const float s0, const float x1, const float x2, const float x3, BGC_FP32_Versor* versor); extern inline void bgc_fp64_versor_make(const double s0, const double x1, const double x2, const double x3, BGC_FP64_Versor* versor); extern inline void bgc_fp32_versor_make_for_rotation(const BGC_FP32_Rotation3* rotation, BGC_FP32_Versor* result); extern inline void bgc_fp64_versor_make_for_rotation(const BGC_FP64_Rotation3* rotation, BGC_FP64_Versor* result); extern inline void bgc_fp32_versor_copy(const BGC_FP32_Versor* source, BGC_FP32_Versor* destination); extern inline void bgc_fp64_versor_copy(const BGC_FP64_Versor* source, BGC_FP64_Versor* destination); extern inline void bgc_fp32_versor_swap(BGC_FP32_Versor* versor1, BGC_FP32_Versor* versor2); extern inline void bgc_fp64_versor_swap(BGC_FP64_Versor* versor1, BGC_FP64_Versor* versor2); extern inline int bgc_fp32_versor_is_idle(const BGC_FP32_Versor* versor); extern inline int bgc_fp64_versor_is_idle(const BGC_FP64_Versor* versor); extern inline void bgc_fp64_versor_convert_to_fp32(const BGC_FP64_Versor* source, BGC_FP32_Versor* destination); extern inline void bgc_fp32_versor_convert_to_fp64(const BGC_FP32_Versor* source, BGC_FP64_Versor* destination); extern inline void bgc_fp32_versor_shorten(BGC_FP32_Versor* versor); extern inline void bgc_fp64_versor_shorten(BGC_FP64_Versor* versor); extern inline void bgc_fp32_versor_get_shortened(const BGC_FP32_Versor* versor, BGC_FP32_Versor* shortened); extern inline void bgc_fp64_versor_get_shortened(const BGC_FP64_Versor* versor, BGC_FP64_Versor* shortened); extern inline void bgc_fp32_versor_alternate(BGC_FP32_Versor* versor); extern inline void bgc_fp64_versor_alternate(BGC_FP64_Versor* versor); extern inline void bgc_fp32_versor_get_alternative(const BGC_FP32_Versor* versor, BGC_FP32_Versor* opposite); extern inline void bgc_fp64_versor_get_alternative(const BGC_FP64_Versor* versor, BGC_FP64_Versor* opposite); extern inline void bgc_fp32_versor_revert(BGC_FP32_Versor* versor); extern inline void bgc_fp64_versor_revert(BGC_FP64_Versor* versor); extern inline void bgc_fp32_versor_get_reverse(const BGC_FP32_Versor* versor, BGC_FP32_Versor* inverse); extern inline void bgc_fp64_versor_get_reverse(const BGC_FP64_Versor* versor, BGC_FP64_Versor* inverse); extern inline void bgc_fp32_versor_combine(const BGC_FP32_Versor* first, const BGC_FP32_Versor* second, BGC_FP32_Versor* result); extern inline void bgc_fp64_versor_combine(const BGC_FP64_Versor* first, const BGC_FP64_Versor* second, BGC_FP64_Versor* result); extern inline void bgc_fp32_versor_combine3(const BGC_FP32_Versor* first, const BGC_FP32_Versor* second, const BGC_FP32_Versor* third, BGC_FP32_Versor* result); extern inline void bgc_fp64_versor_combine3(const BGC_FP64_Versor* first, const BGC_FP64_Versor* second, const BGC_FP64_Versor* third, BGC_FP64_Versor* result); extern inline void bgc_fp32_versor_exclude(const BGC_FP32_Versor* base, const BGC_FP32_Versor* excludant, BGC_FP32_Versor* difference); extern inline void bgc_fp64_versor_exclude(const BGC_FP64_Versor* base, const BGC_FP64_Versor* excludant, BGC_FP64_Versor* difference); extern inline void bgc_fp32_versor_get_rotation_matrix(const BGC_FP32_Versor* versor, BGC_FP32_Matrix3x3* matrix); extern inline void bgc_fp64_versor_get_rotation_matrix(const BGC_FP64_Versor* versor, BGC_FP64_Matrix3x3* matrix); extern inline void bgc_fp32_versor_get_reverse_matrix(const BGC_FP32_Versor* versor, BGC_FP32_Matrix3x3* matrix); extern inline void bgc_fp64_versor_get_reverse_matrix(const BGC_FP64_Versor* versor, BGC_FP64_Matrix3x3* matrix); extern inline void bgc_fp32_versor_get_both_matrices(const BGC_FP32_Versor* versor, BGC_FP32_Matrix3x3* rotation, BGC_FP32_Matrix3x3* reverse); extern inline void bgc_fp64_versor_get_both_matrices(const BGC_FP64_Versor* versor, BGC_FP64_Matrix3x3* rotation, BGC_FP64_Matrix3x3* reverse); extern inline void bgc_fp32_versor_turn_vector(const BGC_FP32_Versor* versor, const BGC_FP32_Vector3* vector, BGC_FP32_Vector3* result); extern inline void bgc_fp64_versor_turn_vector(const BGC_FP64_Versor* versor, const BGC_FP64_Vector3* vector, BGC_FP64_Vector3* result); extern inline void bgc_fp32_versor_turn_vector_back(const BGC_FP32_Versor* versor, const BGC_FP32_Vector3* vector, BGC_FP32_Vector3* result); extern inline void bgc_fp64_versor_turn_vector_back(const BGC_FP64_Versor* versor, const BGC_FP64_Vector3* vector, BGC_FP64_Vector3* result); extern inline int bgc_fp32_versor_are_close(const BGC_FP32_Versor* versor1, const BGC_FP32_Versor* versor2); extern inline int bgc_fp64_versor_are_close(const BGC_FP64_Versor* versor1, const BGC_FP64_Versor* versor2); // ================= Normalize ================== // void _bgc_fp32_versor_normalize(BGC_FP32_Versor* versor) { const float square_modulus = (versor->_s0 * versor->_s0 + versor->_x1 * versor->_x1) + (versor->_x2 * versor->_x2 + versor->_x3 * versor->_x3); if (square_modulus <= BGC_FP32_SQUARE_EPSYLON || isnan(square_modulus)) { versor->_s0 = 1.0f; versor->_x1 = 0.0f; versor->_x2 = 0.0f; versor->_x3 = 0.0f; return; } const float multiplier = sqrtf(1.0f / square_modulus); versor->_s0 *= multiplier; versor->_x1 *= multiplier; versor->_x2 *= multiplier; versor->_x3 *= multiplier; } void _bgc_fp64_versor_normalize(BGC_FP64_Versor* versor) { const double square_modulus = (versor->_s0 * versor->_s0 + versor->_x1 * versor->_x1) + (versor->_x2 * versor->_x2 + versor->_x3 * versor->_x3); if (square_modulus <= BGC_FP64_SQUARE_EPSYLON || isnan(square_modulus)) { versor->_s0 = 1.0; versor->_x1 = 0.0; versor->_x2 = 0.0; versor->_x3 = 0.0; return; } const double multiplier = sqrt(1.0 / square_modulus); versor->_s0 *= multiplier; versor->_x1 *= multiplier; versor->_x2 *= multiplier; versor->_x3 *= multiplier; } // ================== Set Turn ================== // void bgc_fp32_versor_make_for_turn(const float x1, const float x2, const float x3, const float angle, const int unit, BGC_FP32_Versor* result) { const float square_vector = x1 * x1 + x2 * x2 + x3 * x3; if (square_vector <= BGC_FP32_SQUARE_EPSYLON) { bgc_fp32_versor_reset(result); return; } const float half_angle = bgc_fp32_angle_to_radians(0.5f * angle, unit); const float sine = sinf(half_angle); if (bgc_fp32_is_zero(sine)) { bgc_fp32_versor_reset(result); return; } const float multiplier = sine / sqrtf(square_vector); bgc_fp32_versor_make(cosf(half_angle), x1 * multiplier, x2 * multiplier, x3 * multiplier, result); } void bgc_fp64_versor_make_for_turn(const double x1, const double x2, const double x3, const double angle, const int unit, BGC_FP64_Versor* result) { const double square_vector = x1 * x1 + x2 * x2 + x3 * x3; if (square_vector <= BGC_FP64_SQUARE_EPSYLON) { bgc_fp64_versor_reset(result); return; } const double half_angle = bgc_fp64_angle_to_radians(0.5 * angle, unit); const double sine = sin(half_angle); if (bgc_fp64_is_zero(sine)) { bgc_fp64_versor_reset(result); return; } const double multiplier = sine / sqrt(square_vector); bgc_fp64_versor_make(cos(half_angle), x1 * multiplier, x2 * multiplier, x3 * multiplier, result); } // ========= Make Direction Difference ========== // static int _bgc_fp32_versor_make_direction_turn(const BGC_FP32_Vector3* start, const BGC_FP32_Vector3* end, const float square_modulus_product, BGC_FP32_Versor* result) { BGC_FP32_Vector3 orthogonal_axis; bgc_fp32_vector3_get_cross_product(start, end, &orthogonal_axis); const float scalar_product = bgc_fp32_vector3_get_dot_product(start, end); const float square_modulus = bgc_fp32_vector3_get_square_modulus(&orthogonal_axis); const float square_sine = square_modulus / square_modulus_product; if (square_sine > BGC_FP32_SQUARE_EPSYLON) { const float cosine = scalar_product / sqrtf(square_modulus_product); const float angle = 0.5f * atan2f(sqrtf(square_sine), cosine); const float multiplier = sinf(angle) * sqrtf(1.0f / square_modulus); bgc_fp32_versor_make(cosf(angle), orthogonal_axis.x1 * multiplier, orthogonal_axis.x2 * multiplier, orthogonal_axis.x3 * multiplier, result); return BGC_SOME_TURN; } if (scalar_product < 0.0f) { return BGC_OPPOSITE; } bgc_fp32_versor_reset(result); return BGC_ZERO_TURN; } static int _bgc_fp64_versor_make_direction_turn(const BGC_FP64_Vector3* start, const BGC_FP64_Vector3* end, const double square_modulus_product, BGC_FP64_Versor* result) { BGC_FP64_Vector3 orthogonal_axis; bgc_fp64_vector3_get_cross_product(start, end, &orthogonal_axis); const double scalar_product = bgc_fp64_vector3_get_dot_product(start, end); const double square_modulus = bgc_fp64_vector3_get_square_modulus(&orthogonal_axis); const double square_sine = square_modulus / square_modulus_product; if (square_sine > BGC_FP64_SQUARE_EPSYLON) { const double cosine = scalar_product / sqrt(square_modulus_product); const double angle = 0.5 * atan2(sqrt(square_sine), cosine); const double multiplier = sin(angle) * sqrt(1.0f / square_modulus); bgc_fp64_versor_make(cos(angle), orthogonal_axis.x1 * multiplier, orthogonal_axis.x2 * multiplier, orthogonal_axis.x3 * multiplier, result); return BGC_SOME_TURN; } if (scalar_product < 0.0) { return BGC_OPPOSITE; } bgc_fp64_versor_reset(result); return BGC_ZERO_TURN; } int bgc_fp32_versor_make_direction_difference(const BGC_FP32_Vector3* start, const BGC_FP32_Vector3* end, BGC_FP32_Versor* result) { const float start_square_modulus = bgc_fp32_vector3_get_square_modulus(start); const float end_square_modulus = bgc_fp32_vector3_get_square_modulus(end); if (start_square_modulus <= BGC_FP32_SQUARE_EPSYLON || end_square_modulus <= BGC_FP32_SQUARE_EPSYLON) { bgc_fp32_versor_reset(result); return BGC_ZERO_TURN; } return _bgc_fp32_versor_make_direction_turn(start, end, start_square_modulus * end_square_modulus, result); } int bgc_fp64_versor_make_direction_difference(const BGC_FP64_Vector3* start, const BGC_FP64_Vector3* end, BGC_FP64_Versor* result) { const double start_square_modulus = bgc_fp64_vector3_get_square_modulus(start); const double end_square_modulus = bgc_fp64_vector3_get_square_modulus(end); if (start_square_modulus <= BGC_FP64_SQUARE_EPSYLON || end_square_modulus <= BGC_FP64_SQUARE_EPSYLON) { bgc_fp64_versor_reset(result); return BGC_ZERO_TURN; } return _bgc_fp64_versor_make_direction_turn(start, end, start_square_modulus * end_square_modulus, result); } // =============== Set Directions =============== // static int _bgc_fp32_versor_validate_basis(const float primary_square_modulus, const float auxiliary_square_modulus, const float orthogonal_square_modulus) { if (primary_square_modulus <= BGC_FP32_SQUARE_EPSYLON) { //TODO: add error code for: primary_vector is zero return BGC_FAILED; } if (auxiliary_square_modulus <= BGC_FP32_SQUARE_EPSYLON) { //TODO: add error code for: auxiliary_vector is zero return BGC_FAILED; } if (orthogonal_square_modulus <= BGC_FP32_SQUARE_EPSYLON * primary_square_modulus * auxiliary_square_modulus) { //TODO: add error code for: primary_vector and auxiliary_vector are parallel return BGC_FAILED; } return BGC_SUCCESS; } static int _bgc_fp64_versor_validate_basis(const double primary_square_modulus, const double auxiliary_square_modulus, const double orthogonal_square_modulus) { if (primary_square_modulus <= BGC_FP64_SQUARE_EPSYLON) { //TODO: add error code for: primary_vector is zero return BGC_FAILED; } if (auxiliary_square_modulus <= BGC_FP64_SQUARE_EPSYLON) { //TODO: add error code for: auxiliary_vector is zero return BGC_FAILED; } if (orthogonal_square_modulus <= BGC_FP64_SQUARE_EPSYLON * primary_square_modulus * auxiliary_square_modulus) { //TODO: add error code for: primary_vector and auxiliary_vector are parallel return BGC_FAILED; } return BGC_SUCCESS; } int bgc_fp32_versor_make_basis_difference( const BGC_FP32_Vector3* initial_primary_direction, const BGC_FP32_Vector3* initial_auxiliary_direction, const BGC_FP32_Vector3* final_primary_direction, const BGC_FP32_Vector3* final_auxiliary_direction, BGC_FP32_Versor* result ) { BGC_FP32_Vector3 initial_orthogonal_direction, turned_orthogonal_direction, final_orthogonal_direction; // Step 1: Validate initial basis: bgc_fp32_vector3_get_cross_product(initial_primary_direction, initial_auxiliary_direction, &initial_orthogonal_direction); const float initial_primary_square_modulus = bgc_fp32_vector3_get_square_modulus(initial_primary_direction); const float initial_auxiliary_square_modulus = bgc_fp32_vector3_get_square_modulus(initial_auxiliary_direction); const float initial_orthogonal_square_modulus = bgc_fp32_vector3_get_square_modulus(&initial_orthogonal_direction); const int initial_basis_valudation = _bgc_fp32_versor_validate_basis(initial_primary_square_modulus, initial_auxiliary_square_modulus, initial_orthogonal_square_modulus); if (initial_basis_valudation != BGC_SUCCESS) { return initial_basis_valudation; } // Step 1: Validate final basis: bgc_fp32_vector3_get_cross_product(final_primary_direction, final_auxiliary_direction, &final_orthogonal_direction); const float final_primary_square_modulus = bgc_fp32_vector3_get_square_modulus(final_primary_direction); const float final_auxiliary_square_modulus = bgc_fp32_vector3_get_square_modulus(final_auxiliary_direction); const float final_orthogonal_square_modulus = bgc_fp32_vector3_get_square_modulus(&final_orthogonal_direction); const int final_basis_valudation = _bgc_fp32_versor_validate_basis(final_primary_square_modulus, final_auxiliary_square_modulus, final_orthogonal_square_modulus); if (final_basis_valudation != BGC_SUCCESS) { return final_basis_valudation; } // Step 3: Validate normalize orthogonal vectors: bgc_fp32_vector3_divide(&initial_orthogonal_direction, sqrtf(initial_orthogonal_square_modulus), &initial_orthogonal_direction); bgc_fp32_vector3_divide(&final_orthogonal_direction, sqrtf(final_orthogonal_square_modulus), &final_orthogonal_direction); BGC_FP32_Versor turn1, turn2; // Step 4: Find turn1 int turn1_code = _bgc_fp32_versor_make_direction_turn(initial_primary_direction, final_primary_direction, initial_primary_square_modulus * final_primary_square_modulus, &turn1); if (turn1_code == BGC_OPPOSITE) { bgc_fp32_versor_make(0.0f, initial_orthogonal_direction.x1, initial_orthogonal_direction.x2, initial_orthogonal_direction.x3, &turn1); } bgc_fp32_versor_turn_vector(&turn1, &initial_orthogonal_direction, &turned_orthogonal_direction); // Step 5: Find turn2: int turn2_code = _bgc_fp32_versor_make_direction_turn(&turned_orthogonal_direction, &final_orthogonal_direction, 1.0f, &turn2); if (turn2_code == BGC_OPPOSITE) { const float turn2_multiplier = sqrtf(1.0f / final_primary_square_modulus); bgc_fp32_versor_make(0.0f, final_primary_direction->x1 * turn2_multiplier, final_primary_direction->x2 * turn2_multiplier, final_primary_direction->x3 * turn2_multiplier, &turn2 ); } // Step 6: Combine turn1 and turn2: bgc_fp32_versor_combine(&turn1, &turn2, result); return BGC_SUCCESS; } int bgc_fp64_versor_make_basis_difference( const BGC_FP64_Vector3* initial_primary_direction, const BGC_FP64_Vector3* initial_auxiliary_direction, const BGC_FP64_Vector3* final_primary_direction, const BGC_FP64_Vector3* final_auxiliary_direction, BGC_FP64_Versor* result ) { BGC_FP64_Vector3 initial_orthogonal_direction, turned_orthogonal_direction, final_orthogonal_direction; // Step 1: Validate initial basis: bgc_fp64_vector3_get_cross_product(initial_primary_direction, initial_auxiliary_direction, &initial_orthogonal_direction); const double initial_primary_square_modulus = bgc_fp64_vector3_get_square_modulus(initial_primary_direction); const double initial_auxiliary_square_modulus = bgc_fp64_vector3_get_square_modulus(initial_auxiliary_direction); const double initial_orthogonal_square_modulus = bgc_fp64_vector3_get_square_modulus(&initial_orthogonal_direction); const int initial_basis_valudation = _bgc_fp64_versor_validate_basis(initial_primary_square_modulus, initial_auxiliary_square_modulus, initial_orthogonal_square_modulus); if (initial_basis_valudation != BGC_SUCCESS) { return initial_basis_valudation; } // Step 1: Validate final basis: bgc_fp64_vector3_get_cross_product(final_primary_direction, final_auxiliary_direction, &final_orthogonal_direction); const double final_primary_square_modulus = bgc_fp64_vector3_get_square_modulus(final_primary_direction); const double final_auxiliary_square_modulus = bgc_fp64_vector3_get_square_modulus(final_auxiliary_direction); const double final_orthogonal_square_modulus = bgc_fp64_vector3_get_square_modulus(&final_orthogonal_direction); const int final_basis_valudation = _bgc_fp64_versor_validate_basis(final_primary_square_modulus, final_auxiliary_square_modulus, final_orthogonal_square_modulus); if (final_basis_valudation != BGC_SUCCESS) { return final_basis_valudation; } // Step 3: Validate normalize orthogonal vectors: bgc_fp64_vector3_divide(&initial_orthogonal_direction, sqrt(initial_orthogonal_square_modulus), &initial_orthogonal_direction); bgc_fp64_vector3_divide(&final_orthogonal_direction, sqrt(final_orthogonal_square_modulus), &final_orthogonal_direction); BGC_FP64_Versor turn1, turn2; // Step 4: Find turn1 int turn1_code = _bgc_fp64_versor_make_direction_turn(initial_primary_direction, final_primary_direction, initial_primary_square_modulus * final_primary_square_modulus, &turn1); if (turn1_code == BGC_OPPOSITE) { bgc_fp64_versor_make(0.0, initial_orthogonal_direction.x1, initial_orthogonal_direction.x2, initial_orthogonal_direction.x3, &turn1); } bgc_fp64_versor_turn_vector(&turn1, &initial_orthogonal_direction, &turned_orthogonal_direction); // Step 5: Find turn2: int turn2_code = _bgc_fp64_versor_make_direction_turn(&turned_orthogonal_direction, &final_orthogonal_direction, 1.0f, &turn2); if (turn2_code == BGC_OPPOSITE) { const double turn2_multiplier = sqrt(1.0 / final_primary_square_modulus); bgc_fp64_versor_make(0.0, final_primary_direction->x1 * turn2_multiplier, final_primary_direction->x2 * turn2_multiplier, final_primary_direction->x3 * turn2_multiplier, &turn2 ); } // Step 6: Combine turn1 and turn2: bgc_fp64_versor_combine(&turn1, &turn2, result); return BGC_SUCCESS; } // =============== Get Exponation =============== // void bgc_fp32_versor_get_exponation(const BGC_FP32_Versor* base, const float exponent, BGC_FP32_Versor* power) { const float square_vector = base->_x1 * base->_x1 + base->_x2 * base->_x2 + base->_x3 * base->_x3; if (square_vector <= BGC_FP32_SQUARE_EPSYLON || square_vector != square_vector) { bgc_fp32_versor_reset(power); return; } const float vector_modulus = sqrtf(square_vector); const float angle = atan2f(vector_modulus, base->_s0) * exponent; const float multiplier = sinf(angle) / vector_modulus; bgc_fp32_versor_make(cosf(angle), base->_x1 * multiplier, base->_x2 * multiplier, base->_x3 * multiplier, power); } void bgc_fp64_versor_get_exponation(const BGC_FP64_Versor* base, const double exponent, BGC_FP64_Versor* power) { const double square_vector = base->_x1 * base->_x1 + base->_x2 * base->_x2 + base->_x3 * base->_x3; if (square_vector <= BGC_FP64_SQUARE_EPSYLON || square_vector != square_vector) { bgc_fp64_versor_reset(power); return; } const double vector_modulus = sqrt(square_vector); const double angle = atan2(vector_modulus, base->_s0) * exponent; const double multiplier = sin(angle) / vector_modulus; bgc_fp64_versor_make(cos(angle), base->_x1 * multiplier, base->_x2 * multiplier, base->_x3 * multiplier, power); } // ============ Sphere Interpolation ============ // void bgc_fp32_versor_spherically_interpolate(const BGC_FP32_Versor* start, const BGC_FP32_Versor* end, const float phase, BGC_FP32_Versor* result) { const float delta_s0 = (end->_s0 * start->_s0 + end->_x1 * start->_x1) + (end->_x2 * start->_x2 + end->_x3 * start->_x3); const float delta_x1 = (end->_x1 * start->_s0 + end->_x3 * start->_x2) - (end->_s0 * start->_x1 + end->_x2 * start->_x3); const float delta_x2 = (end->_x2 * start->_s0 + end->_x1 * start->_x3) - (end->_s0 * start->_x2 + end->_x3 * start->_x1); const float delta_x3 = (end->_x3 * start->_s0 + end->_x2 * start->_x1) - (end->_s0 * start->_x3 + end->_x1 * start->_x2); const float square_vector = delta_x1 * delta_x1 + delta_x2 * delta_x2 + delta_x3 * delta_x3; // square_vector != square_vector means checking for NaN value at square_vector if (square_vector <= BGC_FP32_SQUARE_EPSYLON || square_vector != square_vector) { bgc_fp32_versor_copy(end, result); return; } // Calculating of the turning which fits the phase: const float vector_modulus = sqrtf(square_vector); const float angle = atan2f(vector_modulus, delta_s0) * phase; const float multiplier = sinf(angle) / vector_modulus; const float turn_s0 = cosf(angle); const float turn_x1 = delta_x1 * multiplier; const float turn_x2 = delta_x2 * multiplier; const float turn_x3 = delta_x3 * multiplier; // Combining of starting orientation with the turning bgc_fp32_versor_make( (turn_s0 * start->_s0 - turn_x1 * start->_x1) - (turn_x2 * start->_x2 + turn_x3 * start->_x3), (turn_x1 * start->_s0 + turn_s0 * start->_x1) - (turn_x3 * start->_x2 - turn_x2 * start->_x3), (turn_x2 * start->_s0 + turn_s0 * start->_x2) - (turn_x1 * start->_x3 - turn_x3 * start->_x1), (turn_x3 * start->_s0 + turn_s0 * start->_x3) - (turn_x2 * start->_x1 - turn_x1 * start->_x2), result ); } void bgc_fp64_versor_spherically_interpolate(const BGC_FP64_Versor* start, const BGC_FP64_Versor* end, const double phase, BGC_FP64_Versor* result) { const double delta_s0 = (end->_s0 * start->_s0 + end->_x1 * start->_x1) + (end->_x2 * start->_x2 + end->_x3 * start->_x3); const double delta_x1 = (end->_x1 * start->_s0 + end->_x3 * start->_x2) - (end->_s0 * start->_x1 + end->_x2 * start->_x3); const double delta_x2 = (end->_x2 * start->_s0 + end->_x1 * start->_x3) - (end->_s0 * start->_x2 + end->_x3 * start->_x1); const double delta_x3 = (end->_x3 * start->_s0 + end->_x2 * start->_x1) - (end->_s0 * start->_x3 + end->_x1 * start->_x2); const double square_vector = delta_x1 * delta_x1 + delta_x2 * delta_x2 + delta_x3 * delta_x3; // square_vector != square_vector means checking for NaN value at square_vector if (square_vector <= BGC_FP64_SQUARE_EPSYLON || square_vector != square_vector) { bgc_fp64_versor_copy(end, result); return; } // Calculating of the turning which fits the phase: const double vector_modulus = sqrt(square_vector); const double angle = atan2(vector_modulus, delta_s0) * phase; const double multiplier = sin(angle) / vector_modulus; const double turn_s0 = cos(angle); const double turn_x1 = delta_x1 * multiplier; const double turn_x2 = delta_x2 * multiplier; const double turn_x3 = delta_x3 * multiplier; // Combining of starting orientation with the turning bgc_fp64_versor_make( (turn_s0 * start->_s0 - turn_x1 * start->_x1) - (turn_x2 * start->_x2 + turn_x3 * start->_x3), (turn_x1 * start->_s0 + turn_s0 * start->_x1) - (turn_x3 * start->_x2 - turn_x2 * start->_x3), (turn_x2 * start->_s0 + turn_s0 * start->_x2) - (turn_x1 * start->_x3 - turn_x3 * start->_x1), (turn_x3 * start->_s0 + turn_s0 * start->_x3) - (turn_x2 * start->_x1 - turn_x1 * start->_x2), result ); } // ================ Get Rotation ================ // void bgc_fp32_versor_get_rotation(const BGC_FP32_Versor* versor, BGC_FP32_Rotation3* result) { const float square_modulus = versor->_x1 * versor->_x1 + versor->_x2 * versor->_x2 + versor->_x3 * versor->_x3; if (square_modulus <= BGC_FP32_SQUARE_EPSYLON) { bgc_fp32_rotation3_reset(result); return; } const float vector_modulus = sqrtf(square_modulus); const float multiplier = 1.0f / vector_modulus; result->radians = 2.0f * atan2f(vector_modulus, versor->_s0); result->axis.x1 = versor->_x1 * multiplier; result->axis.x2 = versor->_x2 * multiplier; result->axis.x3 = versor->_x3 * multiplier; } void bgc_fp64_versor_get_rotation(const BGC_FP64_Versor* versor, BGC_FP64_Rotation3* result) { const double square_modulus = versor->_x1 * versor->_x1 + versor->_x2 * versor->_x2 + versor->_x3 * versor->_x3; if (square_modulus <= BGC_FP64_SQUARE_EPSYLON) { bgc_fp64_rotation3_reset(result); return; } const double vector_modulus = sqrt(square_modulus); const double multiplier = 1.0 / vector_modulus; result->radians = 2.0 * atan2(vector_modulus, versor->_s0); result->axis.x1 = versor->_x1 * multiplier; result->axis.x2 = versor->_x2 * multiplier; result->axis.x3 = versor->_x3 * multiplier; }