From 74be89f1f85aba78a2eb72dff3f4ccf080f64a76 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov <9942846+Morgend@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:27:33 +0700 Subject: [PATCH 01/10] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20tangent=20pa?= =?UTF-8?q?ir=20=D0=B2=20=D1=87=D0=B8=D1=81=D0=BB=D0=B0=20=D0=9A=D0=BE?= =?UTF-8?q?=D1=82=D1=81=D0=B0,=20=D0=B2=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=BD=D1=8B=D1=85=20=D1=87=D0=B8=D1=81=D0=B5=D0=BB=20?= =?UTF-8?q?=D0=B8=D0=B7=20=D0=B4=D0=B2=D1=83=D0=BC=D0=B5=D1=80=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=B2=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=BE=D0=B2,=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B2=20=D1=81=D0=BF=D0=B5=D0=B1=D0=B5=D0=BD=D1=8C=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B2=D0=B5=D1=80=D0=BE=D1=81=D0=BE=D1=80=D0=B2?= =?UTF-8?q?=20=D0=B8=20=D1=87=D0=B8=D1=81=D0=B5=D0=BB=20=D0=9A=D0=BE=D1=82?= =?UTF-8?q?=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry-dev/main.c | 33 +- basic-geometry/basic-geometry.cbp | 12 +- basic-geometry/basic-geometry.h | 29 +- basic-geometry/basic-geometry.vcxproj | 7 +- basic-geometry/basic-geometry.vcxproj.filters | 18 +- basic-geometry/complex.c | 124 ++++ basic-geometry/complex.h | 531 ++++++++++++++++++ basic-geometry/cotes-number.c | 82 +++ basic-geometry/cotes-number.h | 374 ++++++++++++ basic-geometry/quaternion.c | 4 + basic-geometry/quaternion.h | 2 + basic-geometry/tangent-pair.c | 79 --- basic-geometry/tangent-pair.h | 352 ------------ basic-geometry/vector2.c | 54 -- basic-geometry/vector2.h | 114 ---- basic-geometry/versor.c | 58 +- basic-geometry/versor.h | 6 + 17 files changed, 1233 insertions(+), 646 deletions(-) create mode 100644 basic-geometry/complex.c create mode 100644 basic-geometry/complex.h create mode 100644 basic-geometry/cotes-number.c create mode 100644 basic-geometry/cotes-number.h delete mode 100644 basic-geometry/tangent-pair.c delete mode 100644 basic-geometry/tangent-pair.h diff --git a/basic-geometry-dev/main.c b/basic-geometry-dev/main.c index 0f4ad34..901b4e3 100644 --- a/basic-geometry-dev/main.c +++ b/basic-geometry-dev/main.c @@ -79,7 +79,7 @@ void list_work(const uint_fast32_t amount, structure_fp32_t* list) } } } - +/* int main() { const unsigned int amount = 1000000; @@ -121,3 +121,34 @@ int main() return 0; } +*/ + +/* +int main() { + BgcComplexFP32 complex, exponent, result; + + bgc_complex_set_values_fp32(0, 1, &complex); + + bgc_complex_set_values_fp32(4, 0, &exponent); + + bgc_complex_get_exponation_fp32(&complex, exponent.real, exponent.imaginary, &result); + + printf("(%f, %f) ^ (%f, %f) = (%f, %f)\n", complex.real, complex.imaginary, exponent.real, exponent.imaginary, result.real, result.imaginary); + + return 0; +} +*/ + +int main() { + const float exponent = 2.0f; + + BgcVersorFP32 turn, result; + + bgc_versor_set_turn_fp32(0, 0, 1, 120, BGC_ANGLE_UNIT_DEGREES, &turn); + + bgc_versor_get_exponation_fp32(&turn, exponent, &result); + + printf("(%f, %f, %f, %f) ^ %f = (%f, %f, %f, %f)\n", turn.s0, turn.x1, turn.x2, turn.x3, exponent, result.s0, result.x1, result.x2, result.x3); + + return 0; +} diff --git a/basic-geometry/basic-geometry.cbp b/basic-geometry/basic-geometry.cbp index 3e21644..1dadfea 100644 --- a/basic-geometry/basic-geometry.cbp +++ b/basic-geometry/basic-geometry.cbp @@ -48,6 +48,14 @@ + + + + + + @@ -76,10 +84,6 @@ - - - diff --git a/basic-geometry/basic-geometry.h b/basic-geometry/basic-geometry.h index 5a3923c..fb83f61 100644 --- a/basic-geometry/basic-geometry.h +++ b/basic-geometry/basic-geometry.h @@ -1,24 +1,25 @@ #ifndef _BGC_H_ #define _BGC_H_ -#include "utilities.h" +#include "./utilities.h" -#include "angle.h" +#include "./angle.h" -#include "vector2.h" -#include "vector3.h" +#include "./vector2.h" +#include "./vector3.h" -#include "matrixes.h" -#include "matrix2x2.h" -#include "matrix2x3.h" -#include "matrix3x2.h" -#include "matrix3x3.h" +#include "./matrixes.h" +#include "./matrix2x2.h" +#include "./matrix2x3.h" +#include "./matrix3x2.h" +#include "./matrix3x3.h" + +#include "./complex.h" +#include "./cotes-number.h" -#include "tangent-pair.h" +#include "./rotation3.h" -#include "rotation3.h" - -#include "quaternion.h" -#include "versor.h" +#include "./quaternion.h" +#include "./versor.h" #endif diff --git a/basic-geometry/basic-geometry.vcxproj b/basic-geometry/basic-geometry.vcxproj index 98620b5..6c60d06 100644 --- a/basic-geometry/basic-geometry.vcxproj +++ b/basic-geometry/basic-geometry.vcxproj @@ -21,6 +21,8 @@ + + @@ -28,7 +30,6 @@ - @@ -36,6 +37,8 @@ + + @@ -44,7 +47,7 @@ - + diff --git a/basic-geometry/basic-geometry.vcxproj.filters b/basic-geometry/basic-geometry.vcxproj.filters index 2349250..260e3e3 100644 --- a/basic-geometry/basic-geometry.vcxproj.filters +++ b/basic-geometry/basic-geometry.vcxproj.filters @@ -18,6 +18,12 @@ Файлы заголовков + + Файлы заголовков + + + Файлы заголовков + Файлы заголовков @@ -54,14 +60,17 @@ Файлы заголовков - - Файлы заголовков - Исходные файлы + + Исходные файлы + + + Исходные файлы + Исходные файлы @@ -95,8 +104,5 @@ Исходные файлы - - Исходные файлы - \ No newline at end of file diff --git a/basic-geometry/complex.c b/basic-geometry/complex.c new file mode 100644 index 0000000..59c6979 --- /dev/null +++ b/basic-geometry/complex.c @@ -0,0 +1,124 @@ +#include "./complex.h" + +extern inline void bgc_complex_reset_fp32(BgcComplexFP32* complex); +extern inline void bgc_complex_reset_fp64(BgcComplexFP64* complex); + +extern inline void bgc_complex_set_values_fp32(const float real, const float imaginary, BgcComplexFP32* destination); +extern inline void bgc_complex_set_values_fp64(const double real, const double imaginary, BgcComplexFP64* destination); + +extern inline float bgc_complex_get_square_modulus_fp32(const BgcComplexFP32* number); +extern inline double bgc_complex_get_square_modulus_fp64(const BgcComplexFP64* number); + +extern inline float bgc_complex_get_modulus_fp32(const BgcComplexFP32* number); +extern inline double bgc_complex_get_modulus_fp64(const BgcComplexFP64* number); + +extern inline int bgc_complex_is_zero_fp32(const BgcComplexFP32* number); +extern inline int bgc_complex_is_zero_fp64(const BgcComplexFP64* number); + +extern inline int bgc_complex_is_unit_fp32(const BgcComplexFP32* number); +extern inline int bgc_complex_is_unit_fp64(const BgcComplexFP64* number); + +extern inline void bgc_complex_copy_fp32(const BgcComplexFP32* source, BgcComplexFP32* destination); +extern inline void bgc_complex_copy_fp64(const BgcComplexFP64* source, BgcComplexFP64* destination); + +extern inline void bgc_complex_swap_fp32(BgcComplexFP32* number1, BgcComplexFP32* number2); +extern inline void bgc_complex_swap_fp64(BgcComplexFP64* number1, BgcComplexFP64* number2); + +extern inline void bgc_complex_convert_fp64_to_fp32(const BgcComplexFP64* source, BgcComplexFP32* destination); +extern inline void bgc_complex_convert_fp32_to_fp64(const BgcComplexFP32* source, BgcComplexFP64* destination); + +extern inline void bgc_complex_reverse_fp32(const BgcComplexFP32* number, BgcComplexFP32* reverse); +extern inline void bgc_complex_reverse_fp64(const BgcComplexFP64* number, BgcComplexFP64* reverse); + +extern inline int bgc_complex_normalize_fp32(const BgcComplexFP32* number, BgcComplexFP32* normalized); +extern inline int bgc_complex_normalize_fp64(const BgcComplexFP64* number, BgcComplexFP64* normalized); + +extern inline void bgc_complex_conjugate_fp32(const BgcComplexFP32* number, BgcComplexFP32* conjugate); +extern inline void bgc_complex_conjugate_fp64(const BgcComplexFP64* number, BgcComplexFP64* conjugate); + +extern inline int bgc_complex_invert_fp32(const BgcComplexFP32* number, BgcComplexFP32* inverted); +extern inline int bgc_complex_invert_fp64(const BgcComplexFP64* number, BgcComplexFP64* inverted); + +extern inline void bgc_complex_get_product_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* result); +extern inline void bgc_complex_get_product_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* result); + +extern inline int bgc_complex_get_ratio_fp32(const BgcComplexFP32* divident, const BgcComplexFP32* divisor, BgcComplexFP32* quotient); +extern inline int bgc_complex_get_ratio_fp64(const BgcComplexFP64* divident, const BgcComplexFP64* divisor, BgcComplexFP64* quotient); + +extern inline void bgc_complex_add_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* sum); +extern inline void bgc_complex_add_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* sum); + +extern inline void bgc_complex_add_scaled_fp32(const BgcComplexFP32* basic_number, const BgcComplexFP32* scalable_number, const float scale, BgcComplexFP32* sum); +extern inline void bgc_complex_add_scaled_fp64(const BgcComplexFP64* basic_number, const BgcComplexFP64* scalable_number, const double scale, BgcComplexFP64* sum); + +extern inline void bgc_complex_subtract_fp32(const BgcComplexFP32* minuend, const BgcComplexFP32* subtrahend, BgcComplexFP32* difference); +extern inline void bgc_complex_subtract_fp64(const BgcComplexFP64* minuend, const BgcComplexFP64* subtrahend, BgcComplexFP64* difference); + +extern inline void bgc_complex_subtract_scaled_fp32(const BgcComplexFP32* basic_number, const BgcComplexFP32* scalable_number, const float scale, BgcComplexFP32* difference); +extern inline void bgc_complex_subtract_scaled_fp64(const BgcComplexFP64* basic_number, const BgcComplexFP64* scalable_number, const double scale, BgcComplexFP64* difference); + +extern inline void bgc_complex_multiply_fp32(const BgcComplexFP32* multiplicand, const float multiplier, BgcComplexFP32* product); +extern inline void bgc_complex_multiply_fp64(const BgcComplexFP64* multiplicand, const double multiplier, BgcComplexFP64* product); + +extern inline void bgc_complex_divide_fp32(const BgcComplexFP32* dividend, const float divisor, BgcComplexFP32* quotient); +extern inline void bgc_complex_divide_fp64(const BgcComplexFP64* dividend, const double divisor, BgcComplexFP64* quotient); + +extern inline void bgc_complex_get_mean_of_two_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* mean); +extern inline void bgc_complex_get_mean_of_two_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* mean); + +extern inline void bgc_complex_get_mean_of_three_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const BgcComplexFP32* number3, BgcComplexFP32* mean); +extern inline void bgc_complex_get_mean_of_three_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const BgcComplexFP64* number3, BgcComplexFP64* mean); + +extern inline void bgc_complex_get_linear_interpolation_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation); +extern inline void bgc_complex_get_linear_interpolation_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation); + +extern inline void bgc_complex_minimize_fp32(const BgcComplexFP32* number, BgcComplexFP32* minimal); +extern inline void bgc_complex_minimize_fp64(const BgcComplexFP64* number, BgcComplexFP64* minimal); + +extern inline void bgc_complex_maximize_fp32(const BgcComplexFP32* number, BgcComplexFP32* maximal); +extern inline void bgc_complex_maximize_fp64(const BgcComplexFP64* number, BgcComplexFP64* maximal); + +extern inline int bgc_complex_are_close_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2); +extern inline int bgc_complex_are_close_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2); + +// =============== Get Exponation =============== // + +void bgc_complex_get_exponation_fp32(const BgcComplexFP32* base, const float real_exponent, const float imaginary_exponent, BgcComplexFP32* power) +{ + const float square_modulus = bgc_complex_get_square_modulus_fp32(base); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + power->real = 0.0f; + power->imaginary = 0.0f; + return; + } + + const float log_modulus = logf(square_modulus) * 0.5f; + const float angle = atan2f(base->imaginary, base->real); + + const float power_modulus = expf(real_exponent * log_modulus - imaginary_exponent * angle); + const float power_angle = real_exponent * angle + imaginary_exponent * log_modulus; + + power->real = power_modulus * cosf(power_angle); + power->imaginary = power_modulus * sinf(power_angle); +} + +void bgc_complex_get_exponation_fp64(const BgcComplexFP64* base, const double real_exponent, const double imaginary_exponent, BgcComplexFP64* power) +{ + const double square_modulus = bgc_complex_get_square_modulus_fp64(base); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + power->real = 0.0; + power->imaginary = 0.0; + return; + } + + const double log_modulus = log(square_modulus) * 0.5; + const double angle = atan2(base->imaginary, base->real); + + const double power_modulus = exp(real_exponent * log_modulus - imaginary_exponent * angle); + const double power_angle = real_exponent * angle + imaginary_exponent * log_modulus; + + power->real = power_modulus * cos(power_angle); + power->imaginary = power_modulus * sin(power_angle); +} diff --git a/basic-geometry/complex.h b/basic-geometry/complex.h new file mode 100644 index 0000000..c7b77ff --- /dev/null +++ b/basic-geometry/complex.h @@ -0,0 +1,531 @@ +#ifndef _BGC_COMPLEX_H_ +#define _BGC_COMPLEX_H_ + +#include "utilities.h" +#include "angle.h" + +#include + +typedef struct +{ + float real, imaginary; +} BgcComplexFP32; + +typedef struct +{ + double real, imaginary; +} BgcComplexFP64; + +// =================== Reset ==================== // + +inline void bgc_complex_reset_fp32(BgcComplexFP32* complex) +{ + complex->real = 0.0f; + complex->imaginary = 0.0f; +} + +inline void bgc_complex_reset_fp64(BgcComplexFP64* complex) +{ + complex->real = 0.0; + complex->imaginary = 0.0; +} + +// ==================== Set ===================== // + +inline void bgc_complex_set_values_fp32(const float real, const float imaginary, BgcComplexFP32* destination) +{ + destination->real = real; + destination->imaginary = imaginary; +} + +inline void bgc_complex_set_values_fp64(const double real, const double imaginary, BgcComplexFP64* destination) +{ + destination->real = real; + destination->imaginary = imaginary; +} + +// ================== Modulus =================== // + +inline float bgc_complex_get_square_modulus_fp32(const BgcComplexFP32* number) +{ + return number->real * number->real + number->imaginary * number->imaginary; +} + +inline double bgc_complex_get_square_modulus_fp64(const BgcComplexFP64* number) +{ + return number->real * number->real + number->imaginary * number->imaginary; +} + +inline float bgc_complex_get_modulus_fp32(const BgcComplexFP32* number) +{ + return sqrtf(bgc_complex_get_square_modulus_fp32(number)); +} + +inline double bgc_complex_get_modulus_fp64(const BgcComplexFP64* number) +{ + return sqrt(bgc_complex_get_square_modulus_fp64(number)); +} + +// ================= Comparison ================= // + +inline int bgc_complex_is_zero_fp32(const BgcComplexFP32* number) +{ + return bgc_complex_get_square_modulus_fp32(number) <= BGC_SQUARE_EPSYLON_FP32; +} + +inline int bgc_complex_is_zero_fp64(const BgcComplexFP64* number) +{ + return bgc_complex_get_square_modulus_fp64(number) <= BGC_SQUARE_EPSYLON_FP64; +} + +inline int bgc_complex_is_unit_fp32(const BgcComplexFP32* number) +{ + return bgc_is_sqare_unit_fp32(bgc_complex_get_square_modulus_fp32(number)); +} + +inline int bgc_complex_is_unit_fp64(const BgcComplexFP64* number) +{ + return bgc_is_sqare_unit_fp64(bgc_complex_get_square_modulus_fp64(number)); +} + +// ==================== Copy ==================== // + +inline void bgc_complex_copy_fp32(const BgcComplexFP32* source, BgcComplexFP32* destination) +{ + destination->real = source->real; + destination->imaginary = source->imaginary; +} + +inline void bgc_complex_copy_fp64(const BgcComplexFP64* source, BgcComplexFP64* destination) +{ + destination->real = source->real; + destination->imaginary = source->imaginary; +} + +// ==================== Swap ==================== // + +inline void bgc_complex_swap_fp32(BgcComplexFP32* number1, BgcComplexFP32* number2) +{ + const float real = number2->real; + const float imaginary = number2->imaginary; + + number2->real = number1->real; + number2->imaginary = number1->imaginary; + + number1->real = real; + number1->imaginary = imaginary; +} + +inline void bgc_complex_swap_fp64(BgcComplexFP64* number1, BgcComplexFP64* number2) +{ + const double real = number2->real; + const double imaginary = number2->imaginary; + + number2->real = number1->real; + number2->imaginary = number1->imaginary; + + number1->real = real; + number1->imaginary = imaginary; +} + +// ================== Convert =================== // + +inline void bgc_complex_convert_fp64_to_fp32(const BgcComplexFP64* source, BgcComplexFP32* destination) +{ + destination->real = (float)source->real; + destination->imaginary = (float)source->imaginary; +} + +inline void bgc_complex_convert_fp32_to_fp64(const BgcComplexFP32* source, BgcComplexFP64* destination) +{ + destination->real = source->real; + destination->imaginary = source->imaginary; +} + +// ================== Reverse =================== // + +inline void bgc_complex_reverse_fp32(const BgcComplexFP32* number, BgcComplexFP32* reverse) +{ + reverse->real = -number->real; + reverse->imaginary = -number->imaginary; +} + +inline void bgc_complex_reverse_fp64(const BgcComplexFP64* number, BgcComplexFP64* reverse) +{ + reverse->real = -number->real; + reverse->imaginary = -number->imaginary; +} + +// ================= Normalize ================== // + +inline int bgc_complex_normalize_fp32(const BgcComplexFP32* number, BgcComplexFP32* normalized) +{ + const float square_modulus = bgc_complex_get_square_modulus_fp32(number); + + if (bgc_is_sqare_unit_fp32(square_modulus)) { + normalized->real = number->real; + normalized->imaginary = number->imaginary; + return 1; + } + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { + return 0; + } + + const float multiplicand = sqrtf(1.0f / square_modulus); + + normalized->real = number->real * multiplicand; + normalized->imaginary = number->imaginary * multiplicand; + + return 1; +} + +inline int bgc_complex_normalize_fp64(const BgcComplexFP64* number, BgcComplexFP64* normalized) +{ + const double square_modulus = bgc_complex_get_square_modulus_fp64(number); + + if (bgc_is_sqare_unit_fp64(square_modulus)) { + normalized->real = number->real; + normalized->imaginary = number->imaginary; + return 1; + } + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { + return 0; + } + + const double multiplicand = sqrt(1.0 / square_modulus); + + normalized->real = number->real * multiplicand; + normalized->imaginary = number->imaginary * multiplicand; + + return 1; +} + +// ================= Conjugate ================== // + +inline void bgc_complex_conjugate_fp32(const BgcComplexFP32* number, BgcComplexFP32* conjugate) +{ + conjugate->real = number->real; + conjugate->imaginary = -number->imaginary; +} + +inline void bgc_complex_conjugate_fp64(const BgcComplexFP64* number, BgcComplexFP64* conjugate) +{ + conjugate->real = number->real; + conjugate->imaginary = -number->imaginary; +} + +// =================== Invert =================== // + +inline int bgc_complex_invert_fp32(const BgcComplexFP32* number, BgcComplexFP32* inverted) +{ + const float square_modulus = bgc_complex_get_square_modulus_fp32(number); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { + return 0; + } + + const float multiplicand = 1.0f / square_modulus; + + inverted->real = number->real * multiplicand; + inverted->imaginary = -number->imaginary * multiplicand; + + return 1; +} + +inline int bgc_complex_invert_fp64(const BgcComplexFP64* number, BgcComplexFP64* inverted) +{ + const double square_modulus = bgc_complex_get_square_modulus_fp64(number); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { + return 0; + } + + const double multiplicand = 1.0 / square_modulus; + + inverted->real = number->real * multiplicand; + inverted->imaginary = -number->imaginary * multiplicand; + + return 1; +} + +// ================ Get Product ================= // + +inline void bgc_complex_get_product_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* result) +{ + const float real = number1->real * number2->real - number1->imaginary * number2->imaginary; + const float imaginary = number1->real * number2->imaginary + number1->imaginary * number2->real; + + result->real = real; + result->imaginary = imaginary; +} + +inline void bgc_complex_get_product_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* result) +{ + const double real = number1->real * number2->real - number1->imaginary * number2->imaginary; + const double imaginary = number1->real * number2->imaginary + number1->imaginary * number2->real; + + result->real = real; + result->imaginary = imaginary; +} + +// ================= Get Ratio ================== // + +inline int bgc_complex_get_ratio_fp32(const BgcComplexFP32* divident, const BgcComplexFP32* divisor, BgcComplexFP32* quotient) +{ + const float square_modulus = bgc_complex_get_square_modulus_fp32(divisor); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + return 0; + } + + const float real = divident->real * divisor->real + divident->imaginary * divisor->imaginary; + const float imaginary = divident->imaginary * divisor->real - divident->real * divisor->imaginary; + + const float multiplier = 1.0f / square_modulus; + + quotient->real = real * multiplier; + quotient->imaginary = imaginary * multiplier; + + return 1; +} + +inline int bgc_complex_get_ratio_fp64(const BgcComplexFP64* divident, const BgcComplexFP64* divisor, BgcComplexFP64* quotient) +{ + const double square_modulus = bgc_complex_get_square_modulus_fp64(divisor); + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + return 0; + } + + const double real = divident->real * divisor->real + divident->imaginary * divisor->imaginary; + const double imaginary = divident->imaginary * divisor->real - divident->real * divisor->imaginary; + + const double multiplier = 1.0 / square_modulus; + + quotient->real = real * multiplier; + quotient->imaginary = imaginary * multiplier; + + return 1; +} + +// =============== Get Exponation =============== // + +void bgc_complex_get_exponation_fp32(const BgcComplexFP32* base, const float real_exponent, const float imaginary_exponent, BgcComplexFP32* power); + +void bgc_complex_get_exponation_fp64(const BgcComplexFP64* base, const double real_exponent, const double imaginary_exponent, BgcComplexFP64* power); + +// ==================== Add ===================== // + +inline void bgc_complex_add_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* sum) +{ + sum->real = number1->real + number2->real; + sum->imaginary = number1->imaginary + number2->imaginary; +} + +inline void bgc_complex_add_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* sum) +{ + sum->real = number1->real + number2->real; + sum->imaginary = number1->imaginary + number2->imaginary; +} + +// ================= Add scaled ================= // + +inline void bgc_complex_add_scaled_fp32(const BgcComplexFP32* basic_number, const BgcComplexFP32* scalable_number, const float scale, BgcComplexFP32* sum) +{ + sum->real = basic_number->real + scalable_number->real * scale; + sum->imaginary = basic_number->imaginary + scalable_number->imaginary * scale; +} + +inline void bgc_complex_add_scaled_fp64(const BgcComplexFP64* basic_number, const BgcComplexFP64* scalable_number, const double scale, BgcComplexFP64* sum) +{ + sum->real = basic_number->real + scalable_number->real * scale; + sum->imaginary = basic_number->imaginary + scalable_number->imaginary * scale; +} + +// ================== Subtract ================== // + +inline void bgc_complex_subtract_fp32(const BgcComplexFP32* minuend, const BgcComplexFP32* subtrahend, BgcComplexFP32* difference) +{ + difference->real = minuend->real - subtrahend->real; + difference->imaginary = minuend->imaginary - subtrahend->imaginary; +} + +inline void bgc_complex_subtract_fp64(const BgcComplexFP64* minuend, const BgcComplexFP64* subtrahend, BgcComplexFP64* difference) +{ + difference->real = minuend->real - subtrahend->real; + difference->imaginary = minuend->imaginary - subtrahend->imaginary; +} + +// ============== Subtract scaled =============== // + +inline void bgc_complex_subtract_scaled_fp32(const BgcComplexFP32* basic_number, const BgcComplexFP32* scalable_number, const float scale, BgcComplexFP32* difference) +{ + difference->real = basic_number->real - scalable_number->real * scale; + difference->imaginary = basic_number->imaginary - scalable_number->imaginary * scale; +} + +inline void bgc_complex_subtract_scaled_fp64(const BgcComplexFP64* basic_number, const BgcComplexFP64* scalable_number, const double scale, BgcComplexFP64* difference) +{ + difference->real = basic_number->real - scalable_number->real * scale; + difference->imaginary = basic_number->imaginary - scalable_number->imaginary * scale; +} + +// ================== Multiply ================== // + +inline void bgc_complex_multiply_fp32(const BgcComplexFP32* multiplicand, const float multiplier, BgcComplexFP32* product) +{ + product->real = multiplicand->real * multiplier; + product->imaginary = multiplicand->imaginary * multiplier; +} + +inline void bgc_complex_multiply_fp64(const BgcComplexFP64* multiplicand, const double multiplier, BgcComplexFP64* product) +{ + product->real = multiplicand->real * multiplier; + product->imaginary = multiplicand->imaginary * multiplier; +} + +// =================== Divide =================== // + +inline void bgc_complex_divide_fp32(const BgcComplexFP32* dividend, const float divisor, BgcComplexFP32* quotient) +{ + bgc_complex_multiply_fp32(dividend, 1.0f / divisor, quotient); +} + +inline void bgc_complex_divide_fp64(const BgcComplexFP64* dividend, const double divisor, BgcComplexFP64* quotient) +{ + bgc_complex_multiply_fp64(dividend, 1.0 / divisor, quotient); +} + +// ================== Average2 ================== // + +inline void bgc_complex_get_mean_of_two_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, BgcComplexFP32* mean) +{ + mean->real = (number1->real + number2->real) * 0.5f; + mean->imaginary = (number1->imaginary + number2->imaginary) * 0.5f; +} + +inline void bgc_complex_get_mean_of_two_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, BgcComplexFP64* mean) +{ + mean->real = (number1->real + number2->real) * 0.5; + mean->imaginary = (number1->imaginary + number2->imaginary) * 0.5; +} + +// ================== Average3 ================== // + +inline void bgc_complex_get_mean_of_three_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const BgcComplexFP32* number3, BgcComplexFP32* mean) +{ + mean->real = (number1->real + number2->real + number3->real) * BGC_ONE_THIRD_FP32; + mean->imaginary = (number1->imaginary + number2->imaginary + number3->imaginary) * BGC_ONE_THIRD_FP32; +} + +inline void bgc_complex_get_mean_of_three_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const BgcComplexFP64* number3, BgcComplexFP64* mean) +{ + mean->real = (number1->real + number2->real + number3->real) * BGC_ONE_THIRD_FP64; + mean->imaginary = (number1->imaginary + number2->imaginary + number3->imaginary) * BGC_ONE_THIRD_FP64; +} + +// =================== Linear =================== // + +inline void bgc_complex_get_linear_interpolation_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation) +{ + const float counterphase = 1.0f - phase; + + interpolation->real = number1->real * counterphase + number2->real * phase; + interpolation->imaginary = number1->imaginary * counterphase + number2->imaginary * phase; +} + +inline void bgc_complex_get_linear_interpolation_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation) +{ + const double counterphase = 1.0 - phase; + + interpolation->real = number1->real * counterphase + number2->real * phase; + interpolation->imaginary = number1->imaginary * counterphase + number2->imaginary * phase; +} + +// ================== Minimal =================== // + +inline void bgc_complex_minimize_fp32(const BgcComplexFP32* number, BgcComplexFP32* minimal) +{ + if (number->real < minimal->real) { + minimal->real = number->real; + } + + if (number->imaginary < minimal->imaginary) { + minimal->imaginary = number->imaginary; + } +} + +inline void bgc_complex_minimize_fp64(const BgcComplexFP64* number, BgcComplexFP64* minimal) +{ + if (number->real < minimal->real) { + minimal->real = number->real; + } + + if (number->imaginary < minimal->imaginary) { + minimal->imaginary = number->imaginary; + } +} + +// ================== Maximal =================== // + +inline void bgc_complex_maximize_fp32(const BgcComplexFP32* number, BgcComplexFP32* maximal) +{ + if (number->real > maximal->real) { + maximal->real = number->real; + } + + if (number->imaginary > maximal->imaginary) { + maximal->imaginary = number->imaginary; + } +} + +inline void bgc_complex_maximize_fp64(const BgcComplexFP64* number, BgcComplexFP64* maximal) +{ + if (number->real > maximal->real) { + maximal->real = number->real; + } + + if (number->imaginary > maximal->imaginary) { + maximal->imaginary = number->imaginary; + } +} + +// ================== Are Close ================= // + +inline int bgc_complex_are_close_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2) +{ + const float square_modulus1 = bgc_complex_get_square_modulus_fp32(number1); + const float square_modulus2 = bgc_complex_get_square_modulus_fp32(number2); + + const float d_real = number1->real - number2->real; + const float d_imaginary = number1->imaginary - number2->imaginary; + + const float square_distance = d_real * d_real + d_imaginary * d_imaginary; + + if (square_modulus1 <= BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP32 || square_modulus2 <= BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP32) { + return square_distance <= BGC_SQUARE_EPSYLON_FP32; + } + + return square_distance <= BGC_SQUARE_EPSYLON_FP32 * square_modulus1 && square_distance <= BGC_SQUARE_EPSYLON_FP32 * square_modulus2; +} + +inline int bgc_complex_are_close_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2) +{ + const double square_modulus1 = bgc_complex_get_square_modulus_fp64(number1); + const double square_modulus2 = bgc_complex_get_square_modulus_fp64(number2); + + const double d_real = number1->real - number2->real; + const double d_imaginary = number1->imaginary - number2->imaginary; + + const double square_distance = d_real * d_real + d_imaginary * d_imaginary; + + if (square_modulus1 <= BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP64 || square_modulus2 <= BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP64) { + return square_distance <= BGC_SQUARE_EPSYLON_FP64; + } + + return square_distance <= BGC_SQUARE_EPSYLON_FP32 * square_modulus1 && square_distance <= BGC_SQUARE_EPSYLON_FP32 * square_modulus2; +} + +#endif diff --git a/basic-geometry/cotes-number.c b/basic-geometry/cotes-number.c new file mode 100644 index 0000000..fc7cc57 --- /dev/null +++ b/basic-geometry/cotes-number.c @@ -0,0 +1,82 @@ +#include "./cotes-number.h" + +const BgcCotesNumberFP32 BGC_IDLE_COTES_NUMBER_FP32 = { 1.0f, 0.0f }; + +const BgcCotesNumberFP64 BGC_IDLE_COTES_NUMBER_FP64 = { 1.0, 0.0 }; + +extern inline void bgc_cotes_number_reset_fp32(BgcCotesNumberFP32* number); +extern inline void bgc_cotes_number_reset_fp64(BgcCotesNumberFP64* number); + +extern inline void bgc_cotes_number_set_values_fp32(const float x1, const float x2, BgcCotesNumberFP32* number); +extern inline void bgc_cotes_number_set_values_fp64(const double x1, const double x2, BgcCotesNumberFP64* number); + +extern inline void bgc_cotes_number_set_turn_fp32(const float angle, const BgcAngleUnitEnum unit, BgcCotesNumberFP32* number); +extern inline void bgc_cotes_number_set_turn_fp64(const double angle, const BgcAngleUnitEnum unit, BgcCotesNumberFP64* number); + +extern inline float bgc_cotes_number_get_angle_fp32(const BgcCotesNumberFP32* number, const BgcAngleUnitEnum unit); +extern inline double bgc_cotes_number_get_angle_fp64(const BgcCotesNumberFP64* number, const BgcAngleUnitEnum unit); + +extern inline void bgc_cotes_number_copy_fp32(const BgcCotesNumberFP32* source, BgcCotesNumberFP32* destination); +extern inline void bgc_cotes_number_copy_fp64(const BgcCotesNumberFP64* source, BgcCotesNumberFP64* destination); + +extern inline void bgc_cotes_number_swap_fp32(BgcCotesNumberFP32* number1, BgcCotesNumberFP32* number2); +extern inline void bgc_cotes_number_swap_fp64(BgcCotesNumberFP64* number1, BgcCotesNumberFP64* number2); + +extern inline void bgc_cotes_number_convert_fp64_to_fp32(const BgcCotesNumberFP64* source, BgcCotesNumberFP32* destination); +extern inline void bgc_cotes_number_convert_fp32_to_fp64(const BgcCotesNumberFP32* source, BgcCotesNumberFP64* destination); + +extern inline void bgc_cotes_number_invert_fp32(const BgcCotesNumberFP32* number, BgcCotesNumberFP32* inverted); +extern inline void bgc_cotes_number_invert_fp64(const BgcCotesNumberFP64* number, BgcCotesNumberFP64* inverted); + +extern inline void bgc_cotes_number_get_exponation_fp32(const BgcCotesNumberFP32* base, const float exponent, BgcCotesNumberFP32* power); +extern inline void bgc_cotes_number_get_exponation_fp64(const BgcCotesNumberFP64* base, const double exponent, BgcCotesNumberFP64* power); + +extern inline void bgc_cotes_number_combine_fp32(const BgcCotesNumberFP32* number1, const BgcCotesNumberFP32* number2, BgcCotesNumberFP32* result); +extern inline void bgc_cotes_number_combine_fp64(const BgcCotesNumberFP64* number1, const BgcCotesNumberFP64* number2, BgcCotesNumberFP64* result); + +extern inline void bgc_cotes_number_get_rotation_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix); +extern inline void bgc_cotes_number_get_rotation_matrix_fp64(const BgcCotesNumberFP64* number, BgcMatrix2x2FP64* matrix); + +extern inline void bgc_cotes_number_get_reverse_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix); +extern inline void bgc_cotes_number_get_reverse_matrix_fp64(const BgcCotesNumberFP64* number, BgcMatrix2x2FP64* matrix); + +extern inline void bgc_cotes_number_turn_vector_fp32(const BgcCotesNumberFP32* number, const BgcVector2FP32* vector, BgcVector2FP32* result); +extern inline void bgc_cotes_number_turn_vector_fp64(const BgcCotesNumberFP64* number, const BgcVector2FP64* vector, BgcVector2FP64* result); + +extern inline void bgc_cotes_number_turn_vector_back_fp32(const BgcCotesNumberFP32* number, const BgcVector2FP32* vector, BgcVector2FP32* result); +extern inline void bgc_cotes_number_turn_vector_back_fp64(const BgcCotesNumberFP64* number, const BgcVector2FP64* vector, BgcVector2FP64* result); + +extern inline int bgc_cotes_number_are_close_fp32(const BgcCotesNumberFP32* number1, const BgcCotesNumberFP32* number2); +extern inline int bgc_cotes_number_are_close_fp64(const BgcCotesNumberFP64* number1, const BgcCotesNumberFP64* number2); + +void _bgc_cotes_number_normalize_fp32(const float square_modulus, _BgcTwinCotesNumberFP32* twin) +{ + // (square_modulus != square_modulus) is true when square_modulus is NaN + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { + twin->cos = 1.0f; + twin->sin = 0.0f; + return; + } + + const float multiplier = sqrtf(1.0f / square_modulus); + + twin->cos *= multiplier; + twin->sin *= multiplier; +} + +void _bgc_cotes_number_normalize_fp64(const double square_modulus, _BgcTwinCotesNumberFP64* twin) +{ + // (square_modulus != square_modulus) is true when square_modulus is NaN + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { + twin->cos = 1.0; + twin->sin = 0.0; + return; + } + + const double multiplier = sqrt(1.0 / square_modulus); + + twin->cos *= multiplier; + twin->sin *= multiplier; +} diff --git a/basic-geometry/cotes-number.h b/basic-geometry/cotes-number.h new file mode 100644 index 0000000..e4944a6 --- /dev/null +++ b/basic-geometry/cotes-number.h @@ -0,0 +1,374 @@ +#ifndef _BGC_COTES_NUMBER_H_ +#define _BGC_COTES_NUMBER_H_ + +#include + +#include "utilities.h" +#include "angle.h" +#include "vector2.h" +#include "matrix2x2.h" + +// =================== Types ==================== // + +typedef struct +{ + const float cos, sin; +} BgcCotesNumberFP32; + +typedef struct +{ + const double cos, sin; +} BgcCotesNumberFP64; + +// ================= Dark Twins ================= // + +typedef struct { + float cos, sin; +} _BgcTwinCotesNumberFP32; + +typedef struct { + double cos, sin; +} _BgcTwinCotesNumberFP64; + +// ================= Constants ================== // + +extern const BgcCotesNumberFP32 BGC_IDLE_COTES_NUMBER_FP32; +extern const BgcCotesNumberFP64 BGC_IDLE_COTES_NUMBER_FP64; + +// =================== Reset ==================== // + +inline void bgc_cotes_number_reset_fp32(BgcCotesNumberFP32* number) +{ + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)number; + + twin->cos = 1.0f; + twin->sin = 0.0f; +} + +inline void bgc_cotes_number_reset_fp64(BgcCotesNumberFP64* number) +{ + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)number; + + twin->cos = 1.0; + twin->sin = 0.0; +} + +// ==================== Set ===================== // + +void _bgc_cotes_number_normalize_fp32(const float square_modulus, _BgcTwinCotesNumberFP32* twin); + +void _bgc_cotes_number_normalize_fp64(const double square_modulus, _BgcTwinCotesNumberFP64* twin); + +inline void bgc_cotes_number_set_values_fp32(const float x1, const float x2, BgcCotesNumberFP32* number) +{ + const float square_modulus = x1 * x1 + x2 * x2; + + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)number; + + twin->cos = x1; + twin->sin = x2; + + if (!bgc_is_sqare_unit_fp32(square_modulus)) { + _bgc_cotes_number_normalize_fp32(square_modulus, twin); + } +} + +inline void bgc_cotes_number_set_values_fp64(const double x1, const double x2, BgcCotesNumberFP64* number) +{ + const double square_modulus = x1 * x1 + x2 * x2; + + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)number; + + twin->cos = x1; + twin->sin = x2; + + if (!bgc_is_sqare_unit_fp64(square_modulus)) { + _bgc_cotes_number_normalize_fp64(square_modulus, twin); + } +} + +// ================== Set Turn ================== // + +inline void bgc_cotes_number_set_turn_fp32(const float angle, const BgcAngleUnitEnum unit, BgcCotesNumberFP32* number) +{ + const float radians = bgc_angle_to_radians_fp32(angle, unit); + + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)number; + + twin->cos = cosf(radians); + twin->sin = sinf(radians); +} + +inline void bgc_cotes_number_set_turn_fp64(const double angle, const BgcAngleUnitEnum unit, BgcCotesNumberFP64* number) +{ + const double radians = bgc_angle_to_radians_fp64(angle, unit); + + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)number; + + twin->cos = cos(radians); + twin->sin = sin(radians); +} + +// =================== Angle =================== // + +inline float bgc_cotes_number_get_angle_fp32(const BgcCotesNumberFP32* number, const BgcAngleUnitEnum unit) +{ + if (number->cos >= 1.0f - BGC_EPSYLON_FP32) { + return 0.0f; + } + + if (number->cos <= -1.0f + BGC_EPSYLON_FP32) { + return bgc_angle_get_half_circle_fp32(unit); + } + + if (number->sin >= 1.0f - BGC_EPSYLON_FP32) { + return bgc_angle_get_quater_circle_fp32(unit); + } + + if (number->sin <= -1.0f + BGC_EPSYLON_FP32) { + return 0.75f * bgc_angle_get_full_circle_fp32(unit); + } + + return bgc_radians_to_units_fp32(atan2f(number->sin, number->cos), unit); +} + +inline double bgc_cotes_number_get_angle_fp64(const BgcCotesNumberFP64* number, const BgcAngleUnitEnum unit) +{ + if (number->cos >= 1.0 - BGC_EPSYLON_FP64) { + return 0.0; + } + + if (number->cos <= -1.0 + BGC_EPSYLON_FP64) { + return bgc_angle_get_half_circle_fp64(unit); + } + + if (number->sin >= 1.0 - BGC_EPSYLON_FP64) { + return bgc_angle_get_quater_circle_fp64(unit); + } + + if (number->sin <= -1.0 + BGC_EPSYLON_FP64) { + return 0.75 * bgc_angle_get_full_circle_fp64(unit); + } + + return bgc_radians_to_units_fp64(atan2(number->sin, number->cos), unit); +} + +// ==================== Copy ==================== // + +inline void bgc_cotes_number_copy_fp32(const BgcCotesNumberFP32* source, BgcCotesNumberFP32* destination) +{ + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)destination; + + twin->cos = source->cos; + twin->sin = source->sin; +} + +inline void bgc_cotes_number_copy_fp64(const BgcCotesNumberFP64* source, BgcCotesNumberFP64* destination) +{ + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)destination; + + twin->cos = source->cos; + twin->sin = source->sin; +} + +// ==================== Swap ==================== // + +inline void bgc_cotes_number_swap_fp32(BgcCotesNumberFP32* number1, BgcCotesNumberFP32* number2) +{ + const float cos = number1->cos; + const float sin = number1->sin; + + _BgcTwinCotesNumberFP32* twin1 = (_BgcTwinCotesNumberFP32*)number1; + + twin1->cos = number2->cos; + twin1->sin = number2->sin; + + _BgcTwinCotesNumberFP32* twin2 = (_BgcTwinCotesNumberFP32*)number2; + + twin2->cos = cos; + twin2->sin = sin; +} + +inline void bgc_cotes_number_swap_fp64(BgcCotesNumberFP64* number1, BgcCotesNumberFP64* number2) +{ + const double cos = number1->cos; + const double sin = number1->sin; + + _BgcTwinCotesNumberFP64* twin1 = (_BgcTwinCotesNumberFP64*)number1; + + twin1->cos = number2->cos; + twin1->sin = number2->sin; + + _BgcTwinCotesNumberFP64* twin2 = (_BgcTwinCotesNumberFP64*)number2; + + twin2->cos = cos; + twin2->sin = sin; +} + +// ================== Convert =================== // + +inline void bgc_cotes_number_convert_fp64_to_fp32(const BgcCotesNumberFP64* source, BgcCotesNumberFP32* destination) +{ + bgc_cotes_number_set_values_fp32((float)source->cos, (float)source->sin, destination); +} + +inline void bgc_cotes_number_convert_fp32_to_fp64(const BgcCotesNumberFP32* source, BgcCotesNumberFP64* destination) +{ + bgc_cotes_number_set_values_fp64((double)source->cos, (double)source->sin, destination); +} + +// =================== Invert =================== // + +inline void bgc_cotes_number_invert_fp32(const BgcCotesNumberFP32* number, BgcCotesNumberFP32* inverted) +{ + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)inverted; + + twin->cos = number->cos; + twin->sin = -number->sin; +} + +inline void bgc_cotes_number_invert_fp64(const BgcCotesNumberFP64* number, BgcCotesNumberFP64* inverted) +{ + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)inverted; + + twin->cos = number->cos; + twin->sin = -number->sin; +} + +// ================= Exponation ================= // + +inline void bgc_cotes_number_get_exponation_fp32(const BgcCotesNumberFP32* base, const float exponent, BgcCotesNumberFP32* power) +{ + const float power_angle = exponent * atan2f(base->sin, base->cos); + + _BgcTwinCotesNumberFP32* twin = (_BgcTwinCotesNumberFP32*)power; + + twin->cos = cosf(power_angle); + twin->sin = sinf(power_angle); +} + +inline void bgc_cotes_number_get_exponation_fp64(const BgcCotesNumberFP64* base, const double exponent, BgcCotesNumberFP64* power) +{ + const double power_angle = exponent * atan2(base->sin, base->cos); + + _BgcTwinCotesNumberFP64* twin = (_BgcTwinCotesNumberFP64*)power; + + twin->cos = cos(power_angle); + twin->sin = sin(power_angle); +} + +// ================ Combination ================= // + +inline void bgc_cotes_number_combine_fp32(const BgcCotesNumberFP32* number1, const BgcCotesNumberFP32* number2, BgcCotesNumberFP32* result) +{ + bgc_cotes_number_set_values_fp32( + number1->cos * number2->cos - number1->sin * number2->sin, + number1->cos * number2->sin + number1->sin * number2->cos, + result + ); +} + +inline void bgc_cotes_number_combine_fp64(const BgcCotesNumberFP64* number1, const BgcCotesNumberFP64* number2, BgcCotesNumberFP64* result) +{ + bgc_cotes_number_set_values_fp64( + number1->cos * number2->cos - number1->sin * number2->sin, + number1->cos * number2->sin + number1->sin * number2->cos, + result + ); +} + +// ============== Rotation Matrix =============== // + +inline void bgc_cotes_number_get_rotation_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix) +{ + matrix->r1c1 = number->cos; + matrix->r1c2 = -number->sin; + matrix->r2c1 = number->sin; + matrix->r2c2 = number->cos; +} + +inline void bgc_cotes_number_get_rotation_matrix_fp64(const BgcCotesNumberFP64* number, BgcMatrix2x2FP64* matrix) +{ + matrix->r1c1 = number->cos; + matrix->r1c2 = -number->sin; + matrix->r2c1 = number->sin; + matrix->r2c2 = number->cos; +} + +// ============== Reverse Matrix ================ // + +inline void bgc_cotes_number_get_reverse_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix) +{ + matrix->r1c1 = number->cos; + matrix->r1c2 = number->sin; + matrix->r2c1 = -number->sin; + matrix->r2c2 = number->cos; +} + +inline void bgc_cotes_number_get_reverse_matrix_fp64(const BgcCotesNumberFP64* number, BgcMatrix2x2FP64* matrix) +{ + matrix->r1c1 = number->cos; + matrix->r1c2 = number->sin; + matrix->r2c1 = -number->sin; + matrix->r2c2 = number->cos; +} + +// ================ Turn Vector ================= // + +inline void bgc_cotes_number_turn_vector_fp32(const BgcCotesNumberFP32* number, const BgcVector2FP32* vector, BgcVector2FP32* result) +{ + const float x1 = number->cos * vector->x1 - number->sin * vector->x2; + const float x2 = number->sin * vector->x1 + number->cos * vector->x2; + + result->x1 = x1; + result->x2 = x2; +} + +inline void bgc_cotes_number_turn_vector_fp64(const BgcCotesNumberFP64* number, const BgcVector2FP64* vector, BgcVector2FP64* result) +{ + const double x1 = number->cos * vector->x1 - number->sin * vector->x2; + const double x2 = number->sin * vector->x1 + number->cos * vector->x2; + + result->x1 = x1; + result->x2 = x2; +} + +// ============ Turn Vector Backward ============ // + +inline void bgc_cotes_number_turn_vector_back_fp32(const BgcCotesNumberFP32* number, const BgcVector2FP32* vector, BgcVector2FP32* result) +{ + const float x1 = number->sin * vector->x2 + number->cos * vector->x1; + const float x2 = number->cos * vector->x2 - number->sin * vector->x1; + + result->x1 = x1; + result->x2 = x2; +} + +inline void bgc_cotes_number_turn_vector_back_fp64(const BgcCotesNumberFP64* number, const BgcVector2FP64* vector, BgcVector2FP64* result) +{ + const double x1 = number->sin * vector->x2 + number->cos * vector->x1; + const double x2 = number->cos * vector->x2 - number->sin * vector->x1; + + result->x1 = x1; + result->x2 = x2; +} + +// ================== Are Close ================= // + +inline int bgc_cotes_number_are_close_fp32(const BgcCotesNumberFP32* number1, const BgcCotesNumberFP32* number2) +{ + const float d_cos = number1->cos - number2->cos; + const float d_sin = number1->sin - number2->sin; + + return d_cos * d_cos + d_sin * d_sin <= BGC_SQUARE_EPSYLON_FP32; +} + +inline int bgc_cotes_number_are_close_fp64(const BgcCotesNumberFP64* number1, const BgcCotesNumberFP64* number2) +{ + const double d_cos = number1->cos - number2->cos; + const double d_sin = number1->sin - number2->sin; + + return d_cos * d_cos + d_sin * d_sin <= BGC_SQUARE_EPSYLON_FP64; +} + +#endif diff --git a/basic-geometry/quaternion.c b/basic-geometry/quaternion.c index 6694803..963dba7 100644 --- a/basic-geometry/quaternion.c +++ b/basic-geometry/quaternion.c @@ -72,5 +72,9 @@ extern inline int bgc_quaternion_get_rotation_matrix_fp64(const BgcQuaternionFP6 extern inline int bgc_quaternion_get_reverse_matrix_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* reverse); extern inline int bgc_quaternion_get_reverse_matrix_fp64(const BgcQuaternionFP64* quaternion, BgcMatrix3x3FP64* reverse); +extern inline int bgc_quaternion_get_both_matrixes_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* rotation, BgcMatrix3x3FP32* reverse); +extern inline int bgc_quaternion_get_both_matrixes_fp64(const BgcQuaternionFP64* quaternion, BgcMatrix3x3FP64* rotation, BgcMatrix3x3FP64* reverse); + + extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); diff --git a/basic-geometry/quaternion.h b/basic-geometry/quaternion.h index c88b66b..54be3fa 100644 --- a/basic-geometry/quaternion.h +++ b/basic-geometry/quaternion.h @@ -659,6 +659,8 @@ inline int bgc_quaternion_get_reverse_matrix_fp64(const BgcQuaternionFP64* quate return 1; } +// ============= Get Both Matrixes ============== // + inline int bgc_quaternion_get_both_matrixes_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* rotation, BgcMatrix3x3FP32* reverse) { if (bgc_quaternion_get_reverse_matrix_fp32(quaternion, reverse)) { diff --git a/basic-geometry/tangent-pair.c b/basic-geometry/tangent-pair.c deleted file mode 100644 index c38571a..0000000 --- a/basic-geometry/tangent-pair.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "tangent-pair.h" - -const BgcTangentPairFP32 BGC_IDLE_TANGENT_PAIR_FP32 = { 1.0f, 0.0f }; - -const BgcTangentPairFP64 BGC_IDLE_TANGENT_PAIR_FP64 = { 1.0, 0.0 }; - -extern inline void bgc_tangent_pair_reset_fp32(BgcTangentPairFP32* tangent); -extern inline void bgc_tangent_pair_reset_fp64(BgcTangentPairFP64* tangent); - -extern inline void bgc_tangent_pair_set_values_fp32(const float x1, const float x2, BgcTangentPairFP32* tangent); -extern inline void bgc_tangent_pair_set_values_fp64(const double x1, const double x2, BgcTangentPairFP64* tangent); - -extern inline void bgc_tangent_pair_set_turn_fp32(const float angle, const BgcAngleUnitEnum unit, BgcTangentPairFP32* tangent); -extern inline void bgc_tangent_pair_set_turn_fp64(const double angle, const BgcAngleUnitEnum unit, BgcTangentPairFP64* tangent); - -extern inline float bgc_tangent_pair_get_angle_fp32(const BgcTangentPairFP32* tangent, const BgcAngleUnitEnum unit); -extern inline double bgc_tangent_pair_get_angle_fp64(const BgcTangentPairFP64* tangent, const BgcAngleUnitEnum unit); - -extern inline void bgc_tangent_pair_copy_fp32(const BgcTangentPairFP32* source, BgcTangentPairFP32* destination); -extern inline void bgc_tangent_pair_copy_fp64(const BgcTangentPairFP64* source, BgcTangentPairFP64* destination); - -extern inline void bgc_tangent_pair_swap_fp32(BgcTangentPairFP32* tangent1, BgcTangentPairFP32* tangent2); -extern inline void bgc_tangent_pair_swap_fp64(BgcTangentPairFP64* tangent1, BgcTangentPairFP64* tangent2); - -extern inline void bgc_tangent_pair_convert_fp64_to_fp32(const BgcTangentPairFP64* source, BgcTangentPairFP32* destination); -extern inline void bgc_tangent_pair_convert_fp32_to_fp64(const BgcTangentPairFP32* source, BgcTangentPairFP64* destination); - -extern inline void bgc_tangent_pair_invert_fp32(const BgcTangentPairFP32* tangent, BgcTangentPairFP32* inverted); -extern inline void bgc_tangent_pair_invert_fp64(const BgcTangentPairFP64* tangent, BgcTangentPairFP64* inverted); - -extern inline void bgc_tangent_pair_combine_fp32(const BgcTangentPairFP32* tangent1, const BgcTangentPairFP32* tangent2, BgcTangentPairFP32* result); -extern inline void bgc_tangent_pair_combine_fp64(const BgcTangentPairFP64* tangent1, const BgcTangentPairFP64* tangent2, BgcTangentPairFP64* result); - -extern inline void bgc_tangent_pair_get_rotation_matrix_fp32(const BgcTangentPairFP32* tangent, BgcMatrix2x2FP32* matrix); -extern inline void bgc_tangent_pair_get_rotation_matrix_fp64(const BgcTangentPairFP64* tangent, BgcMatrix2x2FP64* matrix); - -extern inline void bgc_tangent_pair_get_reverse_matrix_fp32(const BgcTangentPairFP32* tangent, BgcMatrix2x2FP32* matrix); -extern inline void bgc_tangent_pair_get_reverse_matrix_fp64(const BgcTangentPairFP64* tangent, BgcMatrix2x2FP64* matrix); - -extern inline void bgc_tangent_pair_turn_vector_fp32(const BgcTangentPairFP32* tangent, const BgcVector2FP32* vector, BgcVector2FP32* result); -extern inline void bgc_tangent_pair_turn_vector_fp64(const BgcTangentPairFP64* tangent, const BgcVector2FP64* vector, BgcVector2FP64* result); - -extern inline void bgc_tangent_pair_turn_vector_back_fp32(const BgcTangentPairFP32* tangent, const BgcVector2FP32* vector, BgcVector2FP32* result); -extern inline void bgc_tangent_pair_turn_vector_back_fp64(const BgcTangentPairFP64* tangent, const BgcVector2FP64* vector, BgcVector2FP64* result); - -extern inline int bgc_tangent_pair_are_close_fp32(const BgcTangentPairFP32* tangent1, const BgcTangentPairFP32* tangent2); -extern inline int bgc_tangent_pair_are_close_fp64(const BgcTangentPairFP64* tangent1, const BgcTangentPairFP64* tangent2); - -void _bgc_tangent_pair_normalize_fp32(const float square_modulus, _BgcTwinTangentPairFP32* twin) -{ - // (square_modulus != square_modulus) is true when square_modulus is NaN - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { - twin->cos = 1.0f; - twin->sin = 0.0f; - return; - } - - const float multiplier = sqrtf(1.0f / square_modulus); - - twin->cos *= multiplier; - twin->sin *= multiplier; -} - -void _bgc_tangent_pair_normalize_fp64(const double square_modulus, _BgcTwinTangentPairFP64* twin) -{ - // (square_modulus != square_modulus) is true when square_modulus is NaN - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { - twin->cos = 1.0; - twin->sin = 0.0; - return; - } - - const double multiplier = sqrt(1.0 / square_modulus); - - twin->cos *= multiplier; - twin->sin *= multiplier; -} diff --git a/basic-geometry/tangent-pair.h b/basic-geometry/tangent-pair.h deleted file mode 100644 index 40c5c15..0000000 --- a/basic-geometry/tangent-pair.h +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef _bgc_tangent_pair_H_ -#define _bgc_tangent_pair_H_ - -#include - -#include "utilities.h" -#include "angle.h" -#include "vector2.h" -#include "matrix2x2.h" - -// =================== Types ==================== // - -typedef struct -{ - const float cos, sin; -} BgcTangentPairFP32; - -typedef struct -{ - const double cos, sin; -} BgcTangentPairFP64; - -// ================= Dark Twins ================= // - -typedef struct { - float cos, sin; -} _BgcTwinTangentPairFP32; - -typedef struct { - double cos, sin; -} _BgcTwinTangentPairFP64; - -// ================= Constants ================== // - -extern const BgcTangentPairFP32 BGC_IDLE_TANGENT_PAIR_FP32; -extern const BgcTangentPairFP64 BGC_IDLE_TANGENT_PAIR_FP64; - -// =================== Reset ==================== // - -inline void bgc_tangent_pair_reset_fp32(BgcTangentPairFP32* tangent) -{ - _BgcTwinTangentPairFP32* twin = (_BgcTwinTangentPairFP32*)tangent; - - twin->cos = 1.0f; - twin->sin = 0.0f; -} - -inline void bgc_tangent_pair_reset_fp64(BgcTangentPairFP64* tangent) -{ - _BgcTwinTangentPairFP64* twin = (_BgcTwinTangentPairFP64*)tangent; - - twin->cos = 1.0; - twin->sin = 0.0; -} - -// ==================== Set ===================== // - -void _bgc_tangent_pair_normalize_fp32(const float square_modulus, _BgcTwinTangentPairFP32* twin); - -void _bgc_tangent_pair_normalize_fp64(const double square_modulus, _BgcTwinTangentPairFP64* twin); - -inline void bgc_tangent_pair_set_values_fp32(const float x1, const float x2, BgcTangentPairFP32* tangent) -{ - const float square_modulus = x1 * x1 + x2 * x2; - - _BgcTwinTangentPairFP32* twin = (_BgcTwinTangentPairFP32*)tangent; - - twin->cos = x1; - twin->sin = x2; - - if (!bgc_is_sqare_unit_fp32(square_modulus)) { - _bgc_tangent_pair_normalize_fp32(square_modulus, twin); - } -} - -inline void bgc_tangent_pair_set_values_fp64(const double x1, const double x2, BgcTangentPairFP64* tangent) -{ - const double square_modulus = x1 * x1 + x2 * x2; - - _BgcTwinTangentPairFP64* twin = (_BgcTwinTangentPairFP64*)tangent; - - twin->cos = x1; - twin->sin = x2; - - if (!bgc_is_sqare_unit_fp64(square_modulus)) { - _bgc_tangent_pair_normalize_fp64(square_modulus, twin); - } -} - -// ================== Set Turn ================== // - -inline void bgc_tangent_pair_set_turn_fp32(const float angle, const BgcAngleUnitEnum unit, BgcTangentPairFP32* tangent) -{ - const float radians = bgc_angle_to_radians_fp32(angle, unit); - - _BgcTwinTangentPairFP32* twin = (_BgcTwinTangentPairFP32*)tangent; - - twin->cos = cosf(radians); - twin->sin = sinf(radians); -} - -inline void bgc_tangent_pair_set_turn_fp64(const double angle, const BgcAngleUnitEnum unit, BgcTangentPairFP64* tangent) -{ - const double radians = bgc_angle_to_radians_fp64(angle, unit); - - _BgcTwinTangentPairFP64* twin = (_BgcTwinTangentPairFP64*)tangent; - - twin->cos = cos(radians); - twin->sin = sin(radians); -} - -// =================== Angle =================== // - -inline float bgc_tangent_pair_get_angle_fp32(const BgcTangentPairFP32* tangent, const BgcAngleUnitEnum unit) -{ - if (tangent->cos >= 1.0f - BGC_EPSYLON_FP32) { - return 0.0f; - } - - if (tangent->cos <= -1.0f + BGC_EPSYLON_FP32) { - return bgc_angle_get_half_circle_fp32(unit); - } - - if (tangent->sin >= 1.0f - BGC_EPSYLON_FP32) { - return bgc_angle_get_quater_circle_fp32(unit); - } - - if (tangent->sin <= -1.0f + BGC_EPSYLON_FP32) { - return 0.75f * bgc_angle_get_full_circle_fp32(unit); - } - - return bgc_radians_to_units_fp32(atan2f(tangent->sin, tangent->cos), unit); -} - -inline double bgc_tangent_pair_get_angle_fp64(const BgcTangentPairFP64* tangent, const BgcAngleUnitEnum unit) -{ - if (tangent->cos >= 1.0 - BGC_EPSYLON_FP64) { - return 0.0; - } - - if (tangent->cos <= -1.0 + BGC_EPSYLON_FP64) { - return bgc_angle_get_half_circle_fp64(unit); - } - - if (tangent->sin >= 1.0 - BGC_EPSYLON_FP64) { - return bgc_angle_get_quater_circle_fp64(unit); - } - - if (tangent->sin <= -1.0 + BGC_EPSYLON_FP64) { - return 0.75 * bgc_angle_get_full_circle_fp64(unit); - } - - return bgc_radians_to_units_fp64(atan2(tangent->sin, tangent->cos), unit); -} - -// ==================== Copy ==================== // - -inline void bgc_tangent_pair_copy_fp32(const BgcTangentPairFP32* source, BgcTangentPairFP32* destination) -{ - _BgcTwinTangentPairFP32* twin = (_BgcTwinTangentPairFP32*)destination; - - twin->cos = source->cos; - twin->sin = source->sin; -} - -inline void bgc_tangent_pair_copy_fp64(const BgcTangentPairFP64* source, BgcTangentPairFP64* destination) -{ - _BgcTwinTangentPairFP64* twin = (_BgcTwinTangentPairFP64*)destination; - - twin->cos = source->cos; - twin->sin = source->sin; -} - -// ==================== Swap ==================== // - -inline void bgc_tangent_pair_swap_fp32(BgcTangentPairFP32* tangent1, BgcTangentPairFP32* tangent2) -{ - const float cos = tangent1->cos; - const float sin = tangent1->sin; - - _BgcTwinTangentPairFP32* twin1 = (_BgcTwinTangentPairFP32*)tangent1; - - twin1->cos = tangent2->cos; - twin1->sin = tangent2->sin; - - _BgcTwinTangentPairFP32* twin2 = (_BgcTwinTangentPairFP32*)tangent2; - - twin2->cos = cos; - twin2->sin = sin; -} - -inline void bgc_tangent_pair_swap_fp64(BgcTangentPairFP64* tangent1, BgcTangentPairFP64* tangent2) -{ - const double cos = tangent1->cos; - const double sin = tangent1->sin; - - _BgcTwinTangentPairFP64* twin1 = (_BgcTwinTangentPairFP64*)tangent1; - - twin1->cos = tangent2->cos; - twin1->sin = tangent2->sin; - - _BgcTwinTangentPairFP64* twin2 = (_BgcTwinTangentPairFP64*)tangent2; - - twin2->cos = cos; - twin2->sin = sin; -} - -// ================== Convert =================== // - -inline void bgc_tangent_pair_convert_fp64_to_fp32(const BgcTangentPairFP64* source, BgcTangentPairFP32* destination) -{ - bgc_tangent_pair_set_values_fp32((float)source->cos, (float)source->sin, destination); -} - -inline void bgc_tangent_pair_convert_fp32_to_fp64(const BgcTangentPairFP32* source, BgcTangentPairFP64* destination) -{ - bgc_tangent_pair_set_values_fp64((double)source->cos, (double)source->sin, destination); -} - -// =================== Invert =================== // - -inline void bgc_tangent_pair_invert_fp32(const BgcTangentPairFP32* tangent, BgcTangentPairFP32* inverted) -{ - _BgcTwinTangentPairFP32* twin = (_BgcTwinTangentPairFP32*)inverted; - - twin->cos = tangent->cos; - twin->sin = -tangent->sin; -} - -inline void bgc_tangent_pair_invert_fp64(const BgcTangentPairFP64* tangent, BgcTangentPairFP64* inverted) -{ - _BgcTwinTangentPairFP64* twin = (_BgcTwinTangentPairFP64*)inverted; - - twin->cos = tangent->cos; - twin->sin = -tangent->sin; -} - -// ================ Combination ================= // - -inline void bgc_tangent_pair_combine_fp32(const BgcTangentPairFP32* tangent1, const BgcTangentPairFP32* tangent2, BgcTangentPairFP32* result) -{ - bgc_tangent_pair_set_values_fp32( - tangent1->cos * tangent2->cos - tangent1->sin * tangent2->sin, - tangent1->cos * tangent2->sin + tangent1->sin * tangent2->cos, - result - ); -} - -inline void bgc_tangent_pair_combine_fp64(const BgcTangentPairFP64* tangent1, const BgcTangentPairFP64* tangent2, BgcTangentPairFP64* result) -{ - bgc_tangent_pair_set_values_fp64( - tangent1->cos * tangent2->cos - tangent1->sin * tangent2->sin, - tangent1->cos * tangent2->sin + tangent1->sin * tangent2->cos, - result - ); -} - -// ============== Rotation Matrix =============== // - -inline void bgc_tangent_pair_get_rotation_matrix_fp32(const BgcTangentPairFP32* tangent, BgcMatrix2x2FP32* matrix) -{ - matrix->r1c1 = tangent->cos; - matrix->r1c2 = -tangent->sin; - matrix->r2c1 = tangent->sin; - matrix->r2c2 = tangent->cos; -} - -inline void bgc_tangent_pair_get_rotation_matrix_fp64(const BgcTangentPairFP64* tangent, BgcMatrix2x2FP64* matrix) -{ - matrix->r1c1 = tangent->cos; - matrix->r1c2 = -tangent->sin; - matrix->r2c1 = tangent->sin; - matrix->r2c2 = tangent->cos; -} - -// ============== Reverse Matrix ================ // - -inline void bgc_tangent_pair_get_reverse_matrix_fp32(const BgcTangentPairFP32* tangent, BgcMatrix2x2FP32* matrix) -{ - matrix->r1c1 = tangent->cos; - matrix->r1c2 = tangent->sin; - matrix->r2c1 = -tangent->sin; - matrix->r2c2 = tangent->cos; -} - -inline void bgc_tangent_pair_get_reverse_matrix_fp64(const BgcTangentPairFP64* tangent, BgcMatrix2x2FP64* matrix) -{ - matrix->r1c1 = tangent->cos; - matrix->r1c2 = tangent->sin; - matrix->r2c1 = -tangent->sin; - matrix->r2c2 = tangent->cos; -} - -// ================ Turn Vector ================= // - -inline void bgc_tangent_pair_turn_vector_fp32(const BgcTangentPairFP32* tangent, const BgcVector2FP32* vector, BgcVector2FP32* result) -{ - const float x1 = tangent->cos * vector->x1 - tangent->sin * vector->x2; - const float x2 = tangent->sin * vector->x1 + tangent->cos * vector->x2; - - result->x1 = x1; - result->x2 = x2; -} - -inline void bgc_tangent_pair_turn_vector_fp64(const BgcTangentPairFP64* tangent, const BgcVector2FP64* vector, BgcVector2FP64* result) -{ - const double x1 = tangent->cos * vector->x1 - tangent->sin * vector->x2; - const double x2 = tangent->sin * vector->x1 + tangent->cos * vector->x2; - - result->x1 = x1; - result->x2 = x2; -} - -// ============ Turn Vector Backward ============ // - -inline void bgc_tangent_pair_turn_vector_back_fp32(const BgcTangentPairFP32* tangent, const BgcVector2FP32* vector, BgcVector2FP32* result) -{ - const float x1 = tangent->sin * vector->x2 + tangent->cos * vector->x1; - const float x2 = tangent->cos * vector->x2 - tangent->sin * vector->x1; - - result->x1 = x1; - result->x2 = x2; -} - -inline void bgc_tangent_pair_turn_vector_back_fp64(const BgcTangentPairFP64* tangent, const BgcVector2FP64* vector, BgcVector2FP64* result) -{ - const double x1 = tangent->sin * vector->x2 + tangent->cos * vector->x1; - const double x2 = tangent->cos * vector->x2 - tangent->sin * vector->x1; - - result->x1 = x1; - result->x2 = x2; -} - -// ================== Are Close ================= // - -inline int bgc_tangent_pair_are_close_fp32(const BgcTangentPairFP32* tangent1, const BgcTangentPairFP32* tangent2) -{ - const float d_cos = tangent1->cos - tangent2->cos; - const float d_sin = tangent1->sin - tangent2->sin; - - return d_cos * d_cos + d_sin * d_sin <= BGC_SQUARE_EPSYLON_FP32; -} - -inline int bgc_tangent_pair_are_close_fp64(const BgcTangentPairFP64* tangent1, const BgcTangentPairFP64* tangent2) -{ - const double d_cos = tangent1->cos - tangent2->cos; - const double d_sin = tangent1->sin - tangent2->sin; - - return d_cos * d_cos + d_sin * d_sin <= BGC_SQUARE_EPSYLON_FP64; -} - -#endif diff --git a/basic-geometry/vector2.c b/basic-geometry/vector2.c index af738d4..b0b7c64 100644 --- a/basic-geometry/vector2.c +++ b/basic-geometry/vector2.c @@ -33,12 +33,6 @@ extern inline void bgc_vector2_reverse_fp64(const BgcVector2FP64* vector, BgcVec extern inline int bgc_vector2_normalize_fp32(const BgcVector2FP32* vector, BgcVector2FP32* normalized); extern inline int bgc_vector2_normalize_fp64(const BgcVector2FP64* vector, BgcVector2FP64* normalized); -extern inline void bgc_vector2_complex_conjugate_fp32(const BgcVector2FP32* vector, BgcVector2FP32* conjugate); -extern inline void bgc_vector2_complex_conjugate_fp64(const BgcVector2FP64* vector, BgcVector2FP64* conjugate); - -extern inline int bgc_vector2_complex_invert_fp32(const BgcVector2FP32* vector, BgcVector2FP32* inverted); -extern inline int bgc_vector2_complex_invert_fp64(const BgcVector2FP64* vector, BgcVector2FP64* inverted); - extern inline void bgc_vector2_add_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, BgcVector2FP32* sum); extern inline void bgc_vector2_add_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, BgcVector2FP64* sum); @@ -78,12 +72,6 @@ extern inline double bgc_vector2_get_scalar_product_fp64(const BgcVector2FP64* v extern inline float bgc_vector2_get_cross_product_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2); extern inline double bgc_vector2_get_cross_product_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2); -extern inline void bgc_vector2_get_complex_product_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, BgcVector2FP32* product); -extern inline void bgc_vector2_get_complex_product_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, BgcVector2FP64* product); - -extern inline int bgc_vector2_get_complex_ratio_fp32(const BgcVector2FP32* divident, const BgcVector2FP32* divisor, BgcVector2FP32* quotient); -extern inline int bgc_vector2_get_complex_ratio_fp64(const BgcVector2FP64* divident, const BgcVector2FP64* divisor, BgcVector2FP64* quotient); - extern inline float bgc_vector2_get_square_distance_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2); extern inline double bgc_vector2_get_square_distance_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2); @@ -96,48 +84,6 @@ extern inline int bgc_vector2_are_close_enough_fp64(const BgcVector2FP64* vector extern inline int bgc_vector2_are_close_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2); extern inline int bgc_vector2_are_close_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2); -// =============== Complex Power ================ // - -void bgc_vector2_get_complex_power_fp32(const BgcVector2FP32* base, const BgcVector2FP32* power, BgcVector2FP32* result) -{ - const float base_square_modulus = bgc_vector2_get_square_modulus_fp32(base); - - if (base_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { - result->x1 = 0.0f; - result->x2 = 0.0f; - return; - } - - const float log_modulus = logf(base_square_modulus) * 0.5f; - const float angle = atan2f(base->x2, base->x1); - - const float result_modulus = expf(power->x1 * log_modulus - power->x2 * angle); - const float result_angle = power->x1 * angle + power->x2 * log_modulus; - - result->x1 = result_modulus * cosf(result_angle); - result->x2 = result_modulus * sinf(result_angle); -} - -void bgc_vector2_get_complex_power_fp64(const BgcVector2FP64* base, const BgcVector2FP64* power, BgcVector2FP64* result) -{ - const double base_square_modulus = bgc_vector2_get_square_modulus_fp64(base); - - if (base_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { - result->x1 = 0.0; - result->x2 = 0.0; - return; - } - - const double log_modulus = log(base_square_modulus) * 0.5; - const double angle = atan2(base->x2, base->x1); - - const double result_modulus = exp(power->x1 * log_modulus - power->x2 * angle); - const double result_angle = power->x1 * angle + power->x2 * log_modulus; - - result->x1 = result_modulus * cos(result_angle); - result->x2 = result_modulus * sin(result_angle); -} - // =================== Angle ==================== // float bgc_vector2_get_angle_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const BgcAngleUnitEnum unit) diff --git a/basic-geometry/vector2.h b/basic-geometry/vector2.h index dc8ff3c..8852721 100644 --- a/basic-geometry/vector2.h +++ b/basic-geometry/vector2.h @@ -202,54 +202,6 @@ inline int bgc_vector2_normalize_fp64(const BgcVector2FP64* vector, BgcVector2FP return 1; } -// ============= Complex Conjugate ============== // - -inline void bgc_vector2_complex_conjugate_fp32(const BgcVector2FP32* vector, BgcVector2FP32* conjugate) -{ - conjugate->x1 = vector->x1; - conjugate->x2 = -vector->x2; -} - -inline void bgc_vector2_complex_conjugate_fp64(const BgcVector2FP64* vector, BgcVector2FP64* conjugate) -{ - conjugate->x1 = vector->x1; - conjugate->x2 = -vector->x2; -} - -// =============== Complex Invert =============== // - -inline int bgc_vector2_complex_invert_fp32(const BgcVector2FP32* vector, BgcVector2FP32* inverted) -{ - const float square_modulus = bgc_vector2_get_square_modulus_fp32(vector); - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { - return 0; - } - - const float multiplicand = 1.0f / square_modulus; - - inverted->x1 = vector->x1 * multiplicand; - inverted->x2 = -vector->x2 * multiplicand; - - return 1; -} - -inline int bgc_vector2_complex_invert_fp64(const BgcVector2FP64* vector, BgcVector2FP64* inverted) -{ - const double square_modulus = bgc_vector2_get_square_modulus_fp64(vector); - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { - return 0; - } - - const double multiplicand = 1.0 / square_modulus; - - inverted->x1 = vector->x1 * multiplicand; - inverted->x2 = -vector->x2 * multiplicand; - - return 1; -} - // ==================== Add ===================== // inline void bgc_vector2_add_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, BgcVector2FP32* sum) @@ -450,72 +402,6 @@ inline double bgc_vector2_get_cross_product_fp64(const BgcVector2FP64* vector1, return vector1->x1 * vector2->x2 - vector1->x2 * vector2->x1; } -// ============ Get Complex Product ============= // - -inline void bgc_vector2_get_complex_product_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, BgcVector2FP32* result) -{ - const float x1 = vector1->x1 * vector2->x1 - vector1->x2 * vector2->x2; - const float x2 = vector1->x1 * vector2->x2 + vector1->x2 * vector2->x1; - - result->x1 = x1; - result->x2 = x2; -} - -inline void bgc_vector2_get_complex_product_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, BgcVector2FP64* result) -{ - const double x1 = vector1->x1 * vector2->x1 - vector1->x2 * vector2->x2; - const double x2 = vector1->x1 * vector2->x2 + vector1->x2 * vector2->x1; - - result->x1 = x1; - result->x2 = x2; -} - -// ============= Get Complex Ratio ============== // - -inline int bgc_vector2_get_complex_ratio_fp32(const BgcVector2FP32* divident, const BgcVector2FP32* divisor, BgcVector2FP32* quotient) -{ - const float square_modulus = bgc_vector2_get_square_modulus_fp32(divisor); - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP32) { - return 0; - } - - const float x1 = divident->x1 * divisor->x1 + divident->x2 * divisor->x2; - const float x2 = divident->x2 * divisor->x1 - divident->x1 * divisor->x2; - - const float multiplier = 1.0f / square_modulus; - - quotient->x1 = x1 * multiplier; - quotient->x2 = x2 * multiplier; - - return 1; -} - -inline int bgc_vector2_get_complex_ratio_fp64(const BgcVector2FP64* divident, const BgcVector2FP64* divisor, BgcVector2FP64* quotient) -{ - const double square_modulus = bgc_vector2_get_square_modulus_fp64(divisor); - - if (square_modulus <= BGC_SQUARE_EPSYLON_FP64) { - return 0; - } - - const double x1 = divident->x1 * divisor->x1 + divident->x2 * divisor->x2; - const double x2 = divident->x2 * divisor->x1 - divident->x1 * divisor->x2; - - const double multiplier = 1.0 / square_modulus; - - quotient->x1 = x1 * multiplier; - quotient->x2 = x2 * multiplier; - - return 1; -} - -// ============= Get Complex Power ============== // - -void bgc_vector2_get_complex_power_fp32(const BgcVector2FP32* base, const BgcVector2FP32* power, BgcVector2FP32* result); - -void bgc_vector2_get_complex_power_fp64(const BgcVector2FP64* base, const BgcVector2FP64* power, BgcVector2FP64* result); - // ================= Get Angle ================== // float bgc_vector2_get_angle_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const BgcAngleUnitEnum unit); diff --git a/basic-geometry/versor.c b/basic-geometry/versor.c index 393b9ea..0fadc5c 100644 --- a/basic-geometry/versor.c +++ b/basic-geometry/versor.c @@ -158,17 +158,9 @@ void bgc_versor_get_rotation_fp32(const BgcVersorFP32* versor, BgcRotation3FP32* return; } - const float s0s0 = versor->s0 * versor->s0; - const float x1x1 = versor->x1 * versor->x1; - const float x2x2 = versor->x2 * versor->x2; - const float x3x3 = versor->x3 * versor->x3; + const float multiplier = sqrtf(1.0f / (versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3)); - const float square_module = (s0s0 + x1x1) + (x2x2 + x3x3); - const float square_vector = x1x1 + (x2x2 + x3x3); - - result->radians = 2.0f * acosf(versor->s0 / sqrtf(square_module)); - - const float multiplier = sqrtf(1.0f / square_vector); + result->radians = 2.0f * acosf(versor->s0); result->axis.x1 = versor->x1 * multiplier; result->axis.x2 = versor->x2 * multiplier; @@ -182,19 +174,45 @@ void bgc_versor_get_rotation_fp64(const BgcVersorFP64* versor, BgcRotation3FP64* return; } - const double s0s0 = versor->s0 * versor->s0; - const double x1x1 = versor->x1 * versor->x1; - const double x2x2 = versor->x2 * versor->x2; - const double x3x3 = versor->x3 * versor->x3; + const double multiplier = sqrt(1.0 / (versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3)); - const double square_module = (s0s0 + x1x1) + (x2x2 + x3x3); - const double square_vector = x1x1 + (x2x2 + x3x3); - - result->radians = 2.0 * acos(versor->s0 / sqrt(square_module)); - - const double multiplier = sqrt(1.0 / square_vector); + result->radians = 2.0 * acos(versor->s0); result->axis.x1 = versor->x1 * multiplier; result->axis.x2 = versor->x2 * multiplier; result->axis.x3 = versor->x3 * multiplier; } + +// =============== Get Exponation =============== // + +void bgc_versor_get_exponation_fp32(const BgcVersorFP32* base, const float exponent, BgcVersorFP32* power) +{ + const float square_vector = base->x1 * base->x1 + base->x2 * base->x2 + base->x3 * base->x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP32) { + bgc_versor_reset_fp32(power); + return; + } + + const float angle = acosf(base->s0) * exponent; + + const float multiplier = sinf(angle) / sqrtf(square_vector); + + bgc_versor_set_values_fp32(cosf(angle), base->x1 * multiplier, base->x2 * multiplier, base->x3 * multiplier, power); +} + +void bgc_versor_get_exponation_fp64(const BgcVersorFP64* base, const double exponent, BgcVersorFP64* power) +{ + const double square_vector = base->x1 * base->x1 + base->x2 * base->x2 + base->x3 * base->x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP64) { + bgc_versor_reset_fp64(power); + return; + } + + const double angle = acos(base->s0) * exponent; + + const double multiplier = sin(angle) / sqrt(square_vector); + + bgc_versor_set_values_fp64(cos(angle), base->x1 * multiplier, base->x2 * multiplier, base->x3 * multiplier, power); +} diff --git a/basic-geometry/versor.h b/basic-geometry/versor.h index e5ea79e..895d249 100644 --- a/basic-geometry/versor.h +++ b/basic-geometry/versor.h @@ -274,6 +274,12 @@ inline void bgc_versor_invert_fp64(const BgcVersorFP64* versor, BgcVersorFP64* i twin->x3 = -versor->x3; } +// =============== Get Exponation =============== // + +void bgc_versor_get_exponation_fp32(const BgcVersorFP32* base, const float exponent, BgcVersorFP32* power); + +void bgc_versor_get_exponation_fp64(const BgcVersorFP64* base, const double exponent, BgcVersorFP64* power); + // ================ Combination ================= // inline void bgc_versor_combine_fp32(const BgcVersorFP32* second, const BgcVersorFP32* first, BgcVersorFP32* result) From 1b0fd7ef26d5b18bfbee7d8db3d3b182d0cceef8 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov <9942846+Morgend@users.noreply.github.com> Date: Wed, 26 Feb 2025 19:52:36 +0700 Subject: [PATCH 02/10] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20makefile=20=D0=B4=D0=BB=D1=8F=20=D0=B1=D0=B8?= =?UTF-8?q?=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry/Makefile | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 basic-geometry/Makefile diff --git a/basic-geometry/Makefile b/basic-geometry/Makefile new file mode 100644 index 0000000..726c8d9 --- /dev/null +++ b/basic-geometry/Makefile @@ -0,0 +1,26 @@ +CC=gcc +GFLAGS=-c -Wall -O2 +SOURCES=utilities.c angle.c vector2.c vector3.c complex.c cotes-number.c \ + matrix2x2.c matrix2x3.c matrix3x2.c matrix3x3.c matrixes.c \ + rotation3.c quaternion.c versor.c +OBJECTS=$(SOURCES:.c=.o) +OBJECT_DIRECTORY=obj/Release +BINARY_DIRECTORY=bin/Release +BACK_PATH=../.. +LIBRARY=libbgc.a + +all: directories $(SOURCES) $(LIBRARY) +$(LIBRARY): $(OBJECTS) + cd ./$(OBJECT_DIRECTORY); \ + ar -rv -s $(BACK_PATH)/$(BINARY_DIRECTORY)/$@ $(OBJECTS); \ + cd $(BACK_PATH) + +directories: + mkdir -p $(OBJECT_DIRECTORY) + mkdir -p $(BINARY_DIRECTORY) + +.c.o: + $(CC) $(GFLAGS) $< -o $(OBJECT_DIRECTORY)/$@ + +clean: + rm -rf ./obj ./bin From f85039a556ad8380a9146008e651d068a12ff4f9 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Thu, 27 Feb 2025 00:37:44 +0700 Subject: [PATCH 03/10] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BB=D0=B5=D0=BA=D1=81?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=87=D0=B8=D1=81=D0=B5=D0=BB,=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B2=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B5=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=B0=20=D0=B4=D0=BB=D1=8F=20Visual=20Studio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry-test/basic-geometry-test.cbp | 32 +++++ .../basic-geometry-test.vcxproj | 16 +++ .../basic-geometry-test.vcxproj.filters | 51 ++++++++ basic-geometry-test/main.c | 3 + basic-geometry-test/tests/complex.c | 14 +++ basic-geometry-test/tests/complex.h | 15 +++ .../tests/complex/complex_copy.c | 71 +++++++++++ .../tests/complex/complex_copy.h | 10 ++ .../tests/complex/complex_is_unit.c | 109 ++++++++++++++++ .../tests/complex/complex_is_unit.h | 10 ++ .../tests/complex/complex_is_zero.c | 101 +++++++++++++++ .../tests/complex/complex_is_zero.h | 10 ++ .../tests/complex/complex_modulus.c | 117 ++++++++++++++++++ .../tests/complex/complex_modulus.h | 14 +++ .../tests/complex/complex_reset.c | 41 ++++++ .../tests/complex/complex_reset.h | 10 ++ .../tests/complex/complex_set_values.c | 75 +++++++++++ .../tests/complex/complex_set_values.h | 10 ++ .../tests/complex/complex_swap.c | 95 ++++++++++++++ .../tests/complex/complex_swap.h | 10 ++ basic-geometry/basic-geometry.vcxproj | 1 - basic-geometry/versor.h | 4 +- 22 files changed, 816 insertions(+), 3 deletions(-) create mode 100644 basic-geometry-test/tests/complex.c create mode 100644 basic-geometry-test/tests/complex.h create mode 100644 basic-geometry-test/tests/complex/complex_copy.c create mode 100644 basic-geometry-test/tests/complex/complex_copy.h create mode 100644 basic-geometry-test/tests/complex/complex_is_unit.c create mode 100644 basic-geometry-test/tests/complex/complex_is_unit.h create mode 100644 basic-geometry-test/tests/complex/complex_is_zero.c create mode 100644 basic-geometry-test/tests/complex/complex_is_zero.h create mode 100644 basic-geometry-test/tests/complex/complex_modulus.c create mode 100644 basic-geometry-test/tests/complex/complex_modulus.h create mode 100644 basic-geometry-test/tests/complex/complex_reset.c create mode 100644 basic-geometry-test/tests/complex/complex_reset.h create mode 100644 basic-geometry-test/tests/complex/complex_set_values.c create mode 100644 basic-geometry-test/tests/complex/complex_set_values.h create mode 100644 basic-geometry-test/tests/complex/complex_swap.c create mode 100644 basic-geometry-test/tests/complex/complex_swap.h diff --git a/basic-geometry-test/basic-geometry-test.cbp b/basic-geometry-test/basic-geometry-test.cbp index 6a52f6a..0141096 100644 --- a/basic-geometry-test/basic-geometry-test.cbp +++ b/basic-geometry-test/basic-geometry-test.cbp @@ -49,6 +49,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/basic-geometry-test/basic-geometry-test.vcxproj b/basic-geometry-test/basic-geometry-test.vcxproj index 2895814..d89a31e 100644 --- a/basic-geometry-test/basic-geometry-test.vcxproj +++ b/basic-geometry-test/basic-geometry-test.vcxproj @@ -150,6 +150,14 @@ + + + + + + + + @@ -190,6 +198,14 @@ + + + + + + + + diff --git a/basic-geometry-test/basic-geometry-test.vcxproj.filters b/basic-geometry-test/basic-geometry-test.vcxproj.filters index a91ee1d..eb13dc2 100644 --- a/basic-geometry-test/basic-geometry-test.vcxproj.filters +++ b/basic-geometry-test/basic-geometry-test.vcxproj.filters @@ -114,6 +114,30 @@ tests\quaternion + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests + @@ -228,6 +252,30 @@ tests\quaternion + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests\complex + + + tests + @@ -248,5 +296,8 @@ {e8bafdb8-66e5-4393-bc89-8bff83bcccd6} + + {e025e123-45aa-44f9-aab4-f1705844b211} + \ No newline at end of file diff --git a/basic-geometry-test/main.c b/basic-geometry-test/main.c index 2022099..9bb59b6 100644 --- a/basic-geometry-test/main.c +++ b/basic-geometry-test/main.c @@ -6,6 +6,7 @@ #include "tests/utilities.h" #include "tests/vector2.h" #include "tests/vector3.h" +#include "tests/complex.h" #include "tests/quaternion.h" #include "tests/versor.h" @@ -17,6 +18,8 @@ int main() test_vector3(); + test_complex(); + test_quaternion(); test_versor(); diff --git a/basic-geometry-test/tests/complex.c b/basic-geometry-test/tests/complex.c new file mode 100644 index 0000000..10ea9a6 --- /dev/null +++ b/basic-geometry-test/tests/complex.c @@ -0,0 +1,14 @@ +#include "./complex.h" + +void test_complex() +{ + print_testing_section("BGC Complex"); + + test_complex_reset(); + test_complex_set_values(); + test_complex_copy(); + test_complex_swap(); + test_complex_is_zero(); + test_complex_is_unit(); + test_complex_modulus(); +} diff --git a/basic-geometry-test/tests/complex.h b/basic-geometry-test/tests/complex.h new file mode 100644 index 0000000..2eab35e --- /dev/null +++ b/basic-geometry-test/tests/complex.h @@ -0,0 +1,15 @@ +#ifndef _TEST_COMPLEX_H_ +#define _TEST_COMPLEX_H_ + +#include "./../helpers.h" +#include "./complex/complex_reset.h" +#include "./complex/complex_set_values.h" +#include "./complex/complex_copy.h" +#include "./complex/complex_swap.h" +#include "./complex/complex_is_zero.h" +#include "./complex/complex_is_unit.h" +#include "./complex/complex_modulus.h" + +void test_complex(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_copy.c b/basic-geometry-test/tests/complex/complex_copy.c new file mode 100644 index 0000000..84ed825 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_copy.c @@ -0,0 +1,71 @@ +#include "./complex_copy.h" + +#include + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +static const int _TEST_FP32_COMPLEX_AMOUNT = 4; +static const BgcComplexFP32 _TEST_FP32_COMPLEX_LIST[] = { + { 1.0f, 2.0f }, + { -4.0f, -3.0f }, + { -0.001f, 100.0f }, + { 0.001f, -100.0f } +}; + +void test_complex_copy_fp32() +{ + BgcComplexFP32 vector; + + print_testing_name("bgc_complex_copy_fp32"); + + for (int i = 0; i < _TEST_FP32_COMPLEX_AMOUNT; i++) { + + bgc_complex_copy_fp32(&_TEST_FP32_COMPLEX_LIST[i], &vector); + + if (vector.real != _TEST_FP32_COMPLEX_LIST[i].real || + vector.imaginary != _TEST_FP32_COMPLEX_LIST[i].imaginary) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +static const int _TEST_FP64_COMPLEX_AMOUNT = 4; +static const BgcComplexFP64 _TEST_FP64_COMPLEX_LIST[] = { + { 1.0, 2.0 }, + { -4.0, -3.0 }, + { -0.001, 100.0 }, + { 0.001, -100.0 } +}; + +void test_complex_copy_fp64() +{ + BgcComplexFP64 vector; + + print_testing_name("bgc_complex_copy_fp64"); + + for (int i = 0; i < _TEST_FP64_COMPLEX_AMOUNT; i++) { + + bgc_complex_copy_fp64(&_TEST_FP64_COMPLEX_LIST[i], &vector); + + if (vector.real != _TEST_FP64_COMPLEX_LIST[i].real || + vector.imaginary != _TEST_FP64_COMPLEX_LIST[i].imaginary) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +void test_complex_copy() +{ + test_complex_copy_fp32(); + test_complex_copy_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_copy.h b/basic-geometry-test/tests/complex/complex_copy.h new file mode 100644 index 0000000..d35db2c --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_copy.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_COPY_H_ +#define _TEST_COMPLEX_COPY_H_ + +void test_complex_copy_fp32(); + +void test_complex_copy_fp64(); + +void test_complex_copy(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_is_unit.c b/basic-geometry-test/tests/complex/complex_is_unit.c new file mode 100644 index 0000000..f06ca66 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_is_unit.c @@ -0,0 +1,109 @@ +#include "./complex_is_unit.h" + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +static const int _TEST_FP32_UNIT_COMPLEX_AMOUNT = 10; +static const int _TEST_FP32_NONUNIT_COMPLEX_AMOUNT = 6; + +static const BgcComplexFP32 _TEST_FP32_UNIT_COMPLEX_LIST[] = { + { 1.0f, 0.0f }, + { -1.0f, 0.0f }, + { 0.6f, -0.8f }, + { 1.0f + 0.75f * BGC_EPSYLON_FP32, 0.0f }, + { 1.0f - 0.75f * BGC_EPSYLON_FP32, 0.0f }, + { 0.0f, 1.0f + 0.75f * BGC_EPSYLON_FP32 }, + { 0.0f, 1.0f - 0.75f * BGC_EPSYLON_FP32 }, + { 0.7071067812f, 0.7071067812f }, + { 0.7071067812f + 0.75f * BGC_EPSYLON_FP32, 0.7071067812f }, + { 0.7071067812f, 0.7071067812f - 0.75f * BGC_EPSYLON_FP32 } +}; + +static const BgcComplexFP32 _TEST_FP32_NONUNIT_QUATERION_LIST[] = { + { 1.0f + 1.25f * BGC_EPSYLON_FP32, 0.0f }, + { 1.0f - 1.25f * BGC_EPSYLON_FP32, 0.0f }, + { 0.0f, 1.0f + 1.25f * BGC_EPSYLON_FP32 }, + { 0.0f, 1.0f - 1.25f * BGC_EPSYLON_FP32 }, + { 0.7071067812f + 1.25f * BGC_EPSYLON_FP32, 0.7071067812f + 1.25f * BGC_EPSYLON_FP32 }, + { 0.7071067812f - 1.25f * BGC_EPSYLON_FP32, 0.7071067812f - 1.25f * BGC_EPSYLON_FP32 } +}; + +void test_complex_is_unit_fp32() +{ + print_testing_name("bgc_complex_is_unit_fp32"); + + // Testing zero values: + for (int i = 0; i < _TEST_FP32_UNIT_COMPLEX_AMOUNT; i++) { + if (!bgc_complex_is_unit_fp32(&_TEST_FP32_UNIT_COMPLEX_LIST[i])) { + print_testing_error("A unit complex number was not recognized"); + return; + } + } + + // Testing non-zero values: + for (int i = 0; i < _TEST_FP32_NONUNIT_COMPLEX_AMOUNT; i++) { + if (bgc_complex_is_unit_fp32(&_TEST_FP32_NONUNIT_QUATERION_LIST[i])) { + print_testing_error("A non-unit complex number was recognized a unit complex number"); + return; + } + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +static const int _TEST_FP64_UNIT_COMPLEX_AMOUNT = 10; +static const int _TEST_FP64_NONUNIT_COMPLEX_AMOUNT = 6; + +static const BgcComplexFP64 _TEST_FP64_UNIT_COMPLEX_LIST[] = { + { 1.0, 0.0 }, + { -1.0, 0.0 }, + { -0.6, 0.8 }, + { 1.0 + 0.75 * BGC_EPSYLON_FP64, 0.0 }, + { 1.0 - 0.75 * BGC_EPSYLON_FP64, 0.0 }, + { 0.0, 1.0 + 0.75 * BGC_EPSYLON_FP64 }, + { 0.0, 1.0 - 0.75 * BGC_EPSYLON_FP64 }, + { 0.7071067811865475244, 0.7071067811865475244 }, + { 0.7071067811865475244 + 0.75 * BGC_EPSYLON_FP64, 0.7071067811865475244 }, + { 0.7071067811865475244, 0.7071067811865475244 - 0.75 * BGC_EPSYLON_FP64 } +}; + +static const BgcComplexFP64 _TEST_FP64_NONUNIT_QUATERION_LIST[] = { + { 1.0 + 1.25 * BGC_EPSYLON_FP64, 0.0 }, + { 1.0 - 1.25 * BGC_EPSYLON_FP64, 0.0 }, + { 0.0, 1.0 + 1.25 * BGC_EPSYLON_FP64 }, + { 0.0, 1.0 - 1.25 * BGC_EPSYLON_FP64 }, + { 0.7071067811865475244 + 1.25 * BGC_EPSYLON_FP64, 0.7071067811865475244 + 1.25 * BGC_EPSYLON_FP64 }, + { 0.7071067811865475244 - 1.25 * BGC_EPSYLON_FP64, 0.7071067811865475244 - 1.25 * BGC_EPSYLON_FP64 } +}; + +void test_complex_is_unit_fp64() +{ + print_testing_name("bgc_complex_is_unit_fp64"); + + // Testing zero values: + for (int i = 0; i < _TEST_FP64_UNIT_COMPLEX_AMOUNT; i++) { + if (!bgc_complex_is_unit_fp64(&_TEST_FP64_UNIT_COMPLEX_LIST[i])) { + print_testing_error("A unit complex number was not recognized"); + return; + } + } + + // Testing non-zero values: + for (int i = 0; i < _TEST_FP64_NONUNIT_COMPLEX_AMOUNT; i++) { + if (bgc_complex_is_unit_fp64(&_TEST_FP64_NONUNIT_QUATERION_LIST[i])) { + print_testing_error("A non-unit complex number was recognized a unit complex number"); + return; + } + } + + print_testing_success(); +} + +void test_complex_is_unit() +{ + test_complex_is_unit_fp32(); + test_complex_is_unit_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_is_unit.h b/basic-geometry-test/tests/complex/complex_is_unit.h new file mode 100644 index 0000000..d434d41 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_is_unit.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_IS_UNIT_H_ +#define _TEST_COMPLEX_IS_UNIT_H_ + +void test_complex_is_unit_fp32(); + +void test_complex_is_unit_fp64(); + +void test_complex_is_unit(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_is_zero.c b/basic-geometry-test/tests/complex/complex_is_zero.c new file mode 100644 index 0000000..1f658e3 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_is_zero.c @@ -0,0 +1,101 @@ +#include "./complex_is_zero.h" + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +static const int _TEST_FP32_ZERO_COMPLEX_AMOUNT = 4; +static const int _TEST_FP32_NONZERO_COMPLEX_AMOUNT = 7; + +static const BgcComplexFP32 _TEST_FP32_ZERO_COMPLEX_LIST[] = { + { 0.0f, 0.0f }, + { 0.75f * BGC_EPSYLON_FP32, 0.0f }, + { -0.75f * BGC_EPSYLON_FP32, 0.0f }, + { 0.0f, 0.75f * BGC_EPSYLON_FP32 }, + { 0.0f, -0.75f * BGC_EPSYLON_FP32 } +}; + +static const BgcComplexFP32 _TEST_FP32_NONZERO_QUATERION_LIST[] = { + { 0.0f, 1.0f }, + { 1.25f * BGC_EPSYLON_FP32 }, + { -1.25f * BGC_EPSYLON_FP32 }, + { 0.0f, 1.25f * BGC_EPSYLON_FP32 }, + { 0.0f, -1.25f * BGC_EPSYLON_FP32 }, + { 1.25f * BGC_EPSYLON_FP32, 1.25f * BGC_EPSYLON_FP32 }, + { -1.25f * BGC_EPSYLON_FP32, -1.25f * BGC_EPSYLON_FP32 } +}; + +void test_complex_is_zero_fp32() +{ + print_testing_name("bgc_complex_is_zero_fp32"); + + // Testing zero values: + for (int i = 0; i < _TEST_FP32_ZERO_COMPLEX_AMOUNT; i++) { + if (!bgc_complex_is_zero_fp32(&_TEST_FP32_ZERO_COMPLEX_LIST[i])) { + print_testing_error("A zero complex number was not recognized"); + return; + } + } + + // Testing non-zero values: + for (int i = 0; i < _TEST_FP32_NONZERO_COMPLEX_AMOUNT; i++) { + if (bgc_complex_is_zero_fp32(&_TEST_FP32_NONZERO_QUATERION_LIST[i])) { + print_testing_error("A non-zero complex number was recognized as a zero complex number"); + return; + } + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +static const int _TEST_FP64_ZERO_COMPLEX_AMOUNT = 4; +static const int _TEST_FP64_NONZERO_COMPLEX_AMOUNT = 7; + +static const BgcComplexFP64 _TEST_FP64_ZERO_COMPLEX_LIST[] = { + { 0.0, 0.0 }, + { 0.75 * BGC_EPSYLON_FP64, 0.0 }, + { -0.75 * BGC_EPSYLON_FP64, 0.0 }, + { 0.0, 0.75 * BGC_EPSYLON_FP64 }, + { 0.0, -0.75 * BGC_EPSYLON_FP64 } +}; + +static const BgcComplexFP64 _TEST_FP64_NONZERO_QUATERION_LIST[] = { + { 0.0, 1.0 }, + { 1.25 * BGC_EPSYLON_FP64, 0.0 }, + { -1.25 * BGC_EPSYLON_FP64, 0.0 }, + { 0.0, 1.25 * BGC_EPSYLON_FP64 }, + { 0.0, -1.25 * BGC_EPSYLON_FP64 }, + { 1.25 * BGC_EPSYLON_FP64, 1.25 * BGC_EPSYLON_FP64 }, + { -1.25 * BGC_EPSYLON_FP64, -1.25 * BGC_EPSYLON_FP64 } +}; + +void test_complex_is_zero_fp64() +{ + print_testing_name("bgc_complex_is_zero_fp64"); + + // Testing zero values: + for (int i = 0; i < _TEST_FP64_ZERO_COMPLEX_AMOUNT; i++) { + if (!bgc_complex_is_zero_fp64(&_TEST_FP64_ZERO_COMPLEX_LIST[i])) { + print_testing_error("A zero complex number was not recognized"); + return; + } + } + + // Testing non-zero values: + for (int i = 0; i < _TEST_FP64_NONZERO_COMPLEX_AMOUNT; i++) { + if (bgc_complex_is_zero_fp64(&_TEST_FP64_NONZERO_QUATERION_LIST[i])) { + print_testing_error("A non-zero complex number was recognized as a zero complex number"); + return; + } + } + + print_testing_success(); +} + +void test_complex_is_zero() +{ + test_complex_is_zero_fp32(); + test_complex_is_zero_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_is_zero.h b/basic-geometry-test/tests/complex/complex_is_zero.h new file mode 100644 index 0000000..9153446 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_is_zero.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_IS_ZERO_H_ +#define _TEST_COMPLEX_IS_ZERO_H_ + +void test_complex_is_zero_fp32(); + +void test_complex_is_zero_fp64(); + +void test_complex_is_zero(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_modulus.c b/basic-geometry-test/tests/complex/complex_modulus.c new file mode 100644 index 0000000..20c0495 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_modulus.c @@ -0,0 +1,117 @@ +#include "./complex_modulus.h" + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +static const int _TEST_FP32_COMPLEX_AMOUNT = 4; + +static const BgcComplexFP32 _TEST_FP32_COMPLEX_LIST[] = { + { 4.0f, 3.0f }, + { -1.0f, 1.0f }, + { 100.0f, -100.0f }, + { -0.86602540378f, 0.5f } +}; + +static const float _TEST_FP32_SQUARE_MODULUS_LIST[] = { + 25.0f, + 2.0f, + 20000.0f, + 1.0f +}; + +static const float _TEST_FP32_MODULUS_LIST[] = { + 5.0f, + 1.414213562373f, + 141.4213562373f, + 1.0f +}; + +void test_complex_square_modulus_fp32() +{ + print_testing_name("bgc_complex_get_square_modulus_fp32"); + + for (int i = 0; i < _TEST_FP32_COMPLEX_AMOUNT; i++) { + if (!bgc_are_close_fp32(bgc_complex_get_square_modulus_fp32(&_TEST_FP32_COMPLEX_LIST[i]), _TEST_FP32_SQUARE_MODULUS_LIST[i])) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +void test_complex_modulus_fp32() +{ + print_testing_name("bgc_complex_get_modulus_fp32"); + + for (int i = 0; i < _TEST_FP32_COMPLEX_AMOUNT; i++) { + if (!bgc_are_close_fp32(bgc_complex_get_modulus_fp32(&_TEST_FP32_COMPLEX_LIST[i]), _TEST_FP32_MODULUS_LIST[i])) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +static const int _TEST_FP64_COMPLEX_AMOUNT = 4; + +static const BgcComplexFP64 _TEST_FP64_COMPLEX_LIST[] = { + { 4.0, 3.0 }, + { -1.0, -1.0 }, + { -100.0, 100.0 }, + { -0.5, 0.866025403784438647 } +}; + +static const double _TEST_FP64_SQUARE_MODULUS_LIST[] = { + 25.0, + 2.0, + 20000.0, + 1.0 +}; + +static const double _TEST_FP64_MODULUS_LIST[] = { + 5.0, + 1.4142135623730950488, + 141.42135623730950488, + 1.0 +}; + +void test_complex_square_modulus_fp64() +{ + print_testing_name("bgc_complex_get_square_modulus_fp64"); + + for (int i = 0; i < _TEST_FP64_COMPLEX_AMOUNT; i++) { + if (!bgc_are_close_fp64(bgc_complex_get_square_modulus_fp64(&_TEST_FP64_COMPLEX_LIST[i]), _TEST_FP64_SQUARE_MODULUS_LIST[i])) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +void test_complex_modulus_fp64() +{ + print_testing_name("bgc_complex_get_modulus_fp64"); + + for (int i = 0; i < _TEST_FP64_COMPLEX_AMOUNT; i++) { + if (!bgc_are_close_fp64(bgc_complex_get_modulus_fp64(&_TEST_FP64_COMPLEX_LIST[i]), _TEST_FP64_MODULUS_LIST[i])) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +void test_complex_modulus() +{ + test_complex_square_modulus_fp32(); + test_complex_square_modulus_fp64(); + test_complex_modulus_fp32(); + test_complex_modulus_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_modulus.h b/basic-geometry-test/tests/complex/complex_modulus.h new file mode 100644 index 0000000..9d62f3d --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_modulus.h @@ -0,0 +1,14 @@ +#ifndef _TEST_COMPLEX_MODULUS_H_ +#define _TEST_COMPLEX_MODULUS_H_ + +void test_complex_square_modulus_fp32(); + +void test_complex_square_modulus_fp64(); + +void test_complex_modulus_fp32(); + +void test_complex_modulus_fp64(); + +void test_complex_modulus(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_reset.c b/basic-geometry-test/tests/complex/complex_reset.c new file mode 100644 index 0000000..6c8b11f --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_reset.c @@ -0,0 +1,41 @@ +#include "./complex_reset.h" + +#include "./../../helpers.h" + +void test_complex_reset_fp32() +{ + BgcComplexFP32 vector; + + print_testing_name("bgc_complex_reset_fp32"); + + bgc_complex_reset_fp32(&vector); + + if (vector.real != 0.0f || vector.imaginary != 0.0f) { + print_testing_failed(); + return; + } + + print_testing_success(); +} + +void test_complex_reset_fp64() +{ + BgcComplexFP64 vector; + + print_testing_name("bgc_complex_reset_fp64"); + + bgc_complex_reset_fp64(&vector); + + if (vector.real != 0.0 || vector.imaginary != 0.0) { + print_testing_failed(); + return; + } + + print_testing_success(); +} + +void test_complex_reset() +{ + test_complex_reset_fp32(); + test_complex_reset_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_reset.h b/basic-geometry-test/tests/complex/complex_reset.h new file mode 100644 index 0000000..f76683b --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_reset.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_RESET_H_ +#define _TEST_COMPLEX_RESET_H_ + +void test_complex_reset_fp32(); + +void test_complex_reset_fp64(); + +void test_complex_reset(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_set_values.c b/basic-geometry-test/tests/complex/complex_set_values.c new file mode 100644 index 0000000..9f20beb --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_set_values.c @@ -0,0 +1,75 @@ +#include "./complex_set_values.h" + +#include + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +void test_complex_set_values_fp32() +{ + BgcComplexFP32 vector; + + print_testing_name("bgc_complex_set_values_fp32"); + + bgc_complex_set_values_fp32(1.0f, 2.0f, &vector); + + if (vector.real != 1.0f || vector.imaginary != 2.0f) { + print_testing_error("First step failed"); + return; + } + + bgc_complex_set_values_fp32(-1.0f, -3.0f, &vector); + + if (vector.real != -1.0f || vector.imaginary != -3.0f) { + print_testing_error("Second step failed"); + return; + } + + bgc_complex_set_values_fp32(-8.0f, -2.0f, &vector); + + if (vector.real != -8.0f || vector.imaginary != -2.0f) { + print_testing_error("Third step failed"); + return; + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +void test_complex_set_values_fp64() +{ + BgcComplexFP64 vector; + + print_testing_name("bgc_complex_set_values_fp64"); + + bgc_complex_set_values_fp64(1.0, 2.0, &vector); + + if (vector.real != 1.0 || vector.imaginary != 2.0) { + print_testing_error("First step failed"); + return; + } + + bgc_complex_set_values_fp64(-1.0, -3.0, &vector); + + if (vector.real != -1.0 || vector.imaginary != -3.0) { + print_testing_error("Second step failed"); + return; + } + + bgc_complex_set_values_fp64(-8.0, -2.0, &vector); + + if (vector.real != -8.0 || vector.imaginary != -2.0) { + print_testing_error("Third step failed"); + return; + } + + print_testing_success(); +} + +void test_complex_set_values() +{ + test_complex_set_values_fp32(); + test_complex_set_values_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_set_values.h b/basic-geometry-test/tests/complex/complex_set_values.h new file mode 100644 index 0000000..dc5296d --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_set_values.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_SET_VALUES_H_ +#define _TEST_COMPLEX_SET_VALUES_H_ + +void test_complex_set_values_fp32(); + +void test_complex_set_values_fp64(); + +void test_complex_set_values(); + +#endif diff --git a/basic-geometry-test/tests/complex/complex_swap.c b/basic-geometry-test/tests/complex/complex_swap.c new file mode 100644 index 0000000..bec0546 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_swap.c @@ -0,0 +1,95 @@ +#include "./complex_swap.h" + +#include + +#include "./../../helpers.h" + +// ==================== FP32 ==================== // + +static const int _TEST_FP32_COMPLEX_AMOUNT = 4; + +static const BgcComplexFP32 _TEST_FP32_COMPLEX_LIST1[] = { + { 3.0f, 4.0f }, + { -2.0f, -1.0f }, + { -244.8f, 100.0f }, + { 1000.32f, -100.1f } +}; + +static const BgcComplexFP32 _TEST_FP32_COMPLEX_LIST2[] = { + { 5.3f, 1003.28f }, + { -0.0032f, 891.3f }, + { 5.322f, 0.9275f }, + { 1000.0f, -0.00025f } +}; + +void test_complex_swap_fp32() +{ + BgcComplexFP32 compleimaginary, complex2; + + print_testing_name("bgc_complex_swap_fp32"); + + for (int i = 0; i < _TEST_FP32_COMPLEX_AMOUNT; i++) { + bgc_complex_copy_fp32(&_TEST_FP32_COMPLEX_LIST1[i], &compleimaginary); + bgc_complex_copy_fp32(&_TEST_FP32_COMPLEX_LIST2[i], &complex2); + + bgc_complex_swap_fp32(&compleimaginary, &complex2); + + if (compleimaginary.real != _TEST_FP32_COMPLEX_LIST2[i].real || + compleimaginary.imaginary != _TEST_FP32_COMPLEX_LIST2[i].imaginary || + complex2.real != _TEST_FP32_COMPLEX_LIST1[i].real || + complex2.imaginary != _TEST_FP32_COMPLEX_LIST1[i].imaginary) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +// ==================== FP64 ==================== // + +static const int _TEST_FP64_COMPLEX_AMOUNT = 4; + +static const BgcComplexFP64 _TEST_FP64_COMPLEX_LIST1[] = { + { 1.0, 4.0 }, + { -4.0, -3.0 }, + { -244.8, 344.7 }, + { 1000.32, -271.3 } +}; + +static const BgcComplexFP64 _TEST_FP64_COMPLEX_LIST2[] = { + { -0.123, 1003.28 }, + { 204.07, -781.89 }, + { 5.322, 0.9275 }, + { -0.419, 0.844 } +}; + +void test_complex_swap_fp64() +{ + BgcComplexFP64 compleimaginary, complex2; + + print_testing_name("bgc_complex_swap_fp64"); + + for (int i = 0; i < _TEST_FP64_COMPLEX_AMOUNT; i++) { + bgc_complex_copy_fp64(&_TEST_FP64_COMPLEX_LIST1[i], &compleimaginary); + bgc_complex_copy_fp64(&_TEST_FP64_COMPLEX_LIST2[i], &complex2); + + bgc_complex_swap_fp64(&compleimaginary, &complex2); + + if (compleimaginary.real != _TEST_FP64_COMPLEX_LIST2[i].real || + compleimaginary.imaginary != _TEST_FP64_COMPLEX_LIST2[i].imaginary || + complex2.real != _TEST_FP64_COMPLEX_LIST1[i].real || + complex2.imaginary != _TEST_FP64_COMPLEX_LIST1[i].imaginary) { + print_testing_failed(); + return; + } + } + + print_testing_success(); +} + +void test_complex_swap() +{ + test_complex_swap_fp32(); + test_complex_swap_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_swap.h b/basic-geometry-test/tests/complex/complex_swap.h new file mode 100644 index 0000000..94ae0ed --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_swap.h @@ -0,0 +1,10 @@ +#ifndef _TEST_COMPLEX_SWAP_H_ +#define _TEST_COMPLEX_SWAP_H_ + +void test_complex_swap_fp32(); + +void test_complex_swap_fp64(); + +void test_complex_swap(); + +#endif diff --git a/basic-geometry/basic-geometry.vcxproj b/basic-geometry/basic-geometry.vcxproj index 6c60d06..94fb723 100644 --- a/basic-geometry/basic-geometry.vcxproj +++ b/basic-geometry/basic-geometry.vcxproj @@ -47,7 +47,6 @@ - diff --git a/basic-geometry/versor.h b/basic-geometry/versor.h index 895d249..8215daa 100644 --- a/basic-geometry/versor.h +++ b/basic-geometry/versor.h @@ -184,12 +184,12 @@ inline void bgc_versor_swap_fp64(BgcVersorFP64* versor1, BgcVersorFP64* versor2) inline int bgc_versor_is_identity_fp32(const BgcVersorFP32* versor) { - return 1.0f - BGC_EPSYLON_FP32 <= versor->s0 || versor->s0 <= -(1.0 - BGC_EPSYLON_FP32); + return versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3 <= BGC_SQUARE_EPSYLON_FP32; } inline int bgc_versor_is_identity_fp64(const BgcVersorFP64* versor) { - return 1.0 - BGC_EPSYLON_FP64 <= versor->s0 || versor->s0 <= -(1.0 - BGC_EPSYLON_FP64); + return versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3 <= BGC_SQUARE_EPSYLON_FP64; } // ================== Convert =================== // From 9688bd2fc14968151c9ed6c207bff4eedc994963 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov <9942846+Morgend@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:42:45 +0700 Subject: [PATCH 04/10] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry-test/tests/versor/versor_is_identity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basic-geometry-test/tests/versor/versor_is_identity.c b/basic-geometry-test/tests/versor/versor_is_identity.c index 7aef257..024bcf9 100644 --- a/basic-geometry-test/tests/versor/versor_is_identity.c +++ b/basic-geometry-test/tests/versor/versor_is_identity.c @@ -24,7 +24,7 @@ static const BgcVersorFP32 _TEST_FP32_NON_IDENTIYTY_VERSOR_LIST[] = { { 0.0f, 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, 0.5f, 0.5f, 0.5f }, - { 1.0f - 1.25f * BGC_EPSYLON_FP32, 0.0f, 0.0f, 0.0f } + { 1.0f, -1.25f * BGC_EPSYLON_FP32, 0.0f, 0.0f } }; void test_versor_is_identity_fp32() @@ -72,7 +72,7 @@ static const BgcVersorFP64 _TEST_FP64_NON_IDENTIYTY_VERSOR_LIST[] = { { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }, { 0.5, 0.5, 0.5, 0.5 }, - { 1.0 - 1.25 * BGC_EPSYLON_FP64, 0.0, 0.0, 0.0 } + { 1.0, 0.0, 1.25 * BGC_EPSYLON_FP64, 0.0 } }; void test_versor_is_identity_fp64() From 0a1ca06ce53712bc9a6204474b7f0459dbac3a7c Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Tue, 11 Mar 2025 01:39:35 +0700 Subject: [PATCH 05/10] =?UTF-8?q?=D0=9E=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry/versor.c | 3 +++ basic-geometry/versor.h | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/basic-geometry/versor.c b/basic-geometry/versor.c index 0fadc5c..8405012 100644 --- a/basic-geometry/versor.c +++ b/basic-geometry/versor.c @@ -40,6 +40,9 @@ extern inline void bgc_versor_combine_fp64(const BgcVersorFP64* second, const Bg extern inline void bgc_versor_combine3_fp32(const BgcVersorFP32* third, const BgcVersorFP32* second, const BgcVersorFP32* first, BgcVersorFP32* result); extern inline void bgc_versor_combine3_fp64(const BgcVersorFP64* third, const BgcVersorFP64* second, const BgcVersorFP64* first, BgcVersorFP64* result); +extern inline void bgc_versor_exclude_fp32(const BgcVersorFP32* base, const BgcVersorFP32* excludant, BgcVersorFP32* difference); +extern inline void bgc_versor_exclude_fp64(const BgcVersorFP64* base, const BgcVersorFP64* excludant, BgcVersorFP64* difference); + extern inline void bgc_versor_get_rotation_matrix_fp32(const BgcVersorFP32* versor, BgcMatrix3x3FP32* matrix); extern inline void bgc_versor_get_rotation_matrix_fp64(const BgcVersorFP64* versor, BgcMatrix3x3FP64* matrix); diff --git a/basic-geometry/versor.h b/basic-geometry/versor.h index 8215daa..6240b0f 100644 --- a/basic-geometry/versor.h +++ b/basic-geometry/versor.h @@ -338,6 +338,30 @@ inline void bgc_versor_combine3_fp64(const BgcVersorFP64* third, const BgcVersor ); } +// ================= Exclusion ================== // + +inline void bgc_versor_exclude_fp32(const BgcVersorFP32* base, const BgcVersorFP32* excludant, BgcVersorFP32* difference) +{ + bgc_versor_set_values_fp32( + (base->s0 * excludant->s0 + base->x1 * excludant->x1) + (base->x2 * excludant->x2 + base->x3 * excludant->x3), + (base->x1 * excludant->s0 + base->x3 * excludant->x2) - (base->s0 * excludant->x1 + base->x2 * excludant->x3), + (base->x2 * excludant->s0 + base->x1 * excludant->x3) - (base->s0 * excludant->x2 + base->x3 * excludant->x1), + (base->x3 * excludant->s0 + base->x2 * excludant->x1) - (base->s0 * excludant->x3 + base->x1 * excludant->x2), + difference + ); +} + +inline void bgc_versor_exclude_fp64(const BgcVersorFP64* base, const BgcVersorFP64* excludant, BgcVersorFP64* difference) +{ + bgc_versor_set_values_fp64( + (base->s0 * excludant->s0 + base->x1 * excludant->x1) + (base->x2 * excludant->x2 + base->x3 * excludant->x3), + (base->x1 * excludant->s0 + base->x3 * excludant->x2) - (base->s0 * excludant->x1 + base->x2 * excludant->x3), + (base->x2 * excludant->s0 + base->x1 * excludant->x3) - (base->s0 * excludant->x2 + base->x3 * excludant->x1), + (base->x3 * excludant->s0 + base->x2 * excludant->x1) - (base->s0 * excludant->x3 + base->x1 * excludant->x2), + difference + ); +} + // ================ Get Rotation ================ // void bgc_versor_get_rotation_fp32(const BgcVersorFP32* versor, BgcRotation3FP32* result); From 2e902bc04062eb235c0d6bcc68537113012cd66a Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Tue, 11 Mar 2025 01:44:08 +0700 Subject: [PATCH 06/10] =?UTF-8?q?=D0=9E=D0=BF=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=B2=D1=83=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D1=81=D1=82=D0=B2=D0=B0=20(=D1=87=D0=B8=D1=81?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=9A=D0=BE=D1=82=D1=81=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry/cotes-number.c | 3 +++ basic-geometry/cotes-number.h | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/basic-geometry/cotes-number.c b/basic-geometry/cotes-number.c index fc7cc57..f00206b 100644 --- a/basic-geometry/cotes-number.c +++ b/basic-geometry/cotes-number.c @@ -34,6 +34,9 @@ extern inline void bgc_cotes_number_get_exponation_fp64(const BgcCotesNumberFP64 extern inline void bgc_cotes_number_combine_fp32(const BgcCotesNumberFP32* number1, const BgcCotesNumberFP32* number2, BgcCotesNumberFP32* result); extern inline void bgc_cotes_number_combine_fp64(const BgcCotesNumberFP64* number1, const BgcCotesNumberFP64* number2, BgcCotesNumberFP64* result); +extern inline void bgc_cotes_number_exclude_fp32(const BgcCotesNumberFP32* base, const BgcCotesNumberFP32* excludant, BgcCotesNumberFP32* difference); +extern inline void bgc_cotes_number_exclude_fp64(const BgcCotesNumberFP64* base, const BgcCotesNumberFP64* excludant, BgcCotesNumberFP64* difference); + extern inline void bgc_cotes_number_get_rotation_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix); extern inline void bgc_cotes_number_get_rotation_matrix_fp64(const BgcCotesNumberFP64* number, BgcMatrix2x2FP64* matrix); diff --git a/basic-geometry/cotes-number.h b/basic-geometry/cotes-number.h index e4944a6..1990948 100644 --- a/basic-geometry/cotes-number.h +++ b/basic-geometry/cotes-number.h @@ -277,6 +277,26 @@ inline void bgc_cotes_number_combine_fp64(const BgcCotesNumberFP64* number1, con ); } +// ================= Exclusion ================== // + +inline void bgc_cotes_number_exclude_fp32(const BgcCotesNumberFP32* base, const BgcCotesNumberFP32* excludant, BgcCotesNumberFP32* difference) +{ + bgc_cotes_number_set_values_fp32( + base->cos * excludant->cos + base->sin * excludant->sin, + base->sin * excludant->cos - base->cos * excludant->sin, + difference + ); +} + +inline void bgc_cotes_number_exclude_fp64(const BgcCotesNumberFP64* base, const BgcCotesNumberFP64* excludant, BgcCotesNumberFP64* difference) +{ + bgc_cotes_number_set_values_fp64( + base->cos * excludant->cos + base->sin * excludant->sin, + base->sin * excludant->cos - base->cos * excludant->sin, + difference + ); +} + // ============== Rotation Matrix =============== // inline void bgc_cotes_number_get_rotation_matrix_fp32(const BgcCotesNumberFP32* number, BgcMatrix2x2FP32* matrix) From f06b35ae345aaf827ddf644b65dc44eb5f3ac5e2 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Thu, 13 Mar 2025 02:41:21 +0700 Subject: [PATCH 07/10] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D1=83=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B0=D1=80=D0=B8=D1=84=D0=BC=D0=B5=D1=82=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D1=85=20=D0=BE=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B9=20=D1=81=20=D0=B2=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B0=D0=BC=D0=B8=20=D0=B8=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BF=D0=BB=D0=B5=D0=BA=D1=81=D0=BD=D1=8B=D0=BC=D0=B8=20=D1=87?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../basic-geometry-test.vcxproj | 6 + .../basic-geometry-test.vcxproj.filters | 18 + basic-geometry-test/tests/complex.c | 5 + basic-geometry-test/tests/complex.h | 1 + .../tests/complex/complex_arithmetics.c | 380 ++++++++++++++++++ .../tests/complex/complex_arithmetics.h | 45 +++ basic-geometry-test/tests/vector2.c | 5 + basic-geometry-test/tests/vector2.h | 1 + .../tests/vector2/vector2_arithmetics.c | 380 ++++++++++++++++++ .../tests/vector2/vector2_arithmetics.h | 45 +++ basic-geometry-test/tests/vector3.c | 5 + basic-geometry-test/tests/vector3.h | 1 + .../tests/vector3/vector3_arithmetics.c | 380 ++++++++++++++++++ .../tests/vector3/vector3_arithmetics.h | 45 +++ 14 files changed, 1317 insertions(+) create mode 100644 basic-geometry-test/tests/complex/complex_arithmetics.c create mode 100644 basic-geometry-test/tests/complex/complex_arithmetics.h create mode 100644 basic-geometry-test/tests/vector2/vector2_arithmetics.c create mode 100644 basic-geometry-test/tests/vector2/vector2_arithmetics.h create mode 100644 basic-geometry-test/tests/vector3/vector3_arithmetics.c create mode 100644 basic-geometry-test/tests/vector3/vector3_arithmetics.h diff --git a/basic-geometry-test/basic-geometry-test.vcxproj b/basic-geometry-test/basic-geometry-test.vcxproj index d89a31e..4ffaa0d 100644 --- a/basic-geometry-test/basic-geometry-test.vcxproj +++ b/basic-geometry-test/basic-geometry-test.vcxproj @@ -158,6 +158,7 @@ + @@ -172,6 +173,7 @@ + @@ -180,6 +182,7 @@ + @@ -206,6 +209,7 @@ + @@ -220,6 +224,7 @@ + @@ -228,6 +233,7 @@ + diff --git a/basic-geometry-test/basic-geometry-test.vcxproj.filters b/basic-geometry-test/basic-geometry-test.vcxproj.filters index eb13dc2..5a7630d 100644 --- a/basic-geometry-test/basic-geometry-test.vcxproj.filters +++ b/basic-geometry-test/basic-geometry-test.vcxproj.filters @@ -138,6 +138,15 @@ tests + + tests\vector2 + + + tests\vector3 + + + tests\complex + @@ -276,6 +285,15 @@ tests + + tests\vector2 + + + tests\vector3 + + + tests\complex + diff --git a/basic-geometry-test/tests/complex.c b/basic-geometry-test/tests/complex.c index 10ea9a6..c0cc1fd 100644 --- a/basic-geometry-test/tests/complex.c +++ b/basic-geometry-test/tests/complex.c @@ -11,4 +11,9 @@ void test_complex() test_complex_is_zero(); test_complex_is_unit(); test_complex_modulus(); + + test_complex_add(); + test_complex_subtract(); + test_complex_multiply(); + test_complex_divide(); } diff --git a/basic-geometry-test/tests/complex.h b/basic-geometry-test/tests/complex.h index 2eab35e..efcae64 100644 --- a/basic-geometry-test/tests/complex.h +++ b/basic-geometry-test/tests/complex.h @@ -9,6 +9,7 @@ #include "./complex/complex_is_zero.h" #include "./complex/complex_is_unit.h" #include "./complex/complex_modulus.h" +#include "./complex/complex_arithmetics.h" void test_complex(); diff --git a/basic-geometry-test/tests/complex/complex_arithmetics.c b/basic-geometry-test/tests/complex/complex_arithmetics.c new file mode 100644 index 0000000..eaf3b45 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_arithmetics.c @@ -0,0 +1,380 @@ +#include "./complex_arithmetics.h" +#include "./../../helpers.h" + +// ==================== Add ===================== // + +void test_complex_add_fp32() +{ + BgcComplexFP32 vector1, vector2, result; + + print_testing_name("bgc_complex_add_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_complex_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_complex_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.real, 14.0f) || !bgc_are_close_fp32(result.imaginary, -15.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(-0.28f, 100.1f, &vector1); + bgc_complex_set_values_fp32(1.78f, -0.1f, &vector2); + + bgc_complex_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.real, 1.5f) || !bgc_are_close_fp32(result.imaginary, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_add_scaled_fp32() +{ + BgcComplexFP32 vector1, vector2, result; + + print_testing_name("bgc_complex_add_scaled_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_complex_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_complex_add_scaled_fp32(&vector1, & vector2, -2.0f, &result); + + if (!bgc_are_close_fp32(result.real, 2.0f) || !bgc_are_close_fp32(result.imaginary, -30.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(-0.27f, 100.3f, &vector1); + bgc_complex_set_values_fp32(1.59f, -0.1f, &vector2); + + bgc_complex_add_scaled_fp32(&vector1, &vector2, 3.0f, &result); + + if (!bgc_are_close_fp32(result.real, 4.5f) || !bgc_are_close_fp32(result.imaginary, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_add_fp64() +{ + BgcComplexFP64 vector1, vector2, result; + + print_testing_name("bgc_complex_add_fp64"); + + bgc_complex_set_values_fp64(10.0, -20.0, &vector1); + bgc_complex_set_values_fp64(4.0, 8.0, &vector2); + + bgc_complex_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.real, 14.0) || !bgc_are_close_fp64(result.imaginary, -12.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(-0.27, 100.3, &vector1); + bgc_complex_set_values_fp64(1.29, -0.2, &vector2); + + bgc_complex_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.real, 1.02) || !bgc_are_close_fp64(result.imaginary, 100.1)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_add_scaled_fp64() +{ + BgcComplexFP64 vector1, vector2, result; + + print_testing_name("bgc_complex_add_scaled_fp64"); + + bgc_complex_set_values_fp64(10.0, -20.0, &vector1); + bgc_complex_set_values_fp64(4.0, 5.0, &vector2); + + bgc_complex_add_scaled_fp64(&vector1, &vector2, -2.0, &result); + + if (!bgc_are_close_fp64(result.real, 2.0) || !bgc_are_close_fp64(result.imaginary, -30.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(-0.27, 100.3, &vector1); + bgc_complex_set_values_fp64(1.59, -0.1, &vector2); + + bgc_complex_add_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.real, 4.5) || !bgc_are_close_fp64(result.imaginary, 100.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_add() +{ + test_complex_add_fp32(); + test_complex_add_fp64(); + + test_complex_add_scaled_fp32(); + test_complex_add_scaled_fp64(); +} + +// ================== Subtract ================== // + +void test_complex_subtract_fp32() +{ + BgcComplexFP32 vector1, vector2, result; + + print_testing_name("bgc_complex_subtract_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_complex_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_complex_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.real, 6.0f) || !bgc_are_close_fp32(result.imaginary, -25.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(-0.28f, 99.9f, &vector1); + bgc_complex_set_values_fp32(-1.78f, -0.1f, &vector2); + + bgc_complex_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.real, 1.5f) || !bgc_are_close_fp32(result.imaginary, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_subtract_scaled_fp32() +{ + BgcComplexFP32 vector1, vector2, result; + + print_testing_name("bgc_complex_subtract_scaled_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_complex_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_complex_subtract_scaled_fp32(&vector1, &vector2, 2.0f, &result); + + if (!bgc_are_close_fp32(result.real, 2.0f) || !bgc_are_close_fp32(result.imaginary, -30.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(0.36f, 100.4f, &vector1); + bgc_complex_set_values_fp32(1.09f, 0.1f, &vector2); + + bgc_complex_subtract_scaled_fp32(&vector1, &vector2, 4.0f, &result); + + if (!bgc_are_close_fp32(result.real, -4.0f) || !bgc_are_close_fp32(result.imaginary, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_subtract_fp64() +{ + BgcComplexFP64 vector1, vector2, result; + + print_testing_name("bgc_complex_subtract_fp64"); + + bgc_complex_set_values_fp64(10.0, -20.0, &vector1); + bgc_complex_set_values_fp64(4.0, 8.0, &vector2); + + bgc_complex_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.real, 6.0) || !bgc_are_close_fp64(result.imaginary, -28.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(-0.27, 100.3, &vector1); + bgc_complex_set_values_fp64(1.29, -0.2, &vector2); + + bgc_complex_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.real, -1.56) || !bgc_are_close_fp64(result.imaginary, 100.5)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_subtract_scaled_fp64() +{ + BgcComplexFP64 vector1, vector2, result; + + print_testing_name("bgc_complex_subtract_scaled_fp64"); + + bgc_complex_set_values_fp64(10.0, 20.0, &vector1); + bgc_complex_set_values_fp64(4.0, 5.0, &vector2); + + bgc_complex_subtract_scaled_fp64(&vector1, &vector2, 2.5, &result); + + if (!bgc_are_close_fp64(result.real, 0.0) || !bgc_are_close_fp64(result.imaginary, 7.5)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(-0.27, 100.3, &vector1); + bgc_complex_set_values_fp64(-1.29, -0.1, &vector2); + + bgc_complex_subtract_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.real, 3.6) || !bgc_are_close_fp64(result.imaginary, 100.6)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_subtract() +{ + test_complex_subtract_fp32(); + test_complex_subtract_fp64(); + + test_complex_subtract_scaled_fp32(); + test_complex_subtract_scaled_fp64(); +} + +// ================== Multiply ================== // + +void test_complex_multiply_fp32() +{ + BgcComplexFP32 vector, result; + + print_testing_name("bgc_complex_multiply_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector); + + bgc_complex_multiply_fp32(&vector, 0.5f, &result); + + if (!bgc_are_close_fp32(result.real, 5.0f) || !bgc_are_close_fp32(result.imaginary, -10.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(1.78f, -0.1f, &vector); + + bgc_complex_multiply_fp32(&vector, 2.0f, &result); + + if (!bgc_are_close_fp32(result.real, 3.56f) || !bgc_are_close_fp32(result.imaginary, -0.2f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_multiply_fp64() +{ + BgcComplexFP64 vector, result; + + print_testing_name("bgc_complex_multiply_fp64"); + + bgc_complex_set_values_fp64(30.0, -10.0, &vector); + + bgc_complex_multiply_fp64(&vector, 0.3, &result); + + if (!bgc_are_close_fp64(result.real, 9.0) || !bgc_are_close_fp64(result.imaginary, -3.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(1.18, -0.25, &vector); + + bgc_complex_multiply_fp64(&vector, 4.0, &result); + + if (!bgc_are_close_fp64(result.real, 4.72) || !bgc_are_close_fp64(result.imaginary, -1.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_multiply() +{ + test_complex_multiply_fp32(); + test_complex_multiply_fp64(); +} + +// =================== Divide =================== // + +void test_complex_divide_fp32() +{ + BgcComplexFP32 vector, result; + + print_testing_name("bgc_complex_divide_fp32"); + + bgc_complex_set_values_fp32(10.0f, -20.0f, &vector); + + bgc_complex_divide_fp32(&vector, 10.0f, &result); + + if (!bgc_are_close_fp32(result.real, 1.0f) || !bgc_are_close_fp32(result.imaginary, -2.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp32(1.78f, -0.1f, &vector); + + bgc_complex_divide_fp32(&vector, 0.2f, &result); + + if (!bgc_are_close_fp32(result.real, 8.9f) || !bgc_are_close_fp32(result.imaginary, -0.5f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_divide_fp64() +{ + BgcComplexFP64 vector, result; + + print_testing_name("bgc_complex_divide_fp64"); + + bgc_complex_set_values_fp64(30.0, -10.0, &vector); + + bgc_complex_divide_fp64(&vector, 5.0, &result); + + if (!bgc_are_close_fp64(result.real, 6.0) || !bgc_are_close_fp64(result.imaginary, -2.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_complex_set_values_fp64(1.18, -0.25, &vector); + + bgc_complex_divide_fp64(&vector, 0.5, &result); + + if (!bgc_are_close_fp64(result.real, 2.36) || !bgc_are_close_fp64(result.imaginary, -0.5)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_complex_divide() +{ + test_complex_divide_fp32(); + test_complex_divide_fp64(); +} diff --git a/basic-geometry-test/tests/complex/complex_arithmetics.h b/basic-geometry-test/tests/complex/complex_arithmetics.h new file mode 100644 index 0000000..ecbae95 --- /dev/null +++ b/basic-geometry-test/tests/complex/complex_arithmetics.h @@ -0,0 +1,45 @@ +#ifndef _TEST_COMPLEX_ARITHMETICS_H_ +#define _TEST_COMPLEX_ARITHMETICS_H_ + +// ==================== Add ===================== // + +void test_complex_add_fp32(); + +void test_complex_add_scaled_fp32(); + +void test_complex_add_fp64(); + +void test_complex_add_scaled_fp64(); + +void test_complex_add(); + +// ================== Subtract ================== // + +void test_complex_subtract_fp32(); + +void test_complex_subtract_scaled_fp32(); + +void test_complex_subtract_fp64(); + +void test_complex_subtract_scaled_fp64(); + +void test_complex_subtract(); + +// ================== Multiply ================== // + +void test_complex_multiply_fp32(); + +void test_complex_multiply_fp64(); + +void test_complex_multiply(); + +// =================== Divide =================== // + +void test_complex_divide_fp32(); + +void test_complex_divide_fp64(); + +void test_complex_divide(); + +#endif + diff --git a/basic-geometry-test/tests/vector2.c b/basic-geometry-test/tests/vector2.c index 44ec217..aae89c5 100644 --- a/basic-geometry-test/tests/vector2.c +++ b/basic-geometry-test/tests/vector2.c @@ -11,6 +11,11 @@ void test_vector2() test_vector2_is_zero(); test_vector2_is_unit(); test_vector2_modulus(); + + test_vector2_add(); + test_vector2_subtract(); + test_vector2_multiply(); + test_vector2_divide(); } diff --git a/basic-geometry-test/tests/vector2.h b/basic-geometry-test/tests/vector2.h index 7d9599b..f9f2735 100644 --- a/basic-geometry-test/tests/vector2.h +++ b/basic-geometry-test/tests/vector2.h @@ -9,6 +9,7 @@ #include "./vector2/vector2_is_zero.h" #include "./vector2/vector2_is_unit.h" #include "./vector2/vector2_modulus.h" +#include "./vector2/vector2_arithmetics.h" void test_vector2(); diff --git a/basic-geometry-test/tests/vector2/vector2_arithmetics.c b/basic-geometry-test/tests/vector2/vector2_arithmetics.c new file mode 100644 index 0000000..ee87b58 --- /dev/null +++ b/basic-geometry-test/tests/vector2/vector2_arithmetics.c @@ -0,0 +1,380 @@ +#include "./vector2_arithmetics.h" +#include "./../../helpers.h" + +// ==================== Add ===================== // + +void test_vector2_add_fp32() +{ + BgcVector2FP32 vector1, vector2, result; + + print_testing_name("bgc_vector2_add_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_vector2_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_vector2_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 14.0f) || !bgc_are_close_fp32(result.x2, -15.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(-0.28f, 100.1f, &vector1); + bgc_vector2_set_values_fp32(1.78f, -0.1f, &vector2); + + bgc_vector2_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 1.5f) || !bgc_are_close_fp32(result.x2, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_add_scaled_fp32() +{ + BgcVector2FP32 vector1, vector2, result; + + print_testing_name("bgc_vector2_add_scaled_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_vector2_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_vector2_add_scaled_fp32(&vector1, & vector2, -2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 2.0f) || !bgc_are_close_fp32(result.x2, -30.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(-0.27f, 100.3f, &vector1); + bgc_vector2_set_values_fp32(1.59f, -0.1f, &vector2); + + bgc_vector2_add_scaled_fp32(&vector1, &vector2, 3.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 4.5f) || !bgc_are_close_fp32(result.x2, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_add_fp64() +{ + BgcVector2FP64 vector1, vector2, result; + + print_testing_name("bgc_vector2_add_fp64"); + + bgc_vector2_set_values_fp64(10.0, -20.0, &vector1); + bgc_vector2_set_values_fp64(4.0, 8.0, &vector2); + + bgc_vector2_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 14.0) || !bgc_are_close_fp64(result.x2, -12.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(-0.27, 100.3, &vector1); + bgc_vector2_set_values_fp64(1.29, -0.2, &vector2); + + bgc_vector2_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 1.02) || !bgc_are_close_fp64(result.x2, 100.1)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_add_scaled_fp64() +{ + BgcVector2FP64 vector1, vector2, result; + + print_testing_name("bgc_vector2_add_scaled_fp64"); + + bgc_vector2_set_values_fp64(10.0, -20.0, &vector1); + bgc_vector2_set_values_fp64(4.0, 5.0, &vector2); + + bgc_vector2_add_scaled_fp64(&vector1, &vector2, -2.0, &result); + + if (!bgc_are_close_fp64(result.x1, 2.0) || !bgc_are_close_fp64(result.x2, -30.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(-0.27, 100.3, &vector1); + bgc_vector2_set_values_fp64(1.59, -0.1, &vector2); + + bgc_vector2_add_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.x1, 4.5) || !bgc_are_close_fp64(result.x2, 100.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_add() +{ + test_vector2_add_fp32(); + test_vector2_add_fp64(); + + test_vector2_add_scaled_fp32(); + test_vector2_add_scaled_fp64(); +} + +// ================== Subtract ================== // + +void test_vector2_subtract_fp32() +{ + BgcVector2FP32 vector1, vector2, result; + + print_testing_name("bgc_vector2_subtract_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_vector2_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_vector2_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 6.0f) || !bgc_are_close_fp32(result.x2, -25.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(-0.28f, 99.9f, &vector1); + bgc_vector2_set_values_fp32(-1.78f, -0.1f, &vector2); + + bgc_vector2_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 1.5f) || !bgc_are_close_fp32(result.x2, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_subtract_scaled_fp32() +{ + BgcVector2FP32 vector1, vector2, result; + + print_testing_name("bgc_vector2_subtract_scaled_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector1); + bgc_vector2_set_values_fp32(4.0f, 5.0f, &vector2); + + bgc_vector2_subtract_scaled_fp32(&vector1, &vector2, 2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 2.0f) || !bgc_are_close_fp32(result.x2, -30.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(0.36f, 100.4f, &vector1); + bgc_vector2_set_values_fp32(1.09f, 0.1f, &vector2); + + bgc_vector2_subtract_scaled_fp32(&vector1, &vector2, 4.0f, &result); + + if (!bgc_are_close_fp32(result.x1, -4.0f) || !bgc_are_close_fp32(result.x2, 100.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_subtract_fp64() +{ + BgcVector2FP64 vector1, vector2, result; + + print_testing_name("bgc_vector2_subtract_fp64"); + + bgc_vector2_set_values_fp64(10.0, -20.0, &vector1); + bgc_vector2_set_values_fp64(4.0, 8.0, &vector2); + + bgc_vector2_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 6.0) || !bgc_are_close_fp64(result.x2, -28.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(-0.27, 100.3, &vector1); + bgc_vector2_set_values_fp64(1.29, -0.2, &vector2); + + bgc_vector2_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, -1.56) || !bgc_are_close_fp64(result.x2, 100.5)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_subtract_scaled_fp64() +{ + BgcVector2FP64 vector1, vector2, result; + + print_testing_name("bgc_vector2_subtract_scaled_fp64"); + + bgc_vector2_set_values_fp64(10.0, 20.0, &vector1); + bgc_vector2_set_values_fp64(4.0, 5.0, &vector2); + + bgc_vector2_subtract_scaled_fp64(&vector1, &vector2, 2.5, &result); + + if (!bgc_are_close_fp64(result.x1, 0.0) || !bgc_are_close_fp64(result.x2, 7.5)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(-0.27, 100.3, &vector1); + bgc_vector2_set_values_fp64(-1.29, -0.1, &vector2); + + bgc_vector2_subtract_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.x1, 3.6) || !bgc_are_close_fp64(result.x2, 100.6)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_subtract() +{ + test_vector2_subtract_fp32(); + test_vector2_subtract_fp64(); + + test_vector2_subtract_scaled_fp32(); + test_vector2_subtract_scaled_fp64(); +} + +// ================== Multiply ================== // + +void test_vector2_multiply_fp32() +{ + BgcVector2FP32 vector, result; + + print_testing_name("bgc_vector2_multiply_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector); + + bgc_vector2_multiply_fp32(&vector, 0.5f, &result); + + if (!bgc_are_close_fp32(result.x1, 5.0f) || !bgc_are_close_fp32(result.x2, -10.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(1.78f, -0.1f, &vector); + + bgc_vector2_multiply_fp32(&vector, 2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 3.56f) || !bgc_are_close_fp32(result.x2, -0.2f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_multiply_fp64() +{ + BgcVector2FP64 vector, result; + + print_testing_name("bgc_vector2_multiply_fp64"); + + bgc_vector2_set_values_fp64(30.0, -10.0, &vector); + + bgc_vector2_multiply_fp64(&vector, 0.3, &result); + + if (!bgc_are_close_fp64(result.x1, 9.0) || !bgc_are_close_fp64(result.x2, -3.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(1.18, -0.25, &vector); + + bgc_vector2_multiply_fp64(&vector, 4.0, &result); + + if (!bgc_are_close_fp64(result.x1, 4.72) || !bgc_are_close_fp64(result.x2, -1.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_multiply() +{ + test_vector2_multiply_fp32(); + test_vector2_multiply_fp64(); +} + +// =================== Divide =================== // + +void test_vector2_divide_fp32() +{ + BgcVector2FP32 vector, result; + + print_testing_name("bgc_vector2_divide_fp32"); + + bgc_vector2_set_values_fp32(10.0f, -20.0f, &vector); + + bgc_vector2_divide_fp32(&vector, 10.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 1.0f) || !bgc_are_close_fp32(result.x2, -2.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp32(1.78f, -0.1f, &vector); + + bgc_vector2_divide_fp32(&vector, 0.2f, &result); + + if (!bgc_are_close_fp32(result.x1, 8.9f) || !bgc_are_close_fp32(result.x2, -0.5f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_divide_fp64() +{ + BgcVector2FP64 vector, result; + + print_testing_name("bgc_vector2_divide_fp64"); + + bgc_vector2_set_values_fp64(30.0, -10.0, &vector); + + bgc_vector2_divide_fp64(&vector, 5.0, &result); + + if (!bgc_are_close_fp64(result.x1, 6.0) || !bgc_are_close_fp64(result.x2, -2.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector2_set_values_fp64(1.18, -0.25, &vector); + + bgc_vector2_divide_fp64(&vector, 0.5, &result); + + if (!bgc_are_close_fp64(result.x1, 2.36) || !bgc_are_close_fp64(result.x2, -0.5)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector2_divide() +{ + test_vector2_divide_fp32(); + test_vector2_divide_fp64(); +} diff --git a/basic-geometry-test/tests/vector2/vector2_arithmetics.h b/basic-geometry-test/tests/vector2/vector2_arithmetics.h new file mode 100644 index 0000000..c25b5c8 --- /dev/null +++ b/basic-geometry-test/tests/vector2/vector2_arithmetics.h @@ -0,0 +1,45 @@ +#ifndef _TEST_VECTOR2_ARITHMETICS_H_ +#define _TEST_VECTOR2_ARITHMETICS_H_ + +// ==================== Add ===================== // + +void test_vector2_add_fp32(); + +void test_vector2_add_scaled_fp32(); + +void test_vector2_add_fp64(); + +void test_vector2_add_scaled_fp64(); + +void test_vector2_add(); + +// ================== Subtract ================== // + +void test_vector2_subtract_fp32(); + +void test_vector2_subtract_scaled_fp32(); + +void test_vector2_subtract_fp64(); + +void test_vector2_subtract_scaled_fp64(); + +void test_vector2_subtract(); + +// ================== Multiply ================== // + +void test_vector2_multiply_fp32(); + +void test_vector2_multiply_fp64(); + +void test_vector2_multiply(); + +// =================== Divide =================== // + +void test_vector2_divide_fp32(); + +void test_vector2_divide_fp64(); + +void test_vector2_divide(); + +#endif + diff --git a/basic-geometry-test/tests/vector3.c b/basic-geometry-test/tests/vector3.c index c4d7c82..5801eaf 100644 --- a/basic-geometry-test/tests/vector3.c +++ b/basic-geometry-test/tests/vector3.c @@ -11,4 +11,9 @@ void test_vector3() test_vector3_is_zero(); test_vector3_is_unit(); test_vector3_modulus(); + + test_vector3_add(); + test_vector3_subtract(); + test_vector3_multiply(); + test_vector3_divide(); } diff --git a/basic-geometry-test/tests/vector3.h b/basic-geometry-test/tests/vector3.h index 13a6c6d..4379ac0 100644 --- a/basic-geometry-test/tests/vector3.h +++ b/basic-geometry-test/tests/vector3.h @@ -9,6 +9,7 @@ #include "./vector3/vector3_is_zero.h" #include "./vector3/vector3_is_unit.h" #include "./vector3/vector3_modulus.h" +#include "./vector3/vector3_arithmetics.h" void test_vector3(); diff --git a/basic-geometry-test/tests/vector3/vector3_arithmetics.c b/basic-geometry-test/tests/vector3/vector3_arithmetics.c new file mode 100644 index 0000000..50edbfb --- /dev/null +++ b/basic-geometry-test/tests/vector3/vector3_arithmetics.c @@ -0,0 +1,380 @@ +#include "./vector3_arithmetics.h" +#include "./../../helpers.h" + +// ==================== Add ===================== // + +void test_vector3_add_fp32() +{ + BgcVector3FP32 vector1, vector2, result; + + print_testing_name("bgc_vector3_add_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 30.0f, &vector1); + bgc_vector3_set_values_fp32(4.0f, 5.0f, -6.0f, &vector2); + + bgc_vector3_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 14.0f) || !bgc_are_close_fp32(result.x2, -15.0f) || !bgc_are_close_fp32(result.x3, 24.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(-0.28f, 100.1f, -1.6f, &vector1); + bgc_vector3_set_values_fp32(1.78f, -0.1f, 0.4f, &vector2); + + bgc_vector3_add_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 1.5f) || !bgc_are_close_fp32(result.x2, 100.0f) || !bgc_are_close_fp32(result.x3, -1.2f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_add_scaled_fp32() +{ + BgcVector3FP32 vector1, vector2, result; + + print_testing_name("bgc_vector3_add_scaled_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 24.0f, &vector1); + bgc_vector3_set_values_fp32(4.0f, 5.0f, 6.0f, &vector2); + + bgc_vector3_add_scaled_fp32(&vector1, & vector2, -2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 2.0f) || !bgc_are_close_fp32(result.x2, -30.0f) || !bgc_are_close_fp32(result.x3, 12.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(-0.27f, 100.3f, -1.2f, &vector1); + bgc_vector3_set_values_fp32(1.59f, -0.1f, 0.4f, &vector2); + + bgc_vector3_add_scaled_fp32(&vector1, &vector2, 3.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 4.5f) || !bgc_are_close_fp32(result.x2, 100.0f) || !bgc_are_close_fp32(result.x3, 0.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_add_fp64() +{ + BgcVector3FP64 vector1, vector2, result; + + print_testing_name("bgc_vector3_add_fp64"); + + bgc_vector3_set_values_fp64(10.0, -20.0, 30.0, &vector1); + bgc_vector3_set_values_fp64(4.0, 8.0, -9.0, &vector2); + + bgc_vector3_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 14.0) || !bgc_are_close_fp64(result.x2, -12.0) || !bgc_are_close_fp64(result.x3, 21.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(-0.27, 100.3, -8.2, &vector1); + bgc_vector3_set_values_fp64(1.29, -0.2, 14.1, &vector2); + + bgc_vector3_add_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 1.02) || !bgc_are_close_fp64(result.x2, 100.1) || !bgc_are_close_fp64(result.x3, 5.9)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_add_scaled_fp64() +{ + BgcVector3FP64 vector1, vector2, result; + + print_testing_name("bgc_vector3_add_scaled_fp64"); + + bgc_vector3_set_values_fp64(10.0, -20.0, 7.5, &vector1); + bgc_vector3_set_values_fp64(4.0, 5.0, 1.25, &vector2); + + bgc_vector3_add_scaled_fp64(&vector1, &vector2, -2.0, &result); + + if (!bgc_are_close_fp64(result.x1, 2.0) || !bgc_are_close_fp64(result.x2, -30.0) || !bgc_are_close_fp64(result.x3, 5.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(-0.27, 100.3, -20.0, &vector1); + bgc_vector3_set_values_fp64(1.59, -0.1, 5.0, &vector2); + + bgc_vector3_add_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.x1, 4.5) || !bgc_are_close_fp64(result.x2, 100.0) || !bgc_are_close_fp64(result.x3, -5.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_add() +{ + test_vector3_add_fp32(); + test_vector3_add_fp64(); + + test_vector3_add_scaled_fp32(); + test_vector3_add_scaled_fp64(); +} + +// ================== Subtract ================== // + +void test_vector3_subtract_fp32() +{ + BgcVector3FP32 vector1, vector2, result; + + print_testing_name("bgc_vector3_subtract_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 16.0f, &vector1); + bgc_vector3_set_values_fp32(4.0f, 5.0f, -4.0f, &vector2); + + bgc_vector3_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 6.0f) || !bgc_are_close_fp32(result.x2, -25.0f) || !bgc_are_close_fp32(result.x3, 20.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(-0.28f, 99.9f, -0.2f, &vector1); + bgc_vector3_set_values_fp32(-1.78f, -0.1f, 2.8f, &vector2); + + bgc_vector3_subtract_fp32(&vector1, &vector2, &result); + + if (!bgc_are_close_fp32(result.x1, 1.5f) || !bgc_are_close_fp32(result.x2, 100.0f) || !bgc_are_close_fp32(result.x3, -3.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_subtract_scaled_fp32() +{ + BgcVector3FP32 vector1, vector2, result; + + print_testing_name("bgc_vector3_subtract_scaled_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 1.25f, &vector1); + bgc_vector3_set_values_fp32(4.0f, 5.0f, -0.4f, &vector2); + + bgc_vector3_subtract_scaled_fp32(&vector1, &vector2, 2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 2.0f) || !bgc_are_close_fp32(result.x2, -30.0f) || !bgc_are_close_fp32(result.x3, 2.05f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(0.36f, 100.4f, 10, &vector1); + bgc_vector3_set_values_fp32(1.09f, 0.1f, 2.5f, &vector2); + + bgc_vector3_subtract_scaled_fp32(&vector1, &vector2, 4.0f, &result); + + if (!bgc_are_close_fp32(result.x1, -4.0f) || !bgc_are_close_fp32(result.x2, 100.0f) || !bgc_are_close_fp32(result.x3, 0.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_subtract_fp64() +{ + BgcVector3FP64 vector1, vector2, result; + + print_testing_name("bgc_vector3_subtract_fp64"); + + bgc_vector3_set_values_fp64(10.0, -20.0, 15.0, &vector1); + bgc_vector3_set_values_fp64(4.0, 8.0, -5.0, &vector2); + + bgc_vector3_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, 6.0) || !bgc_are_close_fp64(result.x2, -28.0) || !bgc_are_close_fp64(result.x3, 20.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(-0.27, 100.3, 2.0, &vector1); + bgc_vector3_set_values_fp64(1.29, -0.2, 0.8, &vector2); + + bgc_vector3_subtract_fp64(&vector1, &vector2, &result); + + if (!bgc_are_close_fp64(result.x1, -1.56) || !bgc_are_close_fp64(result.x2, 100.5) || !bgc_are_close_fp64(result.x3, 1.2)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_subtract_scaled_fp64() +{ + BgcVector3FP64 vector1, vector2, result; + + print_testing_name("bgc_vector3_subtract_scaled_fp64"); + + bgc_vector3_set_values_fp64(10.0, 20.0, 0.1, &vector1); + bgc_vector3_set_values_fp64(4.0, 5.0, -4.0, &vector2); + + bgc_vector3_subtract_scaled_fp64(&vector1, &vector2, 2.5, &result); + + if (!bgc_are_close_fp64(result.x1, 0.0) || !bgc_are_close_fp64(result.x2, 7.5) || !bgc_are_close_fp64(result.x3, 10.1)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(-0.27, 100.3, -0.01, &vector1); + bgc_vector3_set_values_fp64(-1.29, -0.1, 0.33, &vector2); + + bgc_vector3_subtract_scaled_fp64(&vector1, &vector2, 3.0, &result); + + if (!bgc_are_close_fp64(result.x1, 3.6) || !bgc_are_close_fp64(result.x2, 100.6) || !bgc_are_close_fp64(result.x3, -1.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_subtract() +{ + test_vector3_subtract_fp32(); + test_vector3_subtract_fp64(); + + test_vector3_subtract_scaled_fp32(); + test_vector3_subtract_scaled_fp64(); +} + +// ================== Multiply ================== // + +void test_vector3_multiply_fp32() +{ + BgcVector3FP32 vector, result; + + print_testing_name("bgc_vector3_multiply_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 3.0f, &vector); + + bgc_vector3_multiply_fp32(&vector, 0.5f, &result); + + if (!bgc_are_close_fp32(result.x1, 5.0f) || !bgc_are_close_fp32(result.x2, -10.0f) || !bgc_are_close_fp32(result.x3, 1.5f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(1.78f, -0.1f, 3.6f, &vector); + + bgc_vector3_multiply_fp32(&vector, 2.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 3.56f) || !bgc_are_close_fp32(result.x2, -0.2f) || !bgc_are_close_fp32(result.x3, 7.2f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_multiply_fp64() +{ + BgcVector3FP64 vector, result; + + print_testing_name("bgc_vector3_multiply_fp64"); + + bgc_vector3_set_values_fp64(30.0, -10.0, 4.0, &vector); + + bgc_vector3_multiply_fp64(&vector, 0.3, &result); + + if (!bgc_are_close_fp64(result.x1, 9.0) || !bgc_are_close_fp64(result.x2, -3.0) || !bgc_are_close_fp64(result.x3, 1.2)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(1.18, -0.25, 0.02, &vector); + + bgc_vector3_multiply_fp64(&vector, 4.0, &result); + + if (!bgc_are_close_fp64(result.x1, 4.72) || !bgc_are_close_fp64(result.x2, -1.0) || !bgc_are_close_fp64(result.x3, 0.08)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_multiply() +{ + test_vector3_multiply_fp32(); + test_vector3_multiply_fp64(); +} + +// =================== Divide =================== // + +void test_vector3_divide_fp32() +{ + BgcVector3FP32 vector, result; + + print_testing_name("bgc_vector3_divide_fp32"); + + bgc_vector3_set_values_fp32(10.0f, -20.0f, 40.0f, &vector); + + bgc_vector3_divide_fp32(&vector, 10.0f, &result); + + if (!bgc_are_close_fp32(result.x1, 1.0f) || !bgc_are_close_fp32(result.x2, -2.0f) || !bgc_are_close_fp32(result.x3, 4.0f)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp32(1.78f, -0.1f, 0.4f, &vector); + + bgc_vector3_divide_fp32(&vector, 0.2f, &result); + + if (!bgc_are_close_fp32(result.x1, 8.9f) || !bgc_are_close_fp32(result.x2, -0.5f) || !bgc_are_close_fp32(result.x3, 2.0f)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_divide_fp64() +{ + BgcVector3FP64 vector, result; + + print_testing_name("bgc_vector3_divide_fp64"); + + bgc_vector3_set_values_fp64(30.0, -10.0, 20.0, &vector); + + bgc_vector3_divide_fp64(&vector, 5.0, &result); + + if (!bgc_are_close_fp64(result.x1, 6.0) || !bgc_are_close_fp64(result.x2, -2.0) || !bgc_are_close_fp64(result.x3, 4.0)) { + print_testing_error("first test failed"); + return; + } + + bgc_vector3_set_values_fp64(4.5, -0.25, 1.5, &vector); + + bgc_vector3_divide_fp64(&vector, -0.5, &result); + + if (!bgc_are_close_fp64(result.x1, -9.0) || !bgc_are_close_fp64(result.x2, 0.5) || !bgc_are_close_fp64(result.x3, -3.0)) { + print_testing_error("second test failed"); + return; + } + + print_testing_success(); +} + +void test_vector3_divide() +{ + test_vector3_divide_fp32(); + test_vector3_divide_fp64(); +} diff --git a/basic-geometry-test/tests/vector3/vector3_arithmetics.h b/basic-geometry-test/tests/vector3/vector3_arithmetics.h new file mode 100644 index 0000000..156c94d --- /dev/null +++ b/basic-geometry-test/tests/vector3/vector3_arithmetics.h @@ -0,0 +1,45 @@ +#ifndef _TEST_VECTOR3_ARITHMETICS_H_ +#define _TEST_VECTOR3_ARITHMETICS_H_ + +// ==================== Add ===================== // + +void test_vector3_add_fp32(); + +void test_vector3_add_scaled_fp32(); + +void test_vector3_add_fp64(); + +void test_vector3_add_scaled_fp64(); + +void test_vector3_add(); + +// ================== Subtract ================== // + +void test_vector3_subtract_fp32(); + +void test_vector3_subtract_scaled_fp32(); + +void test_vector3_subtract_fp64(); + +void test_vector3_subtract_scaled_fp64(); + +void test_vector3_subtract(); + +// ================== Multiply ================== // + +void test_vector3_multiply_fp32(); + +void test_vector3_multiply_fp64(); + +void test_vector3_multiply(); + +// =================== Divide =================== // + +void test_vector3_divide_fp32(); + +void test_vector3_divide_fp64(); + +void test_vector3_divide(); + +#endif + From 9d7011e81e286f5f2cec221fcf9a835b249a1d00 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Mon, 17 Mar 2025 09:56:56 +0700 Subject: [PATCH 08/10] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=84=D0=B5=D1=80=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=BE=D0=B9=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8F=D1=86=D0=B8=D0=B8,=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20=D0=BE=D1=82=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20acos=20?= =?UTF-8?q?=D0=BA=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8E=20atan2,=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry-dev/main.c | 41 +++-- basic-geometry/basic-geometry.h | 3 +- basic-geometry/basic-geometry.vcxproj | 10 +- basic-geometry/basic-geometry.vcxproj.filters | 30 ++-- basic-geometry/complex.c | 4 +- basic-geometry/complex.h | 4 +- basic-geometry/quaternion.c | 92 +++++++++- basic-geometry/quaternion.h | 12 +- basic-geometry/slerp.c | 129 ++++++++++++++ basic-geometry/slerp.h | 94 ++++++++++ basic-geometry/utilities.h | 2 + basic-geometry/vector2.c | 40 ++--- basic-geometry/vector2.h | 4 +- basic-geometry/vector3.c | 44 ++--- basic-geometry/vector3.h | 4 +- basic-geometry/versor.c | 165 +++++++++++++----- basic-geometry/versor.h | 14 +- 17 files changed, 558 insertions(+), 134 deletions(-) create mode 100644 basic-geometry/slerp.c create mode 100644 basic-geometry/slerp.h diff --git a/basic-geometry-dev/main.c b/basic-geometry-dev/main.c index 901b4e3..6dcf2ae 100644 --- a/basic-geometry-dev/main.c +++ b/basic-geometry-dev/main.c @@ -138,17 +138,36 @@ int main() { return 0; } */ - +/* int main() { - const float exponent = 2.0f; - - BgcVersorFP32 turn, result; - - bgc_versor_set_turn_fp32(0, 0, 1, 120, BGC_ANGLE_UNIT_DEGREES, &turn); - - bgc_versor_get_exponation_fp32(&turn, exponent, &result); - - printf("(%f, %f, %f, %f) ^ %f = (%f, %f, %f, %f)\n", turn.s0, turn.x1, turn.x2, turn.x3, exponent, result.s0, result.x1, result.x2, result.x3); - + BgcVersorFP32 start = { 1.0f, 0.0f, 0.0f, 0.0f }; + BgcVersorFP32 end = { 0.0f, 1.0f, 0.0f, 0.0f }; + BgcVersorFP32 result; + bgc_versor_spherical_interpolation_fp32(&start, &end, 0.5f, &result); + printf("Result: %0.12f, %0.12f, %0.12f, %0.12f\n", result.s0, result.x1, result.x2, result.x3); + return 0; +} +*/ + +int main() { + //BgcVersorFP32 start = { 1.0f, 0.0f, 0.0f, 0.0f }; + //BgcVersorFP32 end = { 0.0f, 1.0f, 0.0f, 0.0f }; + /* + BgcVersorFP32 start = { 1.0f, 0.0f, 0.0f, 0.0f }; + BgcVersorFP32 end = { 0.9999f, 0.01414f, 0.0f, 0.0f }; + BgcSlerpFP32 slerp; + BgcVersorFP32 result; + bgc_slerp_make_fp32(&start, &end, &slerp); + bgc_slerp_get_turn_for_phase_fp32(&slerp, 0.5f, &result); + printf("Result: %0.12f, %0.12f, %0.12f, %0.12f\n", result.s0, result.x1, result.x2, result.x3); + */ + + BgcVersorFP64 start = { 1.0, 0.0, 0.0, 0.0 }; + BgcVersorFP64 end = { -0.707, 0.707, 0.0, 0.0 }; + BgcVersorFP64 result; + BgcSlerpFP64 slerp; + bgc_slerp_make_full_fp64(&start, &end, &slerp); + bgc_slerp_get_turn_for_phase_fp64(&slerp, 0.5f, &result); + printf("Result: %0.15f, %0.15f, %0.15f, %0.15f\n", result.s0, result.x1, result.x2, result.x3); return 0; } diff --git a/basic-geometry/basic-geometry.h b/basic-geometry/basic-geometry.h index fb83f61..fcaf5bb 100644 --- a/basic-geometry/basic-geometry.h +++ b/basic-geometry/basic-geometry.h @@ -13,7 +13,7 @@ #include "./matrix2x3.h" #include "./matrix3x2.h" #include "./matrix3x3.h" - + #include "./complex.h" #include "./cotes-number.h" @@ -21,5 +21,6 @@ #include "./quaternion.h" #include "./versor.h" +#include "./slerp.h" #endif diff --git a/basic-geometry/basic-geometry.vcxproj b/basic-geometry/basic-geometry.vcxproj index 94fb723..3614dc7 100644 --- a/basic-geometry/basic-geometry.vcxproj +++ b/basic-geometry/basic-geometry.vcxproj @@ -21,8 +21,8 @@ - - + + @@ -31,14 +31,15 @@ + - - + + @@ -47,6 +48,7 @@ + diff --git a/basic-geometry/basic-geometry.vcxproj.filters b/basic-geometry/basic-geometry.vcxproj.filters index 260e3e3..440dcb1 100644 --- a/basic-geometry/basic-geometry.vcxproj.filters +++ b/basic-geometry/basic-geometry.vcxproj.filters @@ -18,12 +18,12 @@ Файлы заголовков - - Файлы заголовков - - - Файлы заголовков - + + Файлы заголовков + + + Файлы заголовков + Файлы заголовков @@ -60,17 +60,20 @@ Файлы заголовков + + Исходные файлы + + + Исходные файлы + + + Файлы заголовков + Исходные файлы - - Исходные файлы - - - Исходные файлы - Исходные файлы @@ -104,5 +107,8 @@ Исходные файлы + + Исходные файлы + \ No newline at end of file diff --git a/basic-geometry/complex.c b/basic-geometry/complex.c index 59c6979..ef3a0bd 100644 --- a/basic-geometry/complex.c +++ b/basic-geometry/complex.c @@ -69,8 +69,8 @@ extern inline void bgc_complex_get_mean_of_two_fp64(const BgcComplexFP64* number extern inline void bgc_complex_get_mean_of_three_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const BgcComplexFP32* number3, BgcComplexFP32* mean); extern inline void bgc_complex_get_mean_of_three_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const BgcComplexFP64* number3, BgcComplexFP64* mean); -extern inline void bgc_complex_get_linear_interpolation_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation); -extern inline void bgc_complex_get_linear_interpolation_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation); +extern inline void bgc_complex_interpolate_linearly_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation); +extern inline void bgc_complex_interpolate_linearly_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation); extern inline void bgc_complex_minimize_fp32(const BgcComplexFP32* number, BgcComplexFP32* minimal); extern inline void bgc_complex_minimize_fp64(const BgcComplexFP64* number, BgcComplexFP64* minimal); diff --git a/basic-geometry/complex.h b/basic-geometry/complex.h index c7b77ff..e551609 100644 --- a/basic-geometry/complex.h +++ b/basic-geometry/complex.h @@ -428,7 +428,7 @@ inline void bgc_complex_get_mean_of_three_fp64(const BgcComplexFP64* number1, co // =================== Linear =================== // -inline void bgc_complex_get_linear_interpolation_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation) +inline void bgc_complex_interpolate_linearly_fp32(const BgcComplexFP32* number1, const BgcComplexFP32* number2, const float phase, BgcComplexFP32* interpolation) { const float counterphase = 1.0f - phase; @@ -436,7 +436,7 @@ inline void bgc_complex_get_linear_interpolation_fp32(const BgcComplexFP32* numb interpolation->imaginary = number1->imaginary * counterphase + number2->imaginary * phase; } -inline void bgc_complex_get_linear_interpolation_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation) +inline void bgc_complex_interpolate_linearly_fp64(const BgcComplexFP64* number1, const BgcComplexFP64* number2, const double phase, BgcComplexFP64* interpolation) { const double counterphase = 1.0 - phase; diff --git a/basic-geometry/quaternion.c b/basic-geometry/quaternion.c index 963dba7..df057b2 100644 --- a/basic-geometry/quaternion.c +++ b/basic-geometry/quaternion.c @@ -1,3 +1,4 @@ +#include #include "quaternion.h" extern inline void bgc_quaternion_reset_fp32(BgcQuaternionFP32* quaternion); @@ -63,8 +64,8 @@ extern inline void bgc_quaternion_multiply_fp64(const BgcQuaternionFP64* multipl extern inline void bgc_quaternion_divide_fp32(const BgcQuaternionFP32* dividend, const float divisor, BgcQuaternionFP32* quotient); extern inline void bgc_quaternion_divide_fp64(const BgcQuaternionFP64* dividend, const double divisor, BgcQuaternionFP64* quotient); -extern inline void bgc_quaternion_get_linear_interpolation_fp32(const BgcQuaternionFP32* vector1, const BgcQuaternionFP32* vector2, const float phase, BgcQuaternionFP32* interpolation); -extern inline void bgc_quaternion_get_linear_interpolation_fp64(const BgcQuaternionFP64* vector1, const BgcQuaternionFP64* vector2, const double phase, BgcQuaternionFP64* interpolation); +extern inline void bgc_quaternion_interpolate_linearly_fp32(const BgcQuaternionFP32* vector1, const BgcQuaternionFP32* vector2, const float phase, BgcQuaternionFP32* interpolation); +extern inline void bgc_quaternion_interpolate_linearly_fp64(const BgcQuaternionFP64* vector1, const BgcQuaternionFP64* vector2, const double phase, BgcQuaternionFP64* interpolation); extern inline int bgc_quaternion_get_rotation_matrix_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* rotation); extern inline int bgc_quaternion_get_rotation_matrix_fp64(const BgcQuaternionFP64* quaternion, BgcMatrix3x3FP64* rotation); @@ -75,6 +76,89 @@ extern inline int bgc_quaternion_get_reverse_matrix_fp64(const BgcQuaternionFP64 extern inline int bgc_quaternion_get_both_matrixes_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* rotation, BgcMatrix3x3FP32* reverse); extern inline int bgc_quaternion_get_both_matrixes_fp64(const BgcQuaternionFP64* quaternion, BgcMatrix3x3FP64* rotation, BgcMatrix3x3FP64* reverse); +extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); +extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); -extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); -extern inline int bgc_quaternion_are_close_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2); +// =============== Get Exponation =============== // + +int bgc_quaternion_get_exponation_fp32(const BgcQuaternionFP32* base, const float exponent, BgcQuaternionFP32* power) +{ + const float s0s0 = base->s0 * base->s0; + const float x1x1 = base->x1 * base->x1; + const float x2x2 = base->x2 * base->x2; + const float x3x3 = base->x3 * base->x3; + + const float square_vector = x1x1 + (x2x2 + x3x3); + const float square_modulus = (s0s0 + x1x1) + (x2x2 + x3x3); + + // square_modulus != square_modulus means checking for NaN value at square_modulus + if (square_modulus != square_modulus) { + return 0; + } + + if (square_vector <= BGC_SQUARE_EPSYLON_FP32) { + if (base->s0 < 0.0f) { + return 0; + } + + power->s0 = powf(base->s0, exponent); + power->x1 = 0.0f; + power->x2 = 0.0f; + power->x3 = 0.0f; + + return 1; + } + + const float vector_modulus = sqrtf(square_vector); + const float power_angle = atan2f(vector_modulus, base->s0) * exponent; + const float power_modulus = powf(square_modulus, 0.5f * exponent); + const float multiplier = power_modulus * sinf(power_angle) / vector_modulus; + + power->s0 = power_modulus * cosf(power_angle); + power->x1 = base->x1 * multiplier; + power->x2 = base->x2 * multiplier; + power->x3 = base->x3 * multiplier; + + return 1; +} + +int bgc_quaternion_get_exponation_fp64(const BgcQuaternionFP64* base, const double exponent, BgcQuaternionFP64* power) +{ + const double s0s0 = base->s0 * base->s0; + const double x1x1 = base->x1 * base->x1; + const double x2x2 = base->x2 * base->x2; + const double x3x3 = base->x3 * base->x3; + + const double square_vector = x1x1 + (x2x2 + x3x3); + const double square_modulus = (s0s0 + x1x1) + (x2x2 + x3x3); + + // square_modulus != square_modulus means checking for NaN value at square_modulus + if (square_modulus != square_modulus) { + return 0; + } + + if (square_vector <= BGC_SQUARE_EPSYLON_FP64) { + if (base->s0 < 0.0) { + return 0; + } + + power->s0 = pow(base->s0, exponent); + power->x1 = 0.0; + power->x2 = 0.0; + power->x3 = 0.0; + + return 1; + } + + const double vector_modulus = sqrt(square_vector); + const double power_angle = atan2(vector_modulus, base->s0) * exponent; + const double power_modulus = pow(square_modulus, 0.5 * exponent); + const double multiplier = power_modulus * sin(power_angle) / vector_modulus; + + power->s0 = power_modulus * cos(power_angle); + power->x1 = base->x1 * multiplier; + power->x2 = base->x2 * multiplier; + power->x3 = base->x3 * multiplier; + + return 1; +} diff --git a/basic-geometry/quaternion.h b/basic-geometry/quaternion.h index 54be3fa..ebf06db 100644 --- a/basic-geometry/quaternion.h +++ b/basic-geometry/quaternion.h @@ -473,9 +473,9 @@ inline void bgc_quaternion_divide_fp64(const BgcQuaternionFP64* dividend, const bgc_quaternion_multiply_fp64(dividend, 1.0 / divisor, quotient); } -// =================== Linear =================== // +// ============ Linear Interpolation ============ // -inline void bgc_quaternion_get_linear_interpolation_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2, const float phase, BgcQuaternionFP32* interpolation) +inline void bgc_quaternion_interpolate_linearly_fp32(const BgcQuaternionFP32* quaternion1, const BgcQuaternionFP32* quaternion2, const float phase, BgcQuaternionFP32* interpolation) { const float counterphase = 1.0f - phase; @@ -485,7 +485,7 @@ inline void bgc_quaternion_get_linear_interpolation_fp32(const BgcQuaternionFP32 interpolation->x3 = quaternion1->x3 * counterphase + quaternion2->x3 * phase; } -inline void bgc_quaternion_get_linear_interpolation_fp64(const BgcQuaternionFP64* quaternion1, const BgcQuaternionFP64* quaternion2, const double phase, BgcQuaternionFP64* interpolation) +inline void bgc_quaternion_interpolate_linearly_fp64(const BgcQuaternionFP64* quaternion1, const BgcQuaternionFP64* quaternion2, const double phase, BgcQuaternionFP64* interpolation) { const double counterphase = 1.0 - phase; @@ -495,6 +495,12 @@ inline void bgc_quaternion_get_linear_interpolation_fp64(const BgcQuaternionFP64 interpolation->x3 = quaternion1->x3 * counterphase + quaternion2->x3 * phase; } +// =============== Get Exponation =============== // + +int bgc_quaternion_get_exponation_fp32(const BgcQuaternionFP32* base, const float exponent, BgcQuaternionFP32* power); + +int bgc_quaternion_get_exponation_fp64(const BgcQuaternionFP64* base, const double exponent, BgcQuaternionFP64* power); + // ============ Get Rotation Matrix ============= // inline int bgc_quaternion_get_rotation_matrix_fp32(const BgcQuaternionFP32* quaternion, BgcMatrix3x3FP32* rotation) diff --git a/basic-geometry/slerp.c b/basic-geometry/slerp.c new file mode 100644 index 0000000..b318059 --- /dev/null +++ b/basic-geometry/slerp.c @@ -0,0 +1,129 @@ +#include "./slerp.h" + +extern inline void bgc_slerp_reset_fp32(BgcSlerpFP32* slerp); +extern inline void bgc_slerp_reset_fp64(BgcSlerpFP64* slerp); + +extern inline bgc_slerp_get_turn_for_phase_fp32(const BgcSlerpFP32* slerp, const float phase, BgcVersorFP32* result); +extern inline bgc_slerp_get_turn_for_phase_fp64(const BgcSlerpFP64* slerp, const double phase, BgcVersorFP64* result); + +void bgc_slerp_make_full_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, BgcSlerpFP32* slerp) +{ + BgcVersorFP32 delta; + + bgc_versor_exclude_fp32(end, start, &delta); + + const float square_vector = delta.x1 * delta.x1 + delta.x2 * delta.x2 + delta.x3 * delta.x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP32 || square_vector != square_vector) { + bgc_slerp_reset_fp32(slerp); + return; + } + + const float vector_modulus = sqrtf(square_vector); + + slerp->radians = atan2f(vector_modulus, delta.s0); + + const float mutliplier = 1.0f / vector_modulus; + + slerp->s0_cos_weight = start->s0; + slerp->x1_cos_weight = start->x1; + slerp->x2_cos_weight = start->x2; + slerp->x3_cos_weight = start->x3; + + slerp->s0_sin_weight = -mutliplier * (delta.x1 * start->x1 + delta.x2 * start->x2 + delta.x3 * start->x3); + slerp->x1_sin_weight = mutliplier * (delta.x1 * start->s0 + delta.x2 * start->x3 - delta.x3 * start->x2); + slerp->x2_sin_weight = mutliplier * (delta.x2 * start->s0 - delta.x1 * start->x3 + delta.x3 * start->x1); + slerp->x3_sin_weight = mutliplier * (delta.x3 * start->s0 - delta.x2 * start->x1 + delta.x1 * start->x2); +} + +void bgc_slerp_make_full_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, BgcSlerpFP64* slerp) +{ + BgcVersorFP64 delta; + + bgc_versor_exclude_fp64(end, start, &delta); + + const double square_vector = delta.x1 * delta.x1 + delta.x2 * delta.x2 + delta.x3 * delta.x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP64 || square_vector != square_vector) { + bgc_slerp_reset_fp64(slerp); + return; + } + + const double vector_modulus = sqrt(square_vector); + + slerp->radians = atan2(vector_modulus, delta.s0); + + const double mutliplier = 1.0 / vector_modulus; + + slerp->s0_cos_weight = start->s0; + slerp->x1_cos_weight = start->x1; + slerp->x2_cos_weight = start->x2; + slerp->x3_cos_weight = start->x3; + + slerp->s0_sin_weight = -mutliplier * (delta.x1 * start->x1 + delta.x2 * start->x2 + delta.x3 * start->x3); + slerp->x1_sin_weight = mutliplier * (delta.x1 * start->s0 + delta.x2 * start->x3 - delta.x3 * start->x2); + slerp->x2_sin_weight = mutliplier * (delta.x2 * start->s0 - delta.x1 * start->x3 + delta.x3 * start->x1); + slerp->x3_sin_weight = mutliplier * (delta.x3 * start->s0 - delta.x2 * start->x1 + delta.x1 * start->x2); +} + +void bgc_slerp_make_shortened_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, BgcSlerpFP32* slerp) +{ + BgcVersorFP32 delta; + + bgc_versor_exclude_fp32(end, start, &delta); + bgc_versor_shorten_fp32(&delta, &delta); + + const float square_vector = delta.x1 * delta.x1 + delta.x2 * delta.x2 + delta.x3 * delta.x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP32 || square_vector != square_vector) { + bgc_slerp_reset_fp32(slerp); + return; + } + + const float vector_modulus = sqrtf(square_vector); + + slerp->radians = atan2f(vector_modulus, delta.s0); + + const float mutliplier = 1.0f / vector_modulus; + + slerp->s0_cos_weight = start->s0; + slerp->x1_cos_weight = start->x1; + slerp->x2_cos_weight = start->x2; + slerp->x3_cos_weight = start->x3; + + slerp->s0_sin_weight = -mutliplier * (delta.x1 * start->x1 + delta.x2 * start->x2 + delta.x3 * start->x3); + slerp->x1_sin_weight = mutliplier * (delta.x1 * start->s0 + delta.x2 * start->x3 - delta.x3 * start->x2); + slerp->x2_sin_weight = mutliplier * (delta.x2 * start->s0 - delta.x1 * start->x3 + delta.x3 * start->x1); + slerp->x3_sin_weight = mutliplier * (delta.x3 * start->s0 - delta.x2 * start->x1 + delta.x1 * start->x2); +} + +void bgc_slerp_make_shortened_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, BgcSlerpFP64* slerp) +{ + BgcVersorFP64 delta; + + bgc_versor_exclude_fp64(end, start, &delta); + bgc_versor_shorten_fp64(&delta, &delta); + + const double square_vector = delta.x1 * delta.x1 + delta.x2 * delta.x2 + delta.x3 * delta.x3; + + if (square_vector <= BGC_SQUARE_EPSYLON_FP64 || square_vector != square_vector) { + bgc_slerp_reset_fp64(slerp); + return; + } + + const double vector_modulus = sqrt(square_vector); + + slerp->radians = atan2(vector_modulus, delta.s0); + + const double mutliplier = 1.0 / vector_modulus; + + slerp->s0_cos_weight = start->s0; + slerp->x1_cos_weight = start->x1; + slerp->x2_cos_weight = start->x2; + slerp->x3_cos_weight = start->x3; + + slerp->s0_sin_weight = -mutliplier * (delta.x1 * start->x1 + delta.x2 * start->x2 + delta.x3 * start->x3); + slerp->x1_sin_weight = mutliplier * (delta.x1 * start->s0 + delta.x2 * start->x3 - delta.x3 * start->x2); + slerp->x2_sin_weight = mutliplier * (delta.x2 * start->s0 - delta.x1 * start->x3 + delta.x3 * start->x1); + slerp->x3_sin_weight = mutliplier * (delta.x3 * start->s0 - delta.x2 * start->x1 + delta.x1 * start->x2); +} diff --git a/basic-geometry/slerp.h b/basic-geometry/slerp.h new file mode 100644 index 0000000..9289008 --- /dev/null +++ b/basic-geometry/slerp.h @@ -0,0 +1,94 @@ +#ifndef _BGC_VERSOR_SLERP_H_ +#define _BGC_VERSOR_SLERP_H_ + +#include "./versor.h" + +typedef struct { + float s0_cos_weight, s0_sin_weight; + float x1_cos_weight, x1_sin_weight; + float x2_cos_weight, x2_sin_weight; + float x3_cos_weight, x3_sin_weight; + float radians; +} BgcSlerpFP32; + +typedef struct { + double s0_cos_weight, s0_sin_weight; + double x1_cos_weight, x1_sin_weight; + double x2_cos_weight, x2_sin_weight; + double x3_cos_weight, x3_sin_weight; + double radians; +} BgcSlerpFP64; + +inline void bgc_slerp_reset_fp32(BgcSlerpFP32* slerp) +{ + slerp->s0_cos_weight = 1.0f; + slerp->s0_sin_weight = 0.0f; + + slerp->x1_cos_weight = 0.0f; + slerp->x1_sin_weight = 0.0f; + + slerp->x2_cos_weight = 0.0f; + slerp->x2_sin_weight = 0.0f; + + slerp->x3_cos_weight = 0.0f; + slerp->x3_sin_weight = 0.0f; + + slerp->radians = 0.0f; +} + +inline void bgc_slerp_reset_fp64(BgcSlerpFP64* slerp) +{ + slerp->s0_cos_weight = 1.0; + slerp->s0_sin_weight = 0.0; + + slerp->x1_cos_weight = 0.0; + slerp->x1_sin_weight = 0.0; + + slerp->x2_cos_weight = 0.0; + slerp->x2_sin_weight = 0.0; + + slerp->x3_cos_weight = 0.0; + slerp->x3_sin_weight = 0.0; + + slerp->radians = 0.0; +} + +void bgc_slerp_make_full_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, BgcSlerpFP32* slerp); + +void bgc_slerp_make_full_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, BgcSlerpFP64* slerp); + +void bgc_slerp_make_shortened_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, BgcSlerpFP32* slerp); + +void bgc_slerp_make_shortened_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, BgcSlerpFP64* slerp); + +inline bgc_slerp_get_turn_for_phase_fp32(const BgcSlerpFP32* slerp, const float phase, BgcVersorFP32* result) +{ + const float angle = slerp->radians * phase; + const float cosine = cosf(angle); + const float sine = sinf(angle); + + bgc_versor_set_values_fp32( + slerp->s0_cos_weight * cosine + slerp->s0_sin_weight * sine, + slerp->x1_cos_weight * cosine + slerp->x1_sin_weight * sine, + slerp->x2_cos_weight * cosine + slerp->x2_sin_weight * sine, + slerp->x3_cos_weight * cosine + slerp->x3_sin_weight * sine, + result + ); +} + +inline bgc_slerp_get_turn_for_phase_fp64(const BgcSlerpFP64* slerp, const double phase, BgcVersorFP64* result) +{ + const double angle = slerp->radians * phase; + const double cosine = cos(angle); + const double sine = sin(angle); + + bgc_versor_set_values_fp64( + slerp->s0_cos_weight * cosine + slerp->s0_sin_weight * sine, + slerp->x1_cos_weight * cosine + slerp->x1_sin_weight * sine, + slerp->x2_cos_weight * cosine + slerp->x2_sin_weight * sine, + slerp->x3_cos_weight * cosine + slerp->x3_sin_weight * sine, + result + ); +} + +#endif diff --git a/basic-geometry/utilities.h b/basic-geometry/utilities.h index 09d4866..4c4d3cb 100644 --- a/basic-geometry/utilities.h +++ b/basic-geometry/utilities.h @@ -11,6 +11,8 @@ #define BGC_ONE_SEVENTH_FP32 0.142857142857f #define BGC_ONE_NINETH_FP32 0.1111111111f +#define BGC_ARCCOSINE_PRECISION_LIMIT_FP32 0.70711f + #define BGC_GOLDEN_RATIO_HIGH_FP32 1.618034f #define BGC_GOLDEN_RATIO_LOW_FP32 0.618034f diff --git a/basic-geometry/vector2.c b/basic-geometry/vector2.c index b0b7c64..637de61 100644 --- a/basic-geometry/vector2.c +++ b/basic-geometry/vector2.c @@ -57,8 +57,8 @@ extern inline void bgc_vector2_get_mean_of_two_fp64(const BgcVector2FP64* vector extern inline void bgc_vector2_get_mean_of_three_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const BgcVector2FP32* vector3, BgcVector2FP32* mean); extern inline void bgc_vector2_get_mean_of_three_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const BgcVector2FP64* vector3, BgcVector2FP64* mean); -extern inline void bgc_vector2_get_linear_interpolation_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const float phase, BgcVector2FP32* interpolation); -extern inline void bgc_vector2_get_linear_interpolation_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const double phase, BgcVector2FP64* interpolation); +extern inline void bgc_vector2_interpolate_linearly_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const float phase, BgcVector2FP32* interpolation); +extern inline void bgc_vector2_interpolate_linearly_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const double phase, BgcVector2FP64* interpolation); extern inline void bgc_vector2_minimize_fp32(const BgcVector2FP32* vector, BgcVector2FP32* minimal); extern inline void bgc_vector2_minimize_fp64(const BgcVector2FP64* vector, BgcVector2FP64* minimal); @@ -90,52 +90,44 @@ float bgc_vector2_get_angle_fp32(const BgcVector2FP32* vector1, const BgcVector2 { const float square_modulus1 = bgc_vector2_get_square_modulus_fp32(vector1); - if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP32) { + // square_modulus1 != square_modulus1 is check for NaN value at square_modulus1 + if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP32 || square_modulus1 != square_modulus1) { return 0.0f; } const float square_modulus2 = bgc_vector2_get_square_modulus_fp32(vector2); - if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP32) { + // square_modulus2 != square_modulus2 is check for NaN value at square_modulus2 + if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP32 || square_modulus2 != square_modulus2) { return 0.0f; } - const float cosine = bgc_vector2_get_scalar_product_fp32(vector1, vector2) / sqrtf(square_modulus1 * square_modulus2); + const float scalar = bgc_vector2_get_scalar_product_fp32(vector1, vector2); - if (cosine >= 1.0f - BGC_EPSYLON_FP32) { - return 0.0f; - } + const float cross = bgc_vector2_get_cross_product_fp32(vector1, vector2); - if (cosine <= -1.0f + BGC_EPSYLON_FP32) { - return bgc_angle_get_half_circle_fp32(unit); - } - - return bgc_radians_to_units_fp32(acosf(cosine), unit); + return bgc_radians_to_units_fp32(atan2f(cross >= 0 ? cross : -cross, scalar), unit); } double bgc_vector2_get_angle_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const BgcAngleUnitEnum unit) { const double square_modulus1 = bgc_vector2_get_square_modulus_fp64(vector1); - if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP64) { + // square_modulus1 != square_modulus1 is check for NaN value at square_modulus1 + if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP64 || square_modulus1 != square_modulus1) { return 0.0; } const double square_modulus2 = bgc_vector2_get_square_modulus_fp64(vector2); - if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP64) { + // square_modulus2 != square_modulus2 is check for NaN value at square_modulus2 + if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP64 || square_modulus2 != square_modulus2) { return 0.0; } - const double cosine = bgc_vector2_get_scalar_product_fp64(vector1, vector2) / sqrt(square_modulus1 * square_modulus2); + const double scalar = bgc_vector2_get_scalar_product_fp64(vector1, vector2); - if (cosine >= 1.0 - BGC_EPSYLON_FP64) { - return 0.0; - } + const double cross = bgc_vector2_get_cross_product_fp64(vector1, vector2); - if (cosine <= -1.0 + BGC_EPSYLON_FP64) { - return bgc_angle_get_half_circle_fp64(unit); - } - - return bgc_radians_to_units_fp64(acos(cosine), unit); + return bgc_radians_to_units_fp64(atan2(cross >= 0 ? cross : -cross, scalar), unit); } diff --git a/basic-geometry/vector2.h b/basic-geometry/vector2.h index 8852721..1effc5e 100644 --- a/basic-geometry/vector2.h +++ b/basic-geometry/vector2.h @@ -314,7 +314,7 @@ inline void bgc_vector2_get_mean_of_three_fp64(const BgcVector2FP64* vector1, co // =================== Linear =================== // -inline void bgc_vector2_get_linear_interpolation_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const float phase, BgcVector2FP32* interpolation) +inline void bgc_vector2_interpolate_linearly_fp32(const BgcVector2FP32* vector1, const BgcVector2FP32* vector2, const float phase, BgcVector2FP32* interpolation) { const float counterphase = 1.0f - phase; @@ -322,7 +322,7 @@ inline void bgc_vector2_get_linear_interpolation_fp32(const BgcVector2FP32* vect interpolation->x2 = vector1->x2 * counterphase + vector2->x2 * phase; } -inline void bgc_vector2_get_linear_interpolation_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const double phase, BgcVector2FP64* interpolation) +inline void bgc_vector2_interpolate_linearly_fp64(const BgcVector2FP64* vector1, const BgcVector2FP64* vector2, const double phase, BgcVector2FP64* interpolation) { const double counterphase = 1.0 - phase; diff --git a/basic-geometry/vector3.c b/basic-geometry/vector3.c index e15ac8d..8c269ed 100644 --- a/basic-geometry/vector3.c +++ b/basic-geometry/vector3.c @@ -57,8 +57,8 @@ extern inline void bgc_vector3_get_mean_of_two_fp64(const BgcVector3FP64* vector extern inline void bgc_vector3_get_mean_of_three_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, const BgcVector3FP32* vector3, BgcVector3FP32* result); extern inline void bgc_vector3_get_mean_of_three_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const BgcVector3FP64* vector3, BgcVector3FP64* result); -extern inline void bgc_vector3_get_linear_interpolation_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, const float phase, BgcVector3FP32* interpolation); -extern inline void bgc_vector3_get_linear_interpolation_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const double phase, BgcVector3FP64* interpolation); +extern inline void bgc_vector3_interpolate_linearly_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, const float phase, BgcVector3FP32* interpolation); +extern inline void bgc_vector3_interpolate_linearly_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const double phase, BgcVector3FP64* interpolation); extern inline void bgc_vector3_minimize_fp32(const BgcVector3FP32* vector, BgcVector3FP32* minimal); extern inline void bgc_vector3_minimize_fp64(const BgcVector3FP64* vector, BgcVector3FP64* minimal); @@ -96,52 +96,52 @@ float bgc_vector3_get_angle_fp32(const BgcVector3FP32* vector1, const BgcVector3 { const float square_modulus1 = bgc_vector3_get_square_modulus_fp32(vector1); - if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP32) { + // square_modulus1 != square_modulus1 is check for NaN value at square_modulus1 + if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP32 || square_modulus1 != square_modulus1) { return 0.0f; } const float square_modulus2 = bgc_vector3_get_square_modulus_fp32(vector2); - if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP32) { + // square_modulus2 != square_modulus2 is check for NaN value at square_modulus2 + if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP32 || square_modulus2 != square_modulus2) { return 0.0f; } - const float cosine = bgc_vector3_get_scalar_product_fp32(vector1, vector2) / sqrtf(square_modulus1 * square_modulus2); + BgcVector3FP32 cross_product; - if (cosine >= 1.0f - BGC_EPSYLON_FP32) { - return 0.0f; - } + bgc_vector3_get_cross_product_fp32(vector1, vector2, &cross_product); - if (cosine <= -1.0f + BGC_EPSYLON_FP32) { - return bgc_angle_get_half_circle_fp32(unit); - } + const float scalar = bgc_vector3_get_scalar_product_fp32(vector1, vector2); - return bgc_radians_to_units_fp32(acosf(cosine), unit); + const float cross = bgc_vector3_get_modulus_fp32(&cross_product); + + return bgc_radians_to_units_fp32(atan2f(cross, scalar), unit); } double bgc_vector3_get_angle_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const BgcAngleUnitEnum unit) { const double square_modulus1 = bgc_vector3_get_square_modulus_fp64(vector1); - if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP64) { + // square_modulus1 != square_modulus1 is check for NaN value at square_modulus1 + if (square_modulus1 <= BGC_SQUARE_EPSYLON_FP64 || square_modulus1 != square_modulus1) { return 0.0; } const double square_modulus2 = bgc_vector3_get_square_modulus_fp64(vector2); - if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP64) { + // square_modulus2 != square_modulus2 is check for NaN value at square_modulus2 + if (square_modulus2 <= BGC_SQUARE_EPSYLON_FP64 || square_modulus2 != square_modulus2) { return 0.0; } - const double cosine = bgc_vector3_get_scalar_product_fp64(vector1, vector2) / sqrt(square_modulus1 * square_modulus2); + BgcVector3FP64 cross_product; - if (cosine >= 1.0 - BGC_EPSYLON_FP64) { - return 0.0; - } + bgc_vector3_get_cross_product_fp64(vector1, vector2, &cross_product); - if (cosine <= -1.0 + BGC_EPSYLON_FP64) { - return bgc_angle_get_half_circle_fp64(unit); - } + const double scalar = bgc_vector3_get_scalar_product_fp64(vector1, vector2); - return bgc_radians_to_units_fp64(acos(cosine), unit); + const double cross = bgc_vector3_get_modulus_fp64(&cross_product); + + return bgc_radians_to_units_fp64(atan2(cross, scalar), unit); } diff --git a/basic-geometry/vector3.h b/basic-geometry/vector3.h index 33451fe..52fe86c 100644 --- a/basic-geometry/vector3.h +++ b/basic-geometry/vector3.h @@ -350,7 +350,7 @@ inline void bgc_vector3_get_mean_of_three_fp64(const BgcVector3FP64* vector1, co // =================== Linear =================== // -inline void bgc_vector3_get_linear_interpolation_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, const float phase, BgcVector3FP32* interpolation) +inline void bgc_vector3_interpolate_linearly_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, const float phase, BgcVector3FP32* interpolation) { const float counterphase = 1.0f - phase; @@ -359,7 +359,7 @@ inline void bgc_vector3_get_linear_interpolation_fp32(const BgcVector3FP32* vect interpolation->x3 = vector1->x3 * counterphase + vector2->x3 * phase; } -inline void bgc_vector3_get_linear_interpolation_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const double phase, BgcVector3FP64* interpolation) +inline void bgc_vector3_interpolate_linearly_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, const double phase, BgcVector3FP64* interpolation) { const double counterphase = 1.0 - phase; diff --git a/basic-geometry/versor.c b/basic-geometry/versor.c index 8405012..842fc40 100644 --- a/basic-geometry/versor.c +++ b/basic-geometry/versor.c @@ -81,7 +81,6 @@ void _bgc_versor_normalize_fp32(const float square_modulus, _BgcDarkTwinVersorFP twin->x1 *= multiplier; twin->x2 *= multiplier; twin->x3 *= multiplier; - } void _bgc_versor_normalize_fp64(const double square_modulus, _BgcDarkTwinVersorFP64* twin) @@ -152,54 +151,22 @@ void bgc_versor_set_turn_fp64(const double x1, const double x2, const double x3, bgc_versor_set_values_fp64(cos(half_angle), x1 * multiplier, x2 * multiplier, x3 * multiplier, result); } -// ================ Get Rotation ================ // - -void bgc_versor_get_rotation_fp32(const BgcVersorFP32* versor, BgcRotation3FP32* result) -{ - if (versor->s0 <= -(1.0f - BGC_EPSYLON_FP32) || 1.0f - BGC_EPSYLON_FP32 <= versor->s0) { - bgc_rotation3_reset_fp32(result); - return; - } - - const float multiplier = sqrtf(1.0f / (versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3)); - - result->radians = 2.0f * acosf(versor->s0); - - result->axis.x1 = versor->x1 * multiplier; - result->axis.x2 = versor->x2 * multiplier; - result->axis.x3 = versor->x3 * multiplier; -} - -void bgc_versor_get_rotation_fp64(const BgcVersorFP64* versor, BgcRotation3FP64* result) -{ - if (versor->s0 <= -(1.0 - BGC_EPSYLON_FP64) || 1.0 - BGC_EPSYLON_FP64 <= versor->s0) { - bgc_rotation3_reset_fp64(result); - return; - } - - const double multiplier = sqrt(1.0 / (versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3)); - - result->radians = 2.0 * acos(versor->s0); - - result->axis.x1 = versor->x1 * multiplier; - result->axis.x2 = versor->x2 * multiplier; - result->axis.x3 = versor->x3 * multiplier; -} - // =============== Get Exponation =============== // void bgc_versor_get_exponation_fp32(const BgcVersorFP32* base, const float exponent, BgcVersorFP32* power) { const float square_vector = base->x1 * base->x1 + base->x2 * base->x2 + base->x3 * base->x3; - if (square_vector <= BGC_SQUARE_EPSYLON_FP32) { + if (square_vector <= BGC_SQUARE_EPSYLON_FP32 || square_vector != square_vector) { bgc_versor_reset_fp32(power); return; } - const float angle = acosf(base->s0) * exponent; + const float vector_modulus = sqrtf(square_vector); - const float multiplier = sinf(angle) / sqrtf(square_vector); + const float angle = atan2f(vector_modulus, base->s0) * exponent; + + const float multiplier = sinf(angle) / vector_modulus; bgc_versor_set_values_fp32(cosf(angle), base->x1 * multiplier, base->x2 * multiplier, base->x3 * multiplier, power); } @@ -208,14 +175,130 @@ void bgc_versor_get_exponation_fp64(const BgcVersorFP64* base, const double expo { const double square_vector = base->x1 * base->x1 + base->x2 * base->x2 + base->x3 * base->x3; - if (square_vector <= BGC_SQUARE_EPSYLON_FP64) { + if (square_vector <= BGC_SQUARE_EPSYLON_FP64 || square_vector != square_vector) { bgc_versor_reset_fp64(power); return; } - const double angle = acos(base->s0) * exponent; + const double vector_modulus = sqrt(square_vector); - const double multiplier = sin(angle) / sqrt(square_vector); + const double angle = atan2(vector_modulus, base->s0) * exponent; + + const double multiplier = sin(angle) / vector_modulus; bgc_versor_set_values_fp64(cos(angle), base->x1 * multiplier, base->x2 * multiplier, base->x3 * multiplier, power); } + +// ============ Sphere Interpolation ============ // + +void bgc_versor_spherically_interpolate_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, const float phase, BgcVersorFP32* 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_SQUARE_EPSYLON_FP32 || square_vector != square_vector) { + bgc_versor_copy_fp32(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_versor_set_values_fp32( + (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_versor_spherically_interpolate_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, const double phase, BgcVersorFP64* 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_SQUARE_EPSYLON_FP64 || square_vector != square_vector) { + bgc_versor_copy_fp64(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_versor_set_values_fp64( + (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_versor_get_rotation_fp32(const BgcVersorFP32* versor, BgcRotation3FP32* result) +{ + const float square_modulus = versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3; + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + bgc_rotation3_reset_fp32(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_versor_get_rotation_fp64(const BgcVersorFP64* versor, BgcRotation3FP64* result) +{ + const double square_modulus = versor->x1 * versor->x1 + versor->x2 * versor->x2 + versor->x3 * versor->x3; + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + bgc_rotation3_reset_fp64(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; +} diff --git a/basic-geometry/versor.h b/basic-geometry/versor.h index 6240b0f..c516c8d 100644 --- a/basic-geometry/versor.h +++ b/basic-geometry/versor.h @@ -223,14 +223,14 @@ inline void bgc_versor_shorten_fp32(const BgcVersorFP32* versor, BgcVersorFP32* _BgcDarkTwinVersorFP32* twin = (_BgcDarkTwinVersorFP32*)shortened; if (versor->s0 >= 0.0f) { - twin->x1 = versor->s0; + twin->s0 = versor->s0; twin->x1 = versor->x1; twin->x2 = versor->x2; twin->x3 = versor->x3; return; } - twin->x1 = -versor->s0; + twin->s0 = -versor->s0; twin->x1 = -versor->x1; twin->x2 = -versor->x2; twin->x3 = -versor->x3; @@ -241,14 +241,14 @@ inline void bgc_versor_shorten_fp64(const BgcVersorFP64* versor, BgcVersorFP64* _BgcDarkTwinVersorFP64* twin = (_BgcDarkTwinVersorFP64*)shortened; if (versor->s0 >= 0.0) { - twin->x1 = versor->s0; + twin->s0 = versor->s0; twin->x1 = versor->x1; twin->x2 = versor->x2; twin->x3 = versor->x3; return; } - twin->x1 = -versor->s0; + twin->s0 = -versor->s0; twin->x1 = -versor->x1; twin->x2 = -versor->x2; twin->x3 = -versor->x3; @@ -362,6 +362,12 @@ inline void bgc_versor_exclude_fp64(const BgcVersorFP64* base, const BgcVersorFP ); } +// ============ Sphere Interpolation ============ // + +void bgc_versor_spherically_interpolate_fp32(const BgcVersorFP32* start, const BgcVersorFP32* end, const float phase, BgcVersorFP32* result); + +void bgc_versor_spherically_interpolate_fp64(const BgcVersorFP64* start, const BgcVersorFP64* end, const double phase, BgcVersorFP64* result); + // ================ Get Rotation ================ // void bgc_versor_get_rotation_fp32(const BgcVersorFP32* versor, BgcRotation3FP32* result); From e6a94ab8d911cc1b526f69532b6424067240e534 Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Fri, 21 Mar 2025 03:34:20 +0700 Subject: [PATCH 09/10] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B1=D0=B0=D0=B7=D0=B8=D1=81=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=B0=D0=BA=20=D0=B2=D1=81=D0=BF=D0=BE=D0=BC?= =?UTF-8?q?=D0=BE=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry/basic-geometry.vcxproj | 2 + basic-geometry/basic-geometry.vcxproj.filters | 6 + basic-geometry/basis3.c | 232 ++++++++++++++++++ basic-geometry/basis3.h | 35 +++ basic-geometry/rotation3.h | 16 +- basic-geometry/utilities.c | 1 + basic-geometry/utilities.h | 14 ++ basic-geometry/vector3.c | 7 +- basic-geometry/vector3.h | 46 +++- 9 files changed, 345 insertions(+), 14 deletions(-) create mode 100644 basic-geometry/basis3.c create mode 100644 basic-geometry/basis3.h diff --git a/basic-geometry/basic-geometry.vcxproj b/basic-geometry/basic-geometry.vcxproj index 3614dc7..b8039b9 100644 --- a/basic-geometry/basic-geometry.vcxproj +++ b/basic-geometry/basic-geometry.vcxproj @@ -21,6 +21,7 @@ + @@ -40,6 +41,7 @@ + diff --git a/basic-geometry/basic-geometry.vcxproj.filters b/basic-geometry/basic-geometry.vcxproj.filters index 440dcb1..fb935d0 100644 --- a/basic-geometry/basic-geometry.vcxproj.filters +++ b/basic-geometry/basic-geometry.vcxproj.filters @@ -69,6 +69,9 @@ Файлы заголовков + + Файлы заголовков + @@ -110,5 +113,8 @@ Исходные файлы + + Исходные файлы + \ No newline at end of file diff --git a/basic-geometry/basis3.c b/basic-geometry/basis3.c new file mode 100644 index 0000000..566c909 --- /dev/null +++ b/basic-geometry/basis3.c @@ -0,0 +1,232 @@ +#include +#include "./basis3.h" + +typedef struct { + int e1, e2, e3; +} _BgcBasis3State; + +static inline void _bgc_basis3_state_reset(_BgcBasis3State* state) +{ + state->e1 = 0; + state->e2 = 0; + state->e3 = 0; +} + +static inline int _bgc_basis3_validate_directions(const int primary_direction, const int auxiliary_direction) +{ + if (!bgc_is_correct_direction(primary_direction)) { + return BGC_ERROR_BASIS3_PRIMARY_DIRECTION_UNKNOWN; + } + + if (!bgc_is_correct_direction(auxiliary_direction)) { + return BGC_ERROR_BASIS3_AUXILIARY_DIRECTION_UNKNOWN; + } + + if (primary_direction == auxiliary_direction || primary_direction == -auxiliary_direction) { + return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; + } + + return BGC_SUCCESS; +} + +static inline void _bgc_basis3_load_axis_fp32(const int direction, const BgcVector3FP32* axis, _BgcBasis3State* state, BgcBasis3FP32* basis) +{ + switch (direction) { + case BGC_DIRECTION_X1: + bgc_vector3_copy_fp32(axis, &basis->e1); + state->e1 = 1; + break; + + case -BGC_DIRECTION_X1: + bgc_vector3_reverse_fp32(axis, &basis->e1); + state->e1 = 1; + break; + + case BGC_DIRECTION_X2: + bgc_vector3_copy_fp32(axis, &basis->e2); + state->e2 = 1; + break; + + case -BGC_DIRECTION_X2: + bgc_vector3_reverse_fp32(axis, &basis->e2); + state->e2 = 1; + break; + + case BGC_DIRECTION_X3: + bgc_vector3_copy_fp32(axis, &basis->e3); + state->e3 = 1; + break; + + case -BGC_DIRECTION_X3: + bgc_vector3_reverse_fp32(axis, &basis->e3); + state->e3 = 1; + break; + } +} + +int bgc_basis3_make_from_directions_fp32( + const int primary_direction, const BgcVector3FP32* primary_vector, + const int auxiliary_direction, const BgcVector3FP32* auxiliary_vector, + BgcBasis3FP32* basis +) { + const int direstion_validation_code = _bgc_basis3_validate_directions(primary_direction, auxiliary_direction); + + if (direstion_validation_code != BGC_SUCCESS) { + return direstion_validation_code; + } + + const float primary_square_modulus = bgc_vector3_get_square_modulus_fp32(primary_vector); + + if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + return BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO; + } + + const float auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp32(auxiliary_vector); + + if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + return BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO; + } + + BgcVector3FP32 orthogonal; + + bgc_vector3_get_cross_product_fp32(primary_vector, auxiliary_vector, &orthogonal); + + const float orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp32(&orthogonal); + + if (orthogonal_square_modulus <= BGC_SQUARE_EPSYLON_FP32 * primary_square_modulus * auxiliary_square_modulus) { + return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; + } + + BgcVector3FP32 primary_axis, auxiliary_axis; + + bgc_vector3_multiply_fp32(primary_vector, sqrtf(1.0f / primary_square_modulus), &primary_axis); + + bgc_vector3_subtract_scaled_fp32(auxiliary_vector, &primary_axis, bgc_vector3_get_scalar_product_fp32(auxiliary_vector, &primary_axis), &auxiliary_axis); + + bgc_vector3_multiply_fp32(&auxiliary_axis, sqrtf(1.0f / bgc_vector3_get_square_modulus_fp32(&auxiliary_axis)), &auxiliary_axis); + + _BgcBasis3State state; + + _bgc_basis3_state_reset(&state); + + _bgc_basis3_load_axis_fp32(primary_direction, &primary_axis, &state, basis); + _bgc_basis3_load_axis_fp32(auxiliary_direction, &auxiliary_axis, &state, basis); + + if (!state.e1) { + bgc_vector3_get_cross_product_fp32(&basis->e2, &basis->e3, &basis->e1); + bgc_vector3_normalize_fp32(&basis->e1); + return BGC_SUCCESS; + } + + if (!state.e2) { + bgc_vector3_get_cross_product_fp32(&basis->e3, &basis->e1, &basis->e2); + bgc_vector3_normalize_fp32(&basis->e2); + return BGC_SUCCESS; + } + + bgc_vector3_get_cross_product_fp32(&basis->e1, &basis->e2, &basis->e3); + bgc_vector3_normalize_fp32(&basis->e3); + + return BGC_SUCCESS; +} + +static inline void _bgc_basis3_load_axis_fp64(const int direction, const BgcVector3FP64* axis, _BgcBasis3State* state, BgcBasis3FP64* basis) +{ + switch (direction) { + case BGC_DIRECTION_X1: + bgc_vector3_copy_fp64(axis, &basis->e1); + state->e1 = 1; + break; + + case -BGC_DIRECTION_X1: + bgc_vector3_reverse_fp64(axis, &basis->e1); + state->e1 = 1; + break; + + case BGC_DIRECTION_X2: + bgc_vector3_copy_fp64(axis, &basis->e2); + state->e2 = 1; + break; + + case -BGC_DIRECTION_X2: + bgc_vector3_reverse_fp64(axis, &basis->e2); + state->e2 = 1; + break; + + case BGC_DIRECTION_X3: + bgc_vector3_copy_fp64(axis, &basis->e3); + state->e3 = 1; + break; + + case -BGC_DIRECTION_X3: + bgc_vector3_reverse_fp64(axis, &basis->e3); + state->e3 = 1; + break; + } +} + +int bgc_basis3_make_from_directions_fp64( + const int primary_direction, const BgcVector3FP64* primary_vector, + const int auxiliary_direction, const BgcVector3FP64* auxiliary_vector, + BgcBasis3FP64* basis +) { + const int direstion_validation_code = _bgc_basis3_validate_directions(primary_direction, auxiliary_direction); + + if (direstion_validation_code != BGC_SUCCESS) { + return direstion_validation_code; + } + + const double primary_square_modulus = bgc_vector3_get_square_modulus_fp64(primary_vector); + + if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + return BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO; + } + + const double auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp64(auxiliary_vector); + + if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + return BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO; + } + + BgcVector3FP64 orthogonal; + + bgc_vector3_get_cross_product_fp64(primary_vector, auxiliary_vector, &orthogonal); + + const double orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp64(&orthogonal); + + if (orthogonal_square_modulus <= BGC_SQUARE_EPSYLON_FP64 * primary_square_modulus * auxiliary_square_modulus) { + return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; + } + + BgcVector3FP64 primary_axis, auxiliary_axis; + + bgc_vector3_multiply_fp64(primary_vector, sqrt(1.0 / primary_square_modulus), &primary_axis); + + bgc_vector3_subtract_scaled_fp64(auxiliary_vector, &primary_axis, bgc_vector3_get_scalar_product_fp64(auxiliary_vector, &primary_axis), &auxiliary_axis); + + bgc_vector3_multiply_fp64(&auxiliary_axis, sqrt(1.0 / bgc_vector3_get_square_modulus_fp64(&auxiliary_axis)), &auxiliary_axis); + + _BgcBasis3State state; + + _bgc_basis3_state_reset(&state); + + _bgc_basis3_load_axis_fp64(primary_direction, &primary_axis, &state, basis); + _bgc_basis3_load_axis_fp64(auxiliary_direction, &auxiliary_axis, &state, basis); + + if (!state.e1) { + bgc_vector3_get_cross_product_fp64(&basis->e2, &basis->e3, &basis->e1); + bgc_vector3_normalize_fp64(&basis->e1); + return BGC_SUCCESS; + } + + if (!state.e2) { + bgc_vector3_get_cross_product_fp64(&basis->e3, &basis->e1, &basis->e2); + bgc_vector3_normalize_fp64(&basis->e2); + return BGC_SUCCESS; + } + + bgc_vector3_get_cross_product_fp64(&basis->e1, &basis->e2, &basis->e3); + bgc_vector3_normalize_fp64(&basis->e3); + + return BGC_SUCCESS; +} diff --git a/basic-geometry/basis3.h b/basic-geometry/basis3.h new file mode 100644 index 0000000..b1b995d --- /dev/null +++ b/basic-geometry/basis3.h @@ -0,0 +1,35 @@ +#ifndef _BGC_BASIS3_H_ +#define _BGC_BASIS3_H_ + +#include "./vector3.h" + +#define BGC_ERROR_BASIS3_PRIMARY_DIRECTION_UNKNOWN -3001 +#define BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO -3002 + +#define BGC_ERROR_BASIS3_AUXILIARY_DIRECTION_UNKNOWN -3011 +#define BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO -3012 + +#define BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL -3021 + + +typedef struct { + BgcVector3FP32 e1, e2, e3; +} BgcBasis3FP32; + +typedef struct { + BgcVector3FP64 e1, e2, e3; +} BgcBasis3FP64; + +int bgc_basis3_make_from_directions_fp32( + const int primary_direction, const BgcVector3FP32* primary_vector, + const int auxiliary_direction, const BgcVector3FP32* auxiliary_vector, + BgcBasis3FP32* basis +); + +int bgc_basis3_make_from_directions_fp64( + const int primary_direction, const BgcVector3FP64* primary_vector, + const int auxiliary_direction, const BgcVector3FP64* auxiliary_vector, + BgcBasis3FP64* basis +); + +#endif diff --git a/basic-geometry/rotation3.h b/basic-geometry/rotation3.h index 3ba45d1..d55cdc3 100644 --- a/basic-geometry/rotation3.h +++ b/basic-geometry/rotation3.h @@ -47,7 +47,7 @@ inline void bgc_rotation3_set_values_fp32(const float x1, const float x2, const rotation->axis.x2 = x2; rotation->axis.x3 = x3; - if (bgc_vector3_normalize_fp32(&rotation->axis, &rotation->axis)) { + if (bgc_vector3_normalize_fp32(&rotation->axis)) { rotation->radians = bgc_angle_to_radians_fp32(angle, unit); } else { @@ -62,7 +62,7 @@ inline void bgc_rotation3_set_values_fp64(const double x1, const double x2, cons rotation->axis.x2 = x2; rotation->axis.x3 = x3; - if (bgc_vector3_normalize_fp64(&rotation->axis, &rotation->axis)) { + if (bgc_vector3_normalize_fp64(&rotation->axis)) { rotation->radians = bgc_angle_to_radians_fp64(angle, unit); } else { @@ -72,11 +72,9 @@ inline void bgc_rotation3_set_values_fp64(const double x1, const double x2, cons inline void bgc_rotation3_set_with_axis_fp32(const BgcVector3FP32* axis, const float angle, const BgcAngleUnitEnum unit, BgcRotation3FP32* rotation) { - rotation->axis.x1 = axis->x1; - rotation->axis.x2 = axis->x2; - rotation->axis.x3 = axis->x3; + bgc_vector3_copy_fp32(axis, &rotation->axis); - if (bgc_vector3_normalize_fp32(&rotation->axis, &rotation->axis)) { + if (bgc_vector3_normalize_fp32(&rotation->axis)) { rotation->radians = bgc_angle_to_radians_fp32(angle, unit); } else { @@ -86,11 +84,9 @@ inline void bgc_rotation3_set_with_axis_fp32(const BgcVector3FP32* axis, const f inline void bgc_rotation3_set_with_axis_fp64(const BgcVector3FP64* axis, const double angle, const BgcAngleUnitEnum unit, BgcRotation3FP64* rotation) { - rotation->axis.x1 = axis->x1; - rotation->axis.x2 = axis->x2; - rotation->axis.x3 = axis->x3; + bgc_vector3_copy_fp64(axis, &rotation->axis); - if (bgc_vector3_normalize_fp64(&rotation->axis, &rotation->axis)) { + if (bgc_vector3_normalize_fp64(&rotation->axis)) { rotation->radians = bgc_angle_to_radians_fp64(angle, unit); } else { diff --git a/basic-geometry/utilities.c b/basic-geometry/utilities.c index e863c4b..ec89f4f 100644 --- a/basic-geometry/utilities.c +++ b/basic-geometry/utilities.c @@ -1,5 +1,6 @@ #include "utilities.h" +extern inline int bgc_is_correct_direction(const int direction); extern inline int bgc_is_zero_fp32(const float square_value); extern inline int bgc_is_zero_fp64(const double square_value); diff --git a/basic-geometry/utilities.h b/basic-geometry/utilities.h index 4c4d3cb..d12b091 100644 --- a/basic-geometry/utilities.h +++ b/basic-geometry/utilities.h @@ -29,6 +29,20 @@ #define BGC_GOLDEN_RATIO_HIGH_FP64 1.61803398874989485 #define BGC_GOLDEN_RATIO_LOW_FP64 0.61803398874989485 +#define BGC_SUCCESS 0 +#define BGC_FAILED -1 + +#define BGC_DIRECTION_X1 1 +#define BGC_DIRECTION_X2 2 +#define BGC_DIRECTION_X3 3 + +inline int bgc_is_correct_direction(const int direction) +{ + return direction == BGC_DIRECTION_X1 || direction == -BGC_DIRECTION_X1 + || direction == BGC_DIRECTION_X2 || direction == -BGC_DIRECTION_X2 + || direction == BGC_DIRECTION_X3 || direction == -BGC_DIRECTION_X3; +} + inline int bgc_is_zero_fp32(const float value) { return (-BGC_EPSYLON_FP32 <= value) && (value <= BGC_EPSYLON_FP32); diff --git a/basic-geometry/vector3.c b/basic-geometry/vector3.c index 8c269ed..9b97d80 100644 --- a/basic-geometry/vector3.c +++ b/basic-geometry/vector3.c @@ -30,8 +30,11 @@ extern inline void bgc_vector3_swap_fp64(BgcVector3FP64* vector1, BgcVector3FP64 extern inline void bgc_vector3_reverse_fp32(const BgcVector3FP32* vector, BgcVector3FP32* reverse); extern inline void bgc_vector3_reverse_fp64(const BgcVector3FP64* vector, BgcVector3FP64* reverse); -extern inline int bgc_vector3_normalize_fp32(const BgcVector3FP32* vector, BgcVector3FP32* normalized); -extern inline int bgc_vector3_normalize_fp64(const BgcVector3FP64* vector, BgcVector3FP64* normalized); +extern inline int bgc_vector3_normalize_fp32(BgcVector3FP32* vector); +extern inline int bgc_vector3_normalize_fp64(BgcVector3FP64* vector); + +extern inline int bgc_vector3_get_normalized_fp32(const BgcVector3FP32* vector, BgcVector3FP32* normalized); +extern inline int bgc_vector3_get_normalized_fp64(const BgcVector3FP64* vector, BgcVector3FP64* normalized); extern inline void bgc_vector3_add_fp32(const BgcVector3FP32* vector1, const BgcVector3FP32* vector2, BgcVector3FP32* sum); extern inline void bgc_vector3_add_fp64(const BgcVector3FP64* vector1, const BgcVector3FP64* vector2, BgcVector3FP64* sum); diff --git a/basic-geometry/vector3.h b/basic-geometry/vector3.h index 52fe86c..33f846e 100644 --- a/basic-geometry/vector3.h +++ b/basic-geometry/vector3.h @@ -176,7 +176,49 @@ inline void bgc_vector3_reverse_fp64(const BgcVector3FP64* vector, BgcVector3FP6 // ================= Normalize ================== // -inline int bgc_vector3_normalize_fp32(const BgcVector3FP32* vector, BgcVector3FP32* normalized) +inline int bgc_vector3_normalize_fp32(BgcVector3FP32* vector) +{ + const float square_modulus = bgc_vector3_get_square_modulus_fp32(vector); + + if (bgc_is_sqare_unit_fp32(square_modulus)) { + return 1; + } + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP32 || square_modulus != square_modulus) { + return 0; + } + + const float multiplicand = sqrtf(1.0f / square_modulus); + + vector->x1 *= multiplicand; + vector->x2 *= multiplicand; + vector->x3 *= multiplicand; + + return 1; +} + +inline int bgc_vector3_normalize_fp64(BgcVector3FP64* vector) +{ + const double square_modulus = bgc_vector3_get_square_modulus_fp64(vector); + + if (bgc_is_sqare_unit_fp64(square_modulus)) { + return 1; + } + + if (square_modulus <= BGC_SQUARE_EPSYLON_FP64 || square_modulus != square_modulus) { + return 0; + } + + const double multiplicand = sqrt(1.0 / square_modulus); + + vector->x1 *= multiplicand; + vector->x2 *= multiplicand; + vector->x3 *= multiplicand; + + return 1; +} + +inline int bgc_vector3_get_normalized_fp32(const BgcVector3FP32* vector, BgcVector3FP32* normalized) { const float square_modulus = bgc_vector3_get_square_modulus_fp32(vector); @@ -200,7 +242,7 @@ inline int bgc_vector3_normalize_fp32(const BgcVector3FP32* vector, BgcVector3FP return 1; } -inline int bgc_vector3_normalize_fp64(const BgcVector3FP64* vector, BgcVector3FP64* normalized) +inline int bgc_vector3_get_normalized_fp64(const BgcVector3FP64* vector, BgcVector3FP64* normalized) { const double square_modulus = bgc_vector3_get_square_modulus_fp64(vector); From 2a4d5522d32ff88cf2c66a257022041d518638db Mon Sep 17 00:00:00 2001 From: Andrey Pokidov Date: Wed, 4 Jun 2025 23:47:55 +0700 Subject: [PATCH 10/10] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20(versor)=20=D0=BC=D0=B5=D0=B6=D0=B4=D1=83=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=B8=20=D0=B1=D0=B0=D0=B7=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic-geometry-dev/main.c | 336 +++++++++++++++++- basic-geometry/basic-geometry.vcxproj | 2 - basic-geometry/basic-geometry.vcxproj.filters | 6 - basic-geometry/basis3.c | 232 ------------ basic-geometry/basis3.h | 35 -- basic-geometry/utilities.h | 4 +- basic-geometry/vector2.c | 3 + basic-geometry/vector2.h | 56 +++ basic-geometry/vector3.c | 3 + basic-geometry/vector3.h | 88 +++++ basic-geometry/versor.c | 268 ++++++++++++++ basic-geometry/versor.h | 38 ++ 12 files changed, 784 insertions(+), 287 deletions(-) delete mode 100644 basic-geometry/basis3.c delete mode 100644 basic-geometry/basis3.h diff --git a/basic-geometry-dev/main.c b/basic-geometry-dev/main.c index 6dcf2ae..d65ef54 100644 --- a/basic-geometry-dev/main.c +++ b/basic-geometry-dev/main.c @@ -53,12 +53,12 @@ structure_fp32_t* make_structures(const unsigned int amount) void print_versor_fp32(const BgcVersorFP32* versor) { - printf("Versor (%f, %f, %f, %f)\n", versor->s0, versor->x1, versor->x2, versor->x3); + printf("Versor (s0 = %0.12f, x1 = %0.12f, x2 = %0.12f, x3 = %0.12f)\n", versor->s0, versor->x1, versor->x2, versor->x3); } void print_versor_fp64(const BgcVersorFP64* versor) { - printf("Versor (%lf, %lf, %lf, %lf)\n", versor->s0, versor->x1, versor->x2, versor->x3); + printf("Versor (s0 = %0.20f, x1 = %0.20f, x2 = %0.20f, x3 = %0.20f)\n", versor->s0, versor->x1, versor->x2, versor->x3); } void print_vector_fp32(const BgcVector3FP32* vector) @@ -149,7 +149,328 @@ int main() { } */ -int main() { +void test_basis_difference_fp32() +{ + + BgcVector3FP32 initial_primary, initial_auxiliary; + BgcVector3FP32 final_primary, final_auxiliary; + BgcVersorFP32 turn; + + // No turn + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nNo turn:\n"); + print_versor_fp32(&turn); + + // Turn around (1, 1, 0) axis on 180 degrees + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nTurn around (1, 1, 0) axis on 180 degrees:\n"); + print_versor_fp32(&turn); + + // 180 degree turn + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(-1.0f, 0.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n180 degree turn around (0, 1, 0):\n"); + print_versor_fp32(&turn); + + // 90 degree turn around x3 axis + bgc_vector3_set_values_fp32(2.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 3.1f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(0.0f, 10.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(-1.0f, 0.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n90 degree turn around (0, 0, 1):\n"); + print_versor_fp32(&turn); + + // Unorthogonal pairs turn at 90 degrees around x3 axis + bgc_vector3_set_values_fp32(2.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(-2.0f, 3.1f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(0.0f, 10.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(-1.0f, 5.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nUnorthogonal pairs turn at 90 degrees around (0, 0, 1):\n"); + print_versor_fp32(&turn); + + // Zero vectors + bgc_vector3_set_values_fp32(0.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_auxiliary); + + int code; + + code = bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + if (code >= 0) { + printf("\nZero vectors: this cannot be!\n"); + print_versor_fp32(&turn); + } + else { + printf("\nZero vector validation works fine\n"); + } + + // Parallel vectors + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(2.0f, 0.0f, 0.0f, &initial_auxiliary); + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_auxiliary); + + code = bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + if (code >= 0) { + printf("\nParallel vectors: this cannot be!\n"); + print_versor_fp32(&turn); + } + else { + printf("\nParallelism validation works fine\n"); + } + + // Small angle turn (about 1 degree): + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(0.999848f, 0.017452f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(-0.017452f, 0.999848f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nSmall angle turn (about 1 degree):\n"); + print_versor_fp32(&turn); + + // About 179 degrees turn + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(-0.999848f, -0.017452f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.017452f, -0.999848f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 179 degrees turn:\n"); + print_versor_fp32(&turn); + + // 120 degrees around (-1, -1, 1) + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &initial_auxiliary); + + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(0.0f, 0.0f, -1.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n120 degees turn:\n"); + print_versor_fp32(&turn); + + + // About 1 degree turn difference between initial_primary and initial_auxiliary directions + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(0.999848f, 0.017452f, 0.0f, &initial_auxiliary); + bgc_vector3_set_values_fp32(0.0f, 1.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(-1.0f, 0.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 1 degree turn difference between initial_primary and initial_auxiliary directions:\n"); + print_versor_fp32(&turn); + + // About 0.01 degree turn difference between initial_primary and initial_auxiliary directions + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &initial_primary); + bgc_vector3_set_values_fp32(1.0f, 0.000001f, 0.0f, &initial_auxiliary); + bgc_vector3_set_values_fp32(0.0f, -1.0f, 0.0f, &final_primary); + bgc_vector3_set_values_fp32(1.0f, 0.0f, 0.0f, &final_auxiliary); + + bgc_versor_make_basis_difference_fp32(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 0.01 degree turn difference between initial_primary and initial_auxiliary directions:\n"); + print_versor_fp32(&turn); +} + +void test_basis_difference_fp64() +{ + + BgcVector3FP64 initial_primary, initial_auxiliary; + BgcVector3FP64 final_primary, final_auxiliary; + BgcVersorFP64 turn; + + // No turn + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nNo turn:\n"); + print_versor_fp64(&turn); + + // Turn around (1, 1, 0) axis on 180 degrees + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nTurn around (1, 1, 0) axis on 180 degrees:\n"); + print_versor_fp64(&turn); + + // 180 degree turn + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(-1.0, 0.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n180 degree turn around (0, 1, 0):\n"); + print_versor_fp64(&turn); + + // 90 degree turn around x3 axis + bgc_vector3_set_values_fp64(2.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 3.1, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(0.0, 10.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(-1.0, 0.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n90 degree turn around (0, 0, 1):\n"); + print_versor_fp64(&turn); + + // Unorthogonal pairs turn at 90 degrees around x3 axis + bgc_vector3_set_values_fp64(2.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(-2.0, 3.1, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(0.0, 10.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(-1.0, 5.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nUnorthogonal pairs turn at 90 degrees around (0, 0, 1):\n"); + print_versor_fp64(&turn); + + // Zero vectors + bgc_vector3_set_values_fp64(0.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_auxiliary); + + int code; + + code = bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + if (code >= 0) { + printf("\nZero vectors: this cannot be!\n"); + print_versor_fp64(&turn); + } + else { + printf("\nZero vector validation works fine\n"); + } + + // Parallel vectors + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(2.0, 0.0, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_auxiliary); + + code = bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + if (code >= 0) { + printf("\nParallel vectors: this cannot be!\n"); + print_versor_fp64(&turn); + } + else { + printf("\nParallelism validation works fine\n"); + } + + // Small angle turn (about 1 degree): + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(0.999848, 0.017452, 0.0, &final_primary); + bgc_vector3_set_values_fp64(-0.017452, 0.999848, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nSmall angle turn (about 1 degree):\n"); + print_versor_fp64(&turn); + + // About 179 degrees turn + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(-0.999848, -0.017452, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.017452, -0.999848, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 179 degrees turn:\n"); + print_versor_fp64(&turn); + + // 120 degrees around (-1, -1, 1) + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &initial_auxiliary); + + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(0.0, 0.0, -1.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\n120 degees turn:\n"); + print_versor_fp64(&turn); + + + // About 1 degree turn difference between initial_primary and initial_auxiliary directions + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(0.999848, 0.017452, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(0.0, 1.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(-1.0, 0.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 1 degree turn difference between initial_primary and initial_auxiliary directions:\n"); + print_versor_fp64(&turn); + + // About 0.001 degree turn difference between initial_primary and initial_auxiliary directions + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &initial_primary); + bgc_vector3_set_values_fp64(1.0, 0.000001, 0.0, &initial_auxiliary); + bgc_vector3_set_values_fp64(0.0, -1.0, 0.0, &final_primary); + bgc_vector3_set_values_fp64(1.0, 0.0, 0.0, &final_auxiliary); + + bgc_versor_make_basis_difference_fp64(&initial_primary, &initial_auxiliary, &final_primary, &final_auxiliary, &turn); + + printf("\nAbout 0.01 degree turn difference between initial_primary and initial_auxiliary directions:\n"); + print_versor_fp64(&turn); +} + +int main() +{ //BgcVersorFP32 start = { 1.0f, 0.0f, 0.0f, 0.0f }; //BgcVersorFP32 end = { 0.0f, 1.0f, 0.0f, 0.0f }; /* @@ -162,12 +483,7 @@ int main() { printf("Result: %0.12f, %0.12f, %0.12f, %0.12f\n", result.s0, result.x1, result.x2, result.x3); */ - BgcVersorFP64 start = { 1.0, 0.0, 0.0, 0.0 }; - BgcVersorFP64 end = { -0.707, 0.707, 0.0, 0.0 }; - BgcVersorFP64 result; - BgcSlerpFP64 slerp; - bgc_slerp_make_full_fp64(&start, &end, &slerp); - bgc_slerp_get_turn_for_phase_fp64(&slerp, 0.5f, &result); - printf("Result: %0.15f, %0.15f, %0.15f, %0.15f\n", result.s0, result.x1, result.x2, result.x3); + test_basis_difference_fp64(); + return 0; } diff --git a/basic-geometry/basic-geometry.vcxproj b/basic-geometry/basic-geometry.vcxproj index b8039b9..3614dc7 100644 --- a/basic-geometry/basic-geometry.vcxproj +++ b/basic-geometry/basic-geometry.vcxproj @@ -21,7 +21,6 @@ - @@ -41,7 +40,6 @@ - diff --git a/basic-geometry/basic-geometry.vcxproj.filters b/basic-geometry/basic-geometry.vcxproj.filters index fb935d0..440dcb1 100644 --- a/basic-geometry/basic-geometry.vcxproj.filters +++ b/basic-geometry/basic-geometry.vcxproj.filters @@ -69,9 +69,6 @@ Файлы заголовков - - Файлы заголовков - @@ -113,8 +110,5 @@ Исходные файлы - - Исходные файлы - \ No newline at end of file diff --git a/basic-geometry/basis3.c b/basic-geometry/basis3.c deleted file mode 100644 index 566c909..0000000 --- a/basic-geometry/basis3.c +++ /dev/null @@ -1,232 +0,0 @@ -#include -#include "./basis3.h" - -typedef struct { - int e1, e2, e3; -} _BgcBasis3State; - -static inline void _bgc_basis3_state_reset(_BgcBasis3State* state) -{ - state->e1 = 0; - state->e2 = 0; - state->e3 = 0; -} - -static inline int _bgc_basis3_validate_directions(const int primary_direction, const int auxiliary_direction) -{ - if (!bgc_is_correct_direction(primary_direction)) { - return BGC_ERROR_BASIS3_PRIMARY_DIRECTION_UNKNOWN; - } - - if (!bgc_is_correct_direction(auxiliary_direction)) { - return BGC_ERROR_BASIS3_AUXILIARY_DIRECTION_UNKNOWN; - } - - if (primary_direction == auxiliary_direction || primary_direction == -auxiliary_direction) { - return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; - } - - return BGC_SUCCESS; -} - -static inline void _bgc_basis3_load_axis_fp32(const int direction, const BgcVector3FP32* axis, _BgcBasis3State* state, BgcBasis3FP32* basis) -{ - switch (direction) { - case BGC_DIRECTION_X1: - bgc_vector3_copy_fp32(axis, &basis->e1); - state->e1 = 1; - break; - - case -BGC_DIRECTION_X1: - bgc_vector3_reverse_fp32(axis, &basis->e1); - state->e1 = 1; - break; - - case BGC_DIRECTION_X2: - bgc_vector3_copy_fp32(axis, &basis->e2); - state->e2 = 1; - break; - - case -BGC_DIRECTION_X2: - bgc_vector3_reverse_fp32(axis, &basis->e2); - state->e2 = 1; - break; - - case BGC_DIRECTION_X3: - bgc_vector3_copy_fp32(axis, &basis->e3); - state->e3 = 1; - break; - - case -BGC_DIRECTION_X3: - bgc_vector3_reverse_fp32(axis, &basis->e3); - state->e3 = 1; - break; - } -} - -int bgc_basis3_make_from_directions_fp32( - const int primary_direction, const BgcVector3FP32* primary_vector, - const int auxiliary_direction, const BgcVector3FP32* auxiliary_vector, - BgcBasis3FP32* basis -) { - const int direstion_validation_code = _bgc_basis3_validate_directions(primary_direction, auxiliary_direction); - - if (direstion_validation_code != BGC_SUCCESS) { - return direstion_validation_code; - } - - const float primary_square_modulus = bgc_vector3_get_square_modulus_fp32(primary_vector); - - if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { - return BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO; - } - - const float auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp32(auxiliary_vector); - - if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { - return BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO; - } - - BgcVector3FP32 orthogonal; - - bgc_vector3_get_cross_product_fp32(primary_vector, auxiliary_vector, &orthogonal); - - const float orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp32(&orthogonal); - - if (orthogonal_square_modulus <= BGC_SQUARE_EPSYLON_FP32 * primary_square_modulus * auxiliary_square_modulus) { - return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; - } - - BgcVector3FP32 primary_axis, auxiliary_axis; - - bgc_vector3_multiply_fp32(primary_vector, sqrtf(1.0f / primary_square_modulus), &primary_axis); - - bgc_vector3_subtract_scaled_fp32(auxiliary_vector, &primary_axis, bgc_vector3_get_scalar_product_fp32(auxiliary_vector, &primary_axis), &auxiliary_axis); - - bgc_vector3_multiply_fp32(&auxiliary_axis, sqrtf(1.0f / bgc_vector3_get_square_modulus_fp32(&auxiliary_axis)), &auxiliary_axis); - - _BgcBasis3State state; - - _bgc_basis3_state_reset(&state); - - _bgc_basis3_load_axis_fp32(primary_direction, &primary_axis, &state, basis); - _bgc_basis3_load_axis_fp32(auxiliary_direction, &auxiliary_axis, &state, basis); - - if (!state.e1) { - bgc_vector3_get_cross_product_fp32(&basis->e2, &basis->e3, &basis->e1); - bgc_vector3_normalize_fp32(&basis->e1); - return BGC_SUCCESS; - } - - if (!state.e2) { - bgc_vector3_get_cross_product_fp32(&basis->e3, &basis->e1, &basis->e2); - bgc_vector3_normalize_fp32(&basis->e2); - return BGC_SUCCESS; - } - - bgc_vector3_get_cross_product_fp32(&basis->e1, &basis->e2, &basis->e3); - bgc_vector3_normalize_fp32(&basis->e3); - - return BGC_SUCCESS; -} - -static inline void _bgc_basis3_load_axis_fp64(const int direction, const BgcVector3FP64* axis, _BgcBasis3State* state, BgcBasis3FP64* basis) -{ - switch (direction) { - case BGC_DIRECTION_X1: - bgc_vector3_copy_fp64(axis, &basis->e1); - state->e1 = 1; - break; - - case -BGC_DIRECTION_X1: - bgc_vector3_reverse_fp64(axis, &basis->e1); - state->e1 = 1; - break; - - case BGC_DIRECTION_X2: - bgc_vector3_copy_fp64(axis, &basis->e2); - state->e2 = 1; - break; - - case -BGC_DIRECTION_X2: - bgc_vector3_reverse_fp64(axis, &basis->e2); - state->e2 = 1; - break; - - case BGC_DIRECTION_X3: - bgc_vector3_copy_fp64(axis, &basis->e3); - state->e3 = 1; - break; - - case -BGC_DIRECTION_X3: - bgc_vector3_reverse_fp64(axis, &basis->e3); - state->e3 = 1; - break; - } -} - -int bgc_basis3_make_from_directions_fp64( - const int primary_direction, const BgcVector3FP64* primary_vector, - const int auxiliary_direction, const BgcVector3FP64* auxiliary_vector, - BgcBasis3FP64* basis -) { - const int direstion_validation_code = _bgc_basis3_validate_directions(primary_direction, auxiliary_direction); - - if (direstion_validation_code != BGC_SUCCESS) { - return direstion_validation_code; - } - - const double primary_square_modulus = bgc_vector3_get_square_modulus_fp64(primary_vector); - - if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { - return BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO; - } - - const double auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp64(auxiliary_vector); - - if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { - return BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO; - } - - BgcVector3FP64 orthogonal; - - bgc_vector3_get_cross_product_fp64(primary_vector, auxiliary_vector, &orthogonal); - - const double orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp64(&orthogonal); - - if (orthogonal_square_modulus <= BGC_SQUARE_EPSYLON_FP64 * primary_square_modulus * auxiliary_square_modulus) { - return BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL; - } - - BgcVector3FP64 primary_axis, auxiliary_axis; - - bgc_vector3_multiply_fp64(primary_vector, sqrt(1.0 / primary_square_modulus), &primary_axis); - - bgc_vector3_subtract_scaled_fp64(auxiliary_vector, &primary_axis, bgc_vector3_get_scalar_product_fp64(auxiliary_vector, &primary_axis), &auxiliary_axis); - - bgc_vector3_multiply_fp64(&auxiliary_axis, sqrt(1.0 / bgc_vector3_get_square_modulus_fp64(&auxiliary_axis)), &auxiliary_axis); - - _BgcBasis3State state; - - _bgc_basis3_state_reset(&state); - - _bgc_basis3_load_axis_fp64(primary_direction, &primary_axis, &state, basis); - _bgc_basis3_load_axis_fp64(auxiliary_direction, &auxiliary_axis, &state, basis); - - if (!state.e1) { - bgc_vector3_get_cross_product_fp64(&basis->e2, &basis->e3, &basis->e1); - bgc_vector3_normalize_fp64(&basis->e1); - return BGC_SUCCESS; - } - - if (!state.e2) { - bgc_vector3_get_cross_product_fp64(&basis->e3, &basis->e1, &basis->e2); - bgc_vector3_normalize_fp64(&basis->e2); - return BGC_SUCCESS; - } - - bgc_vector3_get_cross_product_fp64(&basis->e1, &basis->e2, &basis->e3); - bgc_vector3_normalize_fp64(&basis->e3); - - return BGC_SUCCESS; -} diff --git a/basic-geometry/basis3.h b/basic-geometry/basis3.h deleted file mode 100644 index b1b995d..0000000 --- a/basic-geometry/basis3.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _BGC_BASIS3_H_ -#define _BGC_BASIS3_H_ - -#include "./vector3.h" - -#define BGC_ERROR_BASIS3_PRIMARY_DIRECTION_UNKNOWN -3001 -#define BGC_ERROR_BASIS3_PRIMARY_VECTOR_IS_ZERO -3002 - -#define BGC_ERROR_BASIS3_AUXILIARY_DIRECTION_UNKNOWN -3011 -#define BGC_ERROR_BASIS3_AUXILIARY_VECTOR_IS_ZERO -3012 - -#define BGC_ERROR_BASIS3_PRIMARY_AUXILIARY_PARALLEL -3021 - - -typedef struct { - BgcVector3FP32 e1, e2, e3; -} BgcBasis3FP32; - -typedef struct { - BgcVector3FP64 e1, e2, e3; -} BgcBasis3FP64; - -int bgc_basis3_make_from_directions_fp32( - const int primary_direction, const BgcVector3FP32* primary_vector, - const int auxiliary_direction, const BgcVector3FP32* auxiliary_vector, - BgcBasis3FP32* basis -); - -int bgc_basis3_make_from_directions_fp64( - const int primary_direction, const BgcVector3FP64* primary_vector, - const int auxiliary_direction, const BgcVector3FP64* auxiliary_vector, - BgcBasis3FP64* basis -); - -#endif diff --git a/basic-geometry/utilities.h b/basic-geometry/utilities.h index d12b091..aadca7f 100644 --- a/basic-geometry/utilities.h +++ b/basic-geometry/utilities.h @@ -4,7 +4,7 @@ #define BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP32 1.0f #define BGC_EPSYLON_FP32 4.76837E-7f -#define BGC_SQUARE_EPSYLON_FP32 2.27373906E-13f +#define BGC_SQUARE_EPSYLON_FP32 (BGC_EPSYLON_FP32 * BGC_EPSYLON_FP32) #define BGC_ONE_THIRD_FP32 0.3333333333f #define BGC_ONE_SIXTH_FP32 0.1666666667f @@ -19,7 +19,7 @@ #define BGC_EPSYLON_EFFECTIVENESS_LIMIT_FP64 1.0 #define BGC_EPSYLON_FP64 4.996003611E-14 -#define BGC_SQUARE_EPSYLON_FP64 2.496005208112504E-27 +#define BGC_SQUARE_EPSYLON_FP64 (BGC_EPSYLON_FP64 * BGC_EPSYLON_FP64) #define BGC_ONE_THIRD_FP64 0.3333333333333333333 #define BGC_ONE_SIXTH_FP64 0.1666666666666666667 diff --git a/basic-geometry/vector2.c b/basic-geometry/vector2.c index 637de61..bf59117 100644 --- a/basic-geometry/vector2.c +++ b/basic-geometry/vector2.c @@ -6,6 +6,9 @@ extern inline void bgc_vector2_reset_fp64(BgcVector2FP64* vector); extern inline void bgc_vector2_set_values_fp32(const float x1, const float x2, BgcVector2FP32* destination); extern inline void bgc_vector2_set_values_fp64(const double x1, const double x2, BgcVector2FP64* destination); +extern inline int bgc_vector2_get_direction_fp32(const int direction, BgcVector2FP32* vector); +extern inline int bgc_vector2_get_direction_fp64(const int direction, BgcVector2FP64* vector); + extern inline float bgc_vector2_get_square_modulus_fp32(const BgcVector2FP32* vector); extern inline double bgc_vector2_get_square_modulus_fp64(const BgcVector2FP64* vector); diff --git a/basic-geometry/vector2.h b/basic-geometry/vector2.h index 1effc5e..9c9c508 100644 --- a/basic-geometry/vector2.h +++ b/basic-geometry/vector2.h @@ -44,6 +44,62 @@ inline void bgc_vector2_set_values_fp64(const double x1, const double x2, BgcVec destination->x2 = x2; } +// ================= Directions ================= // + +inline int bgc_vector2_get_direction_fp32(const int direction, BgcVector2FP32* vector) +{ + switch (direction) { + case BGC_DIRECTION_X1: + vector->x1 = 1.0f; + vector->x2 = 0.0f; + return 1; + + case BGC_DIRECTION_X2: + vector->x1 = 0.0f; + vector->x2 = 1.0f; + return 1; + + case -BGC_DIRECTION_X1: + vector->x1 = -1.0f; + vector->x2 = 0.0f; + return 1; + + case -BGC_DIRECTION_X2: + vector->x1 = 0.0f; + vector->x2 = -1.0f; + return 1; + } + + return 0; +} + +inline int bgc_vector2_get_direction_fp64(const int direction, BgcVector2FP64* vector) +{ + switch (direction) { + case BGC_DIRECTION_X1: + vector->x1 = 1.0; + vector->x2 = 0.0; + return 1; + + case BGC_DIRECTION_X2: + vector->x1 = 0.0; + vector->x2 = 1.0; + return 1; + + case -BGC_DIRECTION_X1: + vector->x1 = -1.0; + vector->x2 = 0.0; + return 1; + + case -BGC_DIRECTION_X2: + vector->x1 = 0.0; + vector->x2 = -1.0; + return 1; + } + + return 0; +} + // ================== Modulus =================== // inline float bgc_vector2_get_square_modulus_fp32(const BgcVector2FP32* vector) diff --git a/basic-geometry/vector3.c b/basic-geometry/vector3.c index 9b97d80..287f0f5 100644 --- a/basic-geometry/vector3.c +++ b/basic-geometry/vector3.c @@ -6,6 +6,9 @@ extern inline void bgc_vector3_reset_fp64(BgcVector3FP64* vector); extern inline void bgc_vector3_set_values_fp32(const float x1, const float x2, const float x3, BgcVector3FP32* destination); extern inline void bgc_vector3_set_values_fp64(const double x1, const double x2, const double x3, BgcVector3FP64* destination); +inline int bgc_vector3_get_direction_fp32(const int direction, BgcVector3FP32* vector); +inline int bgc_vector3_get_direction_fp64(const int direction, BgcVector3FP64* vector); + extern inline float bgc_vector3_get_square_modulus_fp32(const BgcVector3FP32* vector); extern inline double bgc_vector3_get_square_modulus_fp64(const BgcVector3FP64* vector); diff --git a/basic-geometry/vector3.h b/basic-geometry/vector3.h index 33f846e..3f828f8 100644 --- a/basic-geometry/vector3.h +++ b/basic-geometry/vector3.h @@ -50,6 +50,94 @@ inline void bgc_vector3_set_values_fp64(const double x1, const double x2, const destination->x3 = x3; } +// ================= Directions ================= // + +inline int bgc_vector3_get_direction_fp32(const int direction, BgcVector3FP32* vector) +{ + switch (direction) { + case BGC_DIRECTION_X1: + vector->x1 = 1.0f; + vector->x2 = 0.0f; + vector->x3 = 0.0f; + return 1; + + case BGC_DIRECTION_X2: + vector->x1 = 0.0f; + vector->x2 = 1.0f; + vector->x3 = 0.0f; + return 1; + + case BGC_DIRECTION_X3: + vector->x1 = 0.0f; + vector->x2 = 0.0f; + vector->x3 = 1.0f; + return 1; + + case -BGC_DIRECTION_X1: + vector->x1 = -1.0f; + vector->x2 = 0.0f; + vector->x3 = 0.0f; + return 1; + + case -BGC_DIRECTION_X2: + vector->x1 = 0.0f; + vector->x2 = -1.0f; + vector->x3 = 0.0f; + return 1; + + case -BGC_DIRECTION_X3: + vector->x1 = 0.0f; + vector->x2 = 0.0f; + vector->x3 = -1.0f; + return 1; + } + + return 0; +} + +inline int bgc_vector3_get_direction_fp64(const int direction, BgcVector3FP64* vector) +{ + switch (direction) { + case BGC_DIRECTION_X1: + vector->x1 = 1.0; + vector->x2 = 0.0; + vector->x3 = 0.0; + return 1; + + case BGC_DIRECTION_X2: + vector->x1 = 0.0; + vector->x2 = 1.0; + vector->x3 = 0.0; + return 1; + + case BGC_DIRECTION_X3: + vector->x1 = 0.0; + vector->x2 = 0.0; + vector->x3 = 1.0; + return 1; + + case -BGC_DIRECTION_X1: + vector->x1 = -1.0; + vector->x2 = 0.0; + vector->x3 = 0.0; + return 1; + + case -BGC_DIRECTION_X2: + vector->x1 = 0.0; + vector->x2 = -1.0; + vector->x3 = 0.0; + return 1; + + case -BGC_DIRECTION_X3: + vector->x1 = 0.0; + vector->x2 = 0.0; + vector->x3 = -1.0; + return 1; + } + + return 0; +} + // ================== Modulus =================== // inline float bgc_vector3_get_square_modulus_fp32(const BgcVector3FP32* vector) diff --git a/basic-geometry/versor.c b/basic-geometry/versor.c index 842fc40..2d84a73 100644 --- a/basic-geometry/versor.c +++ b/basic-geometry/versor.c @@ -151,6 +151,274 @@ void bgc_versor_set_turn_fp64(const double x1, const double x2, const double x3, bgc_versor_set_values_fp64(cos(half_angle), x1 * multiplier, x2 * multiplier, x3 * multiplier, result); } +// ========= Make Direction Difference ========== // + +inline int _bgc_versor_make_direction_turn_fp32(const BgcVector3FP32* start, const BgcVector3FP32* end, const float square_modulus_product, BgcVersorFP32* result) +{ + BgcVector3FP32 orthogonal_axis; + + bgc_vector3_get_cross_product_fp32(start, end, &orthogonal_axis); + + const float scalar_product = bgc_vector3_get_scalar_product_fp32(start, end); + const float square_modulus = bgc_vector3_get_square_modulus_fp32(&orthogonal_axis); + const float square_sine = square_modulus / square_modulus_product; + + if (square_sine > BGC_SQUARE_EPSYLON_FP32) { + 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_versor_set_values_fp32(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_versor_reset_fp32(result); + return BGC_ZERO_TURN; +} + +inline int _bgc_versor_make_direction_turn_fp64(const BgcVector3FP64* start, const BgcVector3FP64* end, const double square_modulus_product, BgcVersorFP64* result) +{ + BgcVector3FP64 orthogonal_axis; + + bgc_vector3_get_cross_product_fp64(start, end, &orthogonal_axis); + + const double scalar_product = bgc_vector3_get_scalar_product_fp64(start, end); + const double square_modulus = bgc_vector3_get_square_modulus_fp64(&orthogonal_axis); + const double square_sine = square_modulus / square_modulus_product; + + if (square_sine > BGC_SQUARE_EPSYLON_FP64) { + 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_versor_set_values_fp64(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_versor_reset_fp64(result); + return BGC_ZERO_TURN; +} + +int bgc_versor_make_direction_difference_fp32(const BgcVector3FP32* start, const BgcVector3FP32* end, BgcVersorFP32* result) +{ + const float start_square_modulus = bgc_vector3_get_square_modulus_fp32(start); + const float end_square_modulus = bgc_vector3_get_square_modulus_fp32(end); + + if (start_square_modulus <= BGC_SQUARE_EPSYLON_FP32 || end_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + bgc_versor_reset_fp32(result); + return BGC_ZERO_TURN; + } + + return _bgc_versor_make_direction_turn_fp32(start, end, start_square_modulus * end_square_modulus, result); +} + +int bgc_versor_make_direction_difference_fp64(const BgcVector3FP64* start, const BgcVector3FP64* end, BgcVersorFP64* result) +{ + const double start_square_modulus = bgc_vector3_get_square_modulus_fp64(start); + const double end_square_modulus = bgc_vector3_get_square_modulus_fp64(end); + + if (start_square_modulus <= BGC_SQUARE_EPSYLON_FP64 || end_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + bgc_versor_reset_fp64(result); + return BGC_ZERO_TURN; + } + + return _bgc_versor_make_direction_turn_fp64(start, end, start_square_modulus * end_square_modulus, result); +} + +// =============== Set Directions =============== // + +inline int _bgc_versor_validate_basis_fp32(const float primary_square_modulus, const float auxiliary_square_modulus, const float orthogonal_square_modulus) +{ + if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + //TODO: add error code for: primary_vector is zero + return BGC_FAILED; + } + + if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP32) { + //TODO: add error code for: auxiliary_vector is zero + return BGC_FAILED; + } + + if (orthogonal_square_modulus / (primary_square_modulus * auxiliary_square_modulus) <= BGC_SQUARE_EPSYLON_FP32) { + //TODO: add error code for: primary_vector and auxiliary_vector are parallel + return BGC_FAILED; + } + + return BGC_SUCCESS; +} + +inline int _bgc_versor_validate_basis_fp64(const double primary_square_modulus, const double auxiliary_square_modulus, const double orthogonal_square_modulus) +{ + if (primary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + //TODO: add error code for: primary_vector is zero + return BGC_FAILED; + } + + if (auxiliary_square_modulus <= BGC_SQUARE_EPSYLON_FP64) { + //TODO: add error code for: auxiliary_vector is zero + return BGC_FAILED; + } + + if (orthogonal_square_modulus / (primary_square_modulus * auxiliary_square_modulus) <= BGC_SQUARE_EPSYLON_FP64) { + //TODO: add error code for: primary_vector and auxiliary_vector are parallel + return BGC_FAILED; + } + + return BGC_SUCCESS; +} + +int bgc_versor_make_basis_difference_fp32( + const BgcVector3FP32* initial_primary_direction, + const BgcVector3FP32* initial_auxiliary_direction, + const BgcVector3FP32* final_primary_direction, + const BgcVector3FP32* final_auxiliary_direction, + BgcVersorFP32* result +) +{ + BgcVector3FP32 initial_orthogonal_direction, turned_orthogonal_direction, final_orthogonal_direction; + + // Step 1: Validate initial basis: + bgc_vector3_get_cross_product_fp32(initial_primary_direction, initial_auxiliary_direction, &initial_orthogonal_direction); + + const float initial_primary_square_modulus = bgc_vector3_get_square_modulus_fp32(initial_primary_direction); + const float initial_auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp32(initial_auxiliary_direction); + const float initial_orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp32(&initial_orthogonal_direction); + + const int initial_basis_valudation = _bgc_versor_validate_basis_fp32(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_vector3_get_cross_product_fp32(final_primary_direction, final_auxiliary_direction, &final_orthogonal_direction); + + const float final_primary_square_modulus = bgc_vector3_get_square_modulus_fp32(final_primary_direction); + const float final_auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp32(final_auxiliary_direction); + const float final_orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp32(&final_orthogonal_direction); + + const int final_basis_valudation = _bgc_versor_validate_basis_fp32(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_vector3_divide_fp32(&initial_orthogonal_direction, sqrtf(initial_orthogonal_square_modulus), &initial_orthogonal_direction); + bgc_vector3_divide_fp32(&final_orthogonal_direction, sqrtf(final_orthogonal_square_modulus), &final_orthogonal_direction); + + BgcVersorFP32 turn1, turn2; + + // Step 4: Find turn1 + int turn1_code = _bgc_versor_make_direction_turn_fp32(initial_primary_direction, final_primary_direction, initial_primary_square_modulus * final_primary_square_modulus, &turn1); + + if (turn1_code == BGC_OPPOSITE) { + bgc_versor_set_values_fp32(0.0f, initial_orthogonal_direction.x1, initial_orthogonal_direction.x2, initial_orthogonal_direction.x3, &turn1); + } + + bgc_versor_turn_vector_fp32(&turn1, &initial_orthogonal_direction, &turned_orthogonal_direction); + + // Step 5: Find turn2: + int turn2_code = _bgc_versor_make_direction_turn_fp32(&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_versor_set_values_fp32(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_versor_combine_fp32(&turn2, &turn1, result); + + return BGC_SUCCESS; +} + +int bgc_versor_make_basis_difference_fp64( + const BgcVector3FP64* initial_primary_direction, + const BgcVector3FP64* initial_auxiliary_direction, + const BgcVector3FP64* final_primary_direction, + const BgcVector3FP64* final_auxiliary_direction, + BgcVersorFP64* result +) +{ + BgcVector3FP64 initial_orthogonal_direction, turned_orthogonal_direction, final_orthogonal_direction; + + // Step 1: Validate initial basis: + bgc_vector3_get_cross_product_fp64(initial_primary_direction, initial_auxiliary_direction, &initial_orthogonal_direction); + + const double initial_primary_square_modulus = bgc_vector3_get_square_modulus_fp64(initial_primary_direction); + const double initial_auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp64(initial_auxiliary_direction); + const double initial_orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp64(&initial_orthogonal_direction); + + const int initial_basis_valudation = _bgc_versor_validate_basis_fp64(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_vector3_get_cross_product_fp64(final_primary_direction, final_auxiliary_direction, &final_orthogonal_direction); + + const double final_primary_square_modulus = bgc_vector3_get_square_modulus_fp64(final_primary_direction); + const double final_auxiliary_square_modulus = bgc_vector3_get_square_modulus_fp64(final_auxiliary_direction); + const double final_orthogonal_square_modulus = bgc_vector3_get_square_modulus_fp64(&final_orthogonal_direction); + + const int final_basis_valudation = _bgc_versor_validate_basis_fp64(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_vector3_divide_fp64(&initial_orthogonal_direction, sqrt(initial_orthogonal_square_modulus), &initial_orthogonal_direction); + bgc_vector3_divide_fp64(&final_orthogonal_direction, sqrt(final_orthogonal_square_modulus), &final_orthogonal_direction); + + BgcVersorFP64 turn1, turn2; + + // Step 4: Find turn1 + int turn1_code = _bgc_versor_make_direction_turn_fp64(initial_primary_direction, final_primary_direction, initial_primary_square_modulus * final_primary_square_modulus, &turn1); + + if (turn1_code == BGC_OPPOSITE) { + bgc_versor_set_values_fp64(0.0, initial_orthogonal_direction.x1, initial_orthogonal_direction.x2, initial_orthogonal_direction.x3, &turn1); + } + + bgc_versor_turn_vector_fp64(&turn1, &initial_orthogonal_direction, &turned_orthogonal_direction); + + // Step 5: Find turn2: + int turn2_code = _bgc_versor_make_direction_turn_fp64(&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_versor_set_values_fp64(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_versor_combine_fp64(&turn2, &turn1, result); + + return BGC_SUCCESS; +} + // =============== Get Exponation =============== // void bgc_versor_get_exponation_fp32(const BgcVersorFP32* base, const float exponent, BgcVersorFP32* power) diff --git a/basic-geometry/versor.h b/basic-geometry/versor.h index c516c8d..6627d93 100644 --- a/basic-geometry/versor.h +++ b/basic-geometry/versor.h @@ -8,6 +8,20 @@ #include "vector3.h" #include "rotation3.h" #include "matrix3x3.h" +#include "quaternion.h" + +#define BGC_SOME_TURN 1 +#define BGC_ZERO_TURN 0 +#define BGC_OPPOSITE -1 + +#define BGC_ERROR_PRIMARY_DIRECTION_UNKNOWN -3001 +#define BGC_ERROR_PRIMARY_VECTOR_IS_ZERO -3002 + +#define BGC_ERROR_AUXILIARY_DIRECTION_UNKNOWN -3011 +#define BGC_ERROR_AUXILIARY_VECTOR_IS_ZERO -3012 + +#define BGC_ERROR_DIRECTIONS_PARALLEL -3021 +#define BGC_ERROR_VECTORS_PARALLEL -3022 // =================== Types ==================== // @@ -112,6 +126,30 @@ inline void bgc_versor_set_rotation_fp64(const BgcRotation3FP64* rotation, BgcVe bgc_versor_set_turn_fp64(rotation->axis.x1, rotation->axis.x2, rotation->axis.x3, rotation->radians, BGC_ANGLE_UNIT_RADIANS, result); } +// ========= Make Direction Difference ========== // + +int bgc_versor_make_direction_difference_fp32(const BgcVector3FP32* start, const BgcVector3FP32* end, BgcVersorFP32* result); + +int bgc_versor_make_direction_difference_fp64(const BgcVector3FP64* start, const BgcVector3FP64* end, BgcVersorFP64* result); + +// =============== Set Directions =============== // + +int bgc_versor_make_basis_difference_fp32( + const BgcVector3FP32* initial_primary_direction, + const BgcVector3FP32* initial_auxiliary_direction, + const BgcVector3FP32* final_primary_direction, + const BgcVector3FP32* final_auxiliary_direction, + BgcVersorFP32* result +); + +int bgc_versor_make_basis_difference_fp64( + const BgcVector3FP64* initial_primary_direction, + const BgcVector3FP64* initial_auxiliary_direction, + const BgcVector3FP64* final_primary_direction, + const BgcVector3FP64* final_auxiliary_direction, + BgcVersorFP64* result +); + // ==================== Copy ==================== // inline void bgc_versor_copy_fp32(const BgcVersorFP32* source, BgcVersorFP32* destination)