diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b28d70..40f9eec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ unit-test-job: - cmake --build . - export GTEST_OUTPUT="xml:report.xml" - ls -la - - "./VectorAlgebraTest" + - "./LinearAlgebraTest" artifacts: when: always reports: diff --git a/Angle.cpp b/Angle.cpp index 4a039ce..d1221a1 100644 --- a/Angle.cpp +++ b/Angle.cpp @@ -3,123 +3,334 @@ // file, You can obtain one at https ://mozilla.org/MPL/2.0/. #include "Angle.h" -#include "FloatSingle.h" #include +#include "FloatSingle.h" -/* -const float Angle::Rad2Deg = 57.29578F; -const float Angle::Deg2Rad = 0.0174532924F; +namespace LinearAlgebra { -float Angle::Normalize(float angle) { - if (!isfinite(angle)) - return angle; +//===== AngleSingle, AngleOf - while (angle <= -180) - angle += 360; - while (angle > 180) - angle -= 360; +template <> +AngleOf AngleOf::Degrees(float degrees) { + if (isfinite(degrees)) { + while (degrees < -180) + degrees += 360; + while (degrees >= 180) + degrees -= 360; + } + + return AngleOf(degrees); +} + +template <> +AngleOf AngleOf::Radians(float radians) { + if (isfinite(radians)) { + while (radians <= -pi) + radians += 2 * pi; + while (radians > pi) + radians -= 2 * pi; + } + + return Binary(radians * Rad2Deg); +} + +template <> +float AngleOf::InDegrees() const { + return this->value; +} + +template <> +float AngleOf::InRadians() const { + return this->value * Deg2Rad; +} + +//===== Angle16, AngleOf + +template <> +AngleOf AngleOf::Degrees(float degrees) { + // map float [-180..180) to integer [-32768..32767] + signed short value = (signed short)roundf(degrees / 360.0F * 65536.0F); + return Binary(value); +} + +template <> +AngleOf AngleOf::Radians(float radians) { + if (!isfinite(radians)) + return AngleOf::zero; + + // map float [-PI..PI) to integer [-32768..32767] + signed short value = (signed short)roundf(radians / pi * 32768.0F); + return Binary(value); +} + +template <> +float AngleOf::InDegrees() const { + float degrees = this->value / 65536.0f * 360.0f; + return degrees; +} + +template <> +float AngleOf::InRadians() const { + float radians = this->value / 65536.0f * (2 * pi); + return radians; +} + +//===== Angle8, AngleOf + +template <> +AngleOf AngleOf::Degrees(float degrees) { + // map float [-180..180) to integer [-128..127) + signed char value = (signed char)roundf(degrees / 360.0F * 256.0F); + return Binary(value); +} + +template <> +AngleOf AngleOf::Radians(float radians) { + if (!isfinite(radians)) + return AngleOf::zero; + + // map float [-pi..pi) to integer [-128..127) + signed char value = (signed char)roundf(radians / pi * 128.0f); + return Binary(value); +} + +template <> +float AngleOf::InDegrees() const { + float degrees = this->value / 256.0f * 360.0f; + return degrees; +} + +template <> +float AngleOf::InRadians() const { + float radians = this->value / 128.0f * pi; + return radians; +} + +//===== Generic + +template +AngleOf::AngleOf() : value(0) {} + +template +AngleOf::AngleOf(T rawValue) : value(rawValue) {} + +template +const AngleOf AngleOf::zero = AngleOf(); + +template +AngleOf AngleOf::Binary(T rawValue) { + AngleOf angle = AngleOf(); + angle.SetBinary(rawValue); return angle; } -float Angle::Clamp(float angle, float min, float max) { - float normalizedAngle = Normalize(angle); - float r = Float::Clamp(normalizedAngle, min, max); +template +T AngleOf::GetBinary() const { + return this->value; +} +template +void AngleOf::SetBinary(T rawValue) { + this->value = rawValue; +} + +template +bool AngleOf::operator==(const AngleOf angle) const { + return this->value == angle.value; +} + +template +bool AngleOf::operator>(AngleOf angle) const { + return this->value > angle.value; +} + +template +bool AngleOf::operator>=(AngleOf angle) const { + return this->value >= angle.value; +} + +template +bool AngleOf::operator<(AngleOf angle) const { + return this->value < angle.value; +} + +template +bool AngleOf::operator<=(AngleOf angle) const { + return this->value <= angle.value; +} + +template +signed int AngleOf::Sign(AngleOf angle) { + if (angle.value < 0) + return -1; + if (angle.value > 0) + return 1; + return 0; +} + +template +AngleOf AngleOf::Abs(AngleOf angle) { + if (Sign(angle) < 0) + return -angle; + else + return angle; +} + +template +AngleOf AngleOf::operator-() const { + AngleOf angle = Binary(-this->value); + return angle; +} + +template <> +AngleOf AngleOf::operator-(const AngleOf& angle) const { + AngleOf r = Binary(this->value - angle.value); + r = Normalize(r); + return r; +} +template +AngleOf AngleOf::operator-(const AngleOf& angle) const { + AngleOf r = Binary(this->value - angle.value); return r; } -float Angle::Difference(float a, float b) { - float r = Normalize(b - a); +template <> +AngleOf AngleOf::operator+(const AngleOf& angle) const { + AngleOf r = Binary(this->value + angle.value); + r = Normalize(r); + return r; +} +template +AngleOf AngleOf::operator+(const AngleOf& angle) const { + AngleOf r = Binary(this->value + angle.value); return r; } -float Angle::MoveTowards(float fromAngle, float toAngle, float maxAngle) { - float d = toAngle - fromAngle; - float sign = signbit(d) ? -1 : 1; - d = sign * Float::Clamp(fabs(d), 0, maxAngle); - return fromAngle + d; +template <> +AngleOf AngleOf::operator+=(const AngleOf& angle) { + this->value += angle.value; + this->Normalize(); + return *this; } -float Angle::CosineRuleSide(float a, float b, float gamma) { - float a2 = a * a; - float b2 = b * b; - float d = a2 + b2 - 2 * a * b * cos(gamma * Angle::Deg2Rad); - // Catch edge cases where float inacuracies lead tot nans - if (d < 0) - return 0; - - float c = sqrtf(d); - return c; +template +AngleOf AngleOf::operator+=(const AngleOf& angle) { + this->value += angle.value; + return *this; } -float Angle::CosineRuleAngle(float a, float b, float c) { - float a2 = a * a; - float b2 = b * b; - float c2 = c * c; - float d = (a2 + b2 - c2) / (2 * a * b); - // Catch edge cases where float inacuracies lead tot nans - if (d >= 1) - return 0; - if (d <= -1) - return 180; +// This defintion is not matching the declaration in the header file somehow +// template +// AngleOf operator*(const AngleOf &angle, float factor) { +// return AngleOf::Degrees((float)angle.InDegrees() * factor); +// } - float gamma = acos(d) * Angle::Rad2Deg; - return gamma; -} +// This defintion is not matching the declaration in the header file somehow +// template +// AngleOf operator*(float factor, const AngleOf &angle) { +// return AngleOf::Degrees((float)factor * angle.InDegrees()); +// } -float Angle::SineRuleAngle(float a, float beta, float b) { - float alpha = asin(a * sin(beta * Angle::Deg2Rad) / b); - return alpha; -} -*/ -//---------------------- - -template <> Angle2 Angle2::pi = 3.1415927410125732421875F; - -template <> Angle2 Angle2::Rad2Deg = 360.0f / (pi * 2); -template <> Angle2 Angle2::Deg2Rad = (pi * 2) / 360.0f; - -template <> Angle2 Angle2::Normalize(Angle2 angle) { - float angleValue = angle; +template +void AngleOf::Normalize() { + float angleValue = this->InDegrees(); if (!isfinite(angleValue)) - return angleValue; + return; while (angleValue <= -180) angleValue += 360; while (angleValue > 180) angleValue -= 360; - return angleValue; + *this = AngleOf::Degrees(angleValue); } -template <> -Angle2 Angle2::Clamp(Angle2 angle, Angle2 min, - Angle2 max) { - float normalizedAngle = Normalize(angle); - float r = Float::Clamp(normalizedAngle, min, max); - return r; +template +AngleOf AngleOf::Normalize(AngleOf angle) { + float angleValue = angle.InDegrees(); + if (!isfinite(angleValue)) + return angle; + + while (angleValue <= -180) + angleValue += 360; + while (angleValue > 180) + angleValue -= 360; + return AngleOf::Degrees(angleValue); } -// template -// Angle2 Angle2::Difference(Angle2 a, Angle2 b) { -// Angle2 r = Normalize(b - a); -// return r; -// } +template +AngleOf AngleOf::Clamp(AngleOf angle, AngleOf min, AngleOf max) { + float r = Float::Clamp(angle.InDegrees(), min.InDegrees(), max.InDegrees()); + return AngleOf::Degrees(r); +} + +template +AngleOf AngleOf::MoveTowards(AngleOf fromAngle, + AngleOf toAngle, + float maxDegrees) { + maxDegrees = fmaxf(0, maxDegrees); // filter out negative distances + AngleOf d = toAngle - fromAngle; + float dDegrees = Abs(d).InDegrees(); + d = AngleOf::Degrees(Float::Clamp(dDegrees, 0, maxDegrees)); + if (Sign(d) < 0) + d = -d; -template <> -Angle2 Angle2::MoveTowards(Angle2 fromAngle, - Angle2 toAngle, - Angle2 maxAngle) { - float d = toAngle - fromAngle; - float sign = signbit(d) ? -1 : 1; - d = sign * Float::Clamp(fabs(d), 0, maxAngle); return fromAngle + d; } -template <> -Angle2 Angle2::CosineRuleSide(float a, float b, - Angle2 gamma) { +template +float AngleOf::Cos(AngleOf angle) { + return cosf(angle.InRadians()); +} +template +float AngleOf::Sin(AngleOf angle) { + return sinf(angle.InRadians()); +} +template +float AngleOf::Tan(AngleOf angle) { + return tanf(angle.InRadians()); +} + +template +AngleOf AngleOf::Acos(float f) { + return AngleOf::Radians(acosf(f)); +} +template +AngleOf AngleOf::Asin(float f) { + return AngleOf::Radians(asinf(f)); +} +template +AngleOf AngleOf::Atan(float f) { + return AngleOf::Radians(atanf(f)); +} + +template +AngleOf AngleOf::Atan2(float y, float x) { + return AngleOf::Radians(atan2f(y, x)); +} + +// template <> +// float AngleOf::CosineRuleSide(float a, float b, AngleOf gamma) +// { +// float a2 = a * a; +// float b2 = b * b; +// float d = +// a2 + b2 - +// 2 * a * b * Cos(gamma); // cosf(gamma * +// Passer::LinearAlgebra::Deg2Rad); +// // Catch edge cases where float inacuracies lead tot nans +// if (d < 0) +// return 0.0f; + +// float c = sqrtf(d); +// return c; +// } + +template +float AngleOf::CosineRuleSide(float a, float b, AngleOf gamma) { float a2 = a * a; float b2 = b * b; - float d = a2 + b2 - 2 * a * b * cos(gamma * Angle2::Deg2Rad); + float d = + a2 + b2 - + 2 * a * b * Cos(gamma); // cosf(gamma * Passer::LinearAlgebra::Deg2Rad); // Catch edge cases where float inacuracies lead tot nans if (d < 0) return 0; @@ -128,25 +339,56 @@ Angle2 Angle2::CosineRuleSide(float a, float b, return c; } -template <> -Angle2 Angle2::CosineRuleAngle(float a, float b, float c) { +// template <> +// AngleOf AngleOf::CosineRuleAngle(float a, float b, float c) { +// float a2 = a * a; +// float b2 = b * b; +// float c2 = c * c; +// float d = (a2 + b2 - c2) / (2 * a * b); +// // Catch edge cases where float inacuracies lead tot nans +// if (d >= 1) +// return 0.0f; +// if (d <= -1) +// return 180.0f; + +// float gamma = acosf(d) * Rad2Deg; +// return gamma; +// } +template +AngleOf AngleOf::CosineRuleAngle(float a, float b, float c) { float a2 = a * a; float b2 = b * b; float c2 = c * c; float d = (a2 + b2 - c2) / (2 * a * b); // Catch edge cases where float inacuracies lead tot nans if (d >= 1) - return 0; + return AngleOf(); if (d <= -1) - return 180; + return AngleOf::Degrees(180); - float gamma = acos(d) * Angle::Rad2Deg; + // float gamma = acosf(d) * Rad2Deg; + AngleOf gamma = Acos(d); return gamma; } -template <> -Angle2 Angle2::SineRuleAngle(float a, Angle2 beta, - float b) { - float alpha = asin(a * sin(beta * Angle::Deg2Rad) / b); +// template <> +// AngleOf AngleOf::SineRuleAngle(float a, +// AngleOf beta, +// float b) { +// float deg2rad = Deg2Rad; +// float alpha = asinf(a * sinf(beta.InDegrees() * deg2rad) / b); +// return alpha; +// } +template +AngleOf AngleOf::SineRuleAngle(float a, AngleOf beta, float b) { + // float deg2rad = Deg2Rad; + // float alpha = asinf(a * sinf(beta.InDegrees() * deg2rad) / b); + AngleOf alpha = Asin(a * Sin(beta) / b); return alpha; -} \ No newline at end of file +} + +template class AngleOf; +template class AngleOf; +template class AngleOf; + +} // namespace LinearAlgebra \ No newline at end of file diff --git a/Angle.h b/Angle.h index edabf65..e82b3af 100644 --- a/Angle.h +++ b/Angle.h @@ -5,51 +5,223 @@ #ifndef ANGLE_H #define ANGLE_H -template class Angle2 { -public: - Angle2(){}; - Angle2(T v) : value(v) {} - operator T() { return value; } +namespace LinearAlgebra { - static Angle2 Rad2Deg; - static Angle2 Deg2Rad; +static float pi = 3.1415927410125732421875F; - static Angle2 pi; +static float Rad2Deg = 360.0f / (pi * 2); +static float Deg2Rad = (pi * 2) / 360.0f; - static Angle2 Normalize(Angle2 angle); - static Angle2 Clamp(Angle2 angle, Angle2 min, Angle2 max); - static Angle2 Difference(Angle2 a, Angle2 b) { - Angle2 r = Normalize(b - a); - return r; - }; - static Angle2 MoveTowards(Angle2 fromAngle, Angle2 toAngle, - Angle2 maxAngle); +/// @brief An angle in various representations. +/// @tparam T The internal type used for the representation of the angle. +/// The angle is internally limited to (-180..180] degrees or (-PI...PI] +/// radians. When an angle exceeds this range, it is normalized to a value +/// within the range. +template +class AngleOf { + public: + /// @brief Create a new angle with a zero value + AngleOf(); - static Angle2 CosineRuleSide(float a, float b, Angle2 gamma); - static Angle2 CosineRuleAngle(float a, float b, float c); + /// @brief An zero value angle + const static AngleOf zero; + // const static AngleOf deg90; + // const static AngleOf deg180; - static Angle2 SineRuleAngle(float a, Angle2 beta, float c); + /// @brief Creates an angle in degrees + /// @param degrees the angle in degrees + /// @return The angle value + static AngleOf Degrees(float degrees); + /// @brief Creates an angle in radians + /// @param radians the angle in radians + /// @return The angle value + static AngleOf Radians(float radians); -private: + /// @brief Creates an angle from a raw value + /// @param rawValue the raw value to use for the angle + /// @return The the angle + static AngleOf Binary(T rawValue); + + /// @brief Get the angle value in degrees + /// @return The angle value in degrees + float InDegrees() const; + /// @brief Get the angle value in radians + /// @return The angle value in radians + float InRadians() const; + + /// @brief Get the raw value for the angle + /// @return The raw value + T GetBinary() const; + /// @brief Set the raw value of the angle + /// @param rawValue The raw value + void SetBinary(T rawValue); + + /// @brief Tests whether this angle is equal to the given angle + /// @param angle The angle to compare to + /// @return True when the angles are equal, False otherwise + /// @note The equality is determine within the limits of precision of the raw + /// type T + bool operator==(const AngleOf angle) const; + /// @brief Tests if this angle is greater than the given angle + /// @param angle The given angle + /// @return True when this angle is greater than the given angle, False + /// otherwise + bool operator>(AngleOf angle) const; + /// @brief Tests if this angle is greater than or equal to the given angle + /// @param angle The given angle + /// @return True when this angle is greater than or equal to the given angle. + /// False otherwise. + bool operator>=(AngleOf angle) const; + /// @brief Tests if this angle is less than the given angle + /// @param angle The given angle + /// @return True when this angle is less than the given angle. False + /// otherwise. + bool operator<(AngleOf angle) const; + /// @brief Tests if this angle is less than or equal to the given angle + /// @param angle The given angle + /// @return True when this angle is less than or equal to the given angle. + /// False otherwise. + bool operator<=(AngleOf angle) const; + + /// @brief Returns the sign of the angle + /// @param angle The angle + /// @return -1 when the angle is negative, 1 when it is positive and 0 + /// otherwise. + static signed int Sign(AngleOf angle); + /// @brief Returns the magnitude of the angle + /// @param angle The angle + /// @return The positive magitude of the angle. + /// Negative values are negated to get a positive result + static AngleOf Abs(AngleOf angle); + + /// @brief Negate the angle + /// @return The negated angle + AngleOf operator-() const; + /// @brief Substract another angle from this angle + /// @param angle The angle to subtract from this angle + /// @return The result of the subtraction + AngleOf operator-(const AngleOf& angle) const; + /// @brief Add another angle from this angle + /// @param angle The angle to add to this angle + /// @return The result of the addition + AngleOf operator+(const AngleOf& angle) const; + /// @brief Add another angle to this angle + /// @param angle The angle to add to this angle + /// @return The result of the addition + AngleOf operator+=(const AngleOf& angle); + + /// @brief Mutliplies the angle + /// @param angle The angle to multiply + /// @param factor The factor by which the angle is multiplied + /// @return The multiplied angle + friend AngleOf operator*(const AngleOf& angle, float factor) { + return AngleOf::Degrees((float)angle.InDegrees() * factor); + } + /// @brief Multiplies the angle + /// @param factor The factor by which the angle is multiplies + /// @param angle The angle to multiply + /// @return The multiplied angle + friend AngleOf operator*(float factor, const AngleOf& angle) { + return AngleOf::Degrees((float)factor * angle.InDegrees()); + } + + /// @brief Normalizes the angle to (-180..180] or (-PI..PI] + /// Should not be needed but available in case it is. + void Normalize(); + /// @brief Normalizes the angle to (-180..180] or (-PI..PI] + /// @param angle The angle to normalize + /// @return The normalized angle; + static AngleOf Normalize(AngleOf angle); + /// @brief Clamps the angle value between the two given angles + /// @param angle The angle to clamp + /// @param min The minimum angle + /// @param max The maximum angle + /// @return The clamped value + /// @remark When the min value is greater than the max value, angle is + /// returned unclamped. + static AngleOf Clamp(AngleOf angle, AngleOf min, AngleOf max); + // static AngleOf Difference(AngleOf a, AngleOf b) { + // AngleOf r = Normalize(b.InDegrees() - a.InDegrees()); + // return r; + // }; + + /// @brief Rotates an angle towards another angle with a max distance + /// @param fromAngle The angle to start from + /// @param toAngle The angle to rotate towards + /// @param maxAngle The maximum angle to rotate + /// @return The rotated angle + static AngleOf MoveTowards(AngleOf fromAngle, + AngleOf toAngle, + float maxAngle); + + /// @brief Calculates the cosine of an angle + /// @param angle The given angle + /// @return The cosine of the angle + static float Cos(AngleOf angle); + /// @brief Calculates the sine of an angle + /// @param angle The given angle + /// @return The sine of the angle + static float Sin(AngleOf angle); + /// @brief Calculates the tangent of an angle + /// @param angle The given angle + /// @return The tangent of the angle + static float Tan(AngleOf angle); + + /// @brief Calculates the arc cosine angle + /// @param f The value + /// @return The arc cosine for the given value + static AngleOf Acos(float f); + /// @brief Calculates the arc sine angle + /// @param f The value + /// @return The arc sine for the given value + static AngleOf Asin(float f); + /// @brief Calculates the arc tangent angle + /// @param f The value + /// @return The arc tangent for the given value + static AngleOf Atan(float f); + /// @brief Calculates the tangent for the given values + /// @param y The vertical value + /// @param x The horizontal value + /// @return The tanget for the given values + /// Uses the y and x signs to compute the quadrant + static AngleOf Atan2(float y, float x); + + /// @brief Computes the length of a side using the rule of cosines + /// @param a The length of side A + /// @param b The length of side B + /// @param gamma The angle of the corner opposing side C + /// @return The length of side C + static float CosineRuleSide(float a, float b, AngleOf gamma); + /// @brief Computes the angle of a corner using the rule of cosines + /// @param a The length of side A + /// @param b The length of side B + /// @param c The length of side C + /// @return The angle of the corner opposing side C + static AngleOf CosineRuleAngle(float a, float b, float c); + + /// @brief Computes the angle of a corner using the rule of sines + /// @param a The length of side A + /// @param beta the angle of the corner opposing side B + /// @param c The length of side C + /// @return The angle of the corner opposing side A + static AngleOf SineRuleAngle(float a, AngleOf beta, float c); + + private: T value; + + AngleOf(T rawValue); }; -using Angle = Angle2; -/* -class Angle { -public: - const static float Rad2Deg; - const static float Deg2Rad; +using AngleSingle = AngleOf; +using Angle16 = AngleOf; +using Angle8 = AngleOf; - static float Normalize(float angle); - static float Clamp(float angle, float min, float max); - static float Difference(float a, float b); - static float MoveTowards(float fromAngle, float toAngle, float maxAngle); +#if defined(ARDUINO) +using Angle = Angle16; +#else +using Angle = AngleSingle; +#endif - static float CosineRuleSide(float a, float b, float gamma); - static float CosineRuleAngle(float a, float b, float c); +} // namespace LinearAlgebra - static float SineRuleAngle(float a, float beta, float c); -}; -*/ #endif \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d61999d..ed52791 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,15 +5,16 @@ if(ESP_PLATFORM) INCLUDE_DIRS "." ) else() - project(VectorAlgebra) # Create project "simple_example" + project(LinearAlgebra) - set(CMAKE_CXX_STANDARD 11) # Enable c++11 standard + set(CMAKE_CXX_STANDARD 17) # Enable c++11 standard set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_compile_definitions(GTEST) include(FetchContent) FetchContent_Declare( googletest + DOWNLOAD_EXTRACT_TIMESTAMP ON URL https://github.com/google/googletest/archive/refs/heads/main.zip ) @@ -22,35 +23,43 @@ else() FetchContent_MakeAvailable(googletest) include_directories(.) - add_library(VectorAlgebra STATIC - "FloatSingle.cpp" - "Angle.cpp" - "Vector2.cpp" - "Vector3.cpp" - "Quaternion.cpp" - "Polar.cpp" - "Spherical.cpp" - "Matrix.cpp" + file(GLOB srcs + *.cpp + ) + add_library(LinearAlgebra STATIC ${srcs} + # "FloatSingle.cpp" + # "Angle.cpp" + # "Vector2.cpp" + # "Vector3.cpp" + # "Quaternion.cpp" + # "Polar.cpp" + # "Spherical.cpp" + # "Matrix.cpp" + # "SwingTwist.cpp" + # "Direction.cpp" ) enable_testing() + file(GLOB_RECURSE test_srcs test/*_test.cc) add_executable( - VectorAlgebraTest - "test/Angle_test.cc" - "test/FloatSingle_test.cc" - "test/Vector2_test.cc" - "test/Vector3_test.cc" - "test/Quaternion_test.cc" - "test/Matrix_test.cc" + LinearAlgebraTest + ${test_srcs} ) target_link_libraries( - VectorAlgebraTest + LinearAlgebraTest gtest_main - VectorAlgebra + LinearAlgebra ) + if(MSVC) + target_compile_options(LinearAlgebraTest PRIVATE /W4 /WX) +# else() +# target_compile_options(LinearAlgebraTest PRIVATE -Wall -Wextra -Wpedantic -Werror) + endif() + + include(GoogleTest) - gtest_discover_tests(VectorAlgebraTest) + gtest_discover_tests(LinearAlgebraTest) endif() diff --git a/Direction.cpp b/Direction.cpp new file mode 100644 index 0000000..86fa77c --- /dev/null +++ b/Direction.cpp @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https ://mozilla.org/MPL/2.0/. + +#include "Direction.h" + +#include "Quaternion.h" +#include "Vector3.h" + +#include + +namespace LinearAlgebra { +template +DirectionOf::DirectionOf() { + this->horizontal = AngleOf(); + this->vertical = AngleOf(); +} + +template +DirectionOf::DirectionOf(AngleOf horizontal, AngleOf vertical) { + this->horizontal = horizontal; + this->vertical = vertical; + Normalize(); +}; + +template +const DirectionOf DirectionOf::forward = + DirectionOf(AngleOf(), AngleOf()); +template +const DirectionOf DirectionOf::back = + DirectionOf(AngleOf::Degrees(180), AngleOf()); +template +const DirectionOf DirectionOf::up = + DirectionOf(AngleOf(), AngleOf::Degrees(90)); +template +const DirectionOf DirectionOf::down = + DirectionOf(AngleOf(), AngleOf::Degrees(-90)); +template +const DirectionOf DirectionOf::left = + DirectionOf(AngleOf::Degrees(-90), AngleOf()); +template +const DirectionOf DirectionOf::right = + DirectionOf(AngleOf::Degrees(90), AngleOf()); + +template +Vector3 DirectionOf::ToVector3() const { + Quaternion q = Quaternion::Euler(-this->vertical.InDegrees(), + this->horizontal.InDegrees(), 0); + Vector3 v = q * Vector3::forward; + return v; +} + +template +DirectionOf DirectionOf::FromVector3(Vector3 vector) { + DirectionOf d; + d.horizontal = AngleOf::Atan2( + vector.Right(), + vector + .Forward()); // AngleOf::Radians(atan2f(v.Right(), v.Forward())); + d.vertical = + AngleOf::Degrees(-90) - + AngleOf::Acos( + vector.Up()); // AngleOf::Radians(-(0.5f * pi) - acosf(v.Up())); + d.Normalize(); + return d; +} + +template +DirectionOf DirectionOf::Degrees(float horizontal, float vertical) { + return DirectionOf(AngleOf::Degrees(horizontal), + AngleOf::Degrees(vertical)); +} + +template +DirectionOf DirectionOf::Radians(float horizontal, float vertical) { + return DirectionOf(AngleOf::Radians(horizontal), + AngleOf::Radians(vertical)); +} + +template +bool DirectionOf::operator==(const DirectionOf direction) const { + return (this->horizontal == direction.horizontal) && + (this->vertical == direction.vertical); +} + +template +DirectionOf DirectionOf::operator-() const { + DirectionOf r = DirectionOf(this->horizontal + AngleOf::Degrees(180), + -this->vertical); + return r; +} + +template +void DirectionOf::Normalize() { + if (this->vertical > AngleOf::Degrees(90) || + this->vertical < AngleOf::Degrees(-90)) { + this->horizontal += AngleOf::Degrees(180); + this->vertical = AngleOf::Degrees(180) - this->vertical; + } +} + +template class LinearAlgebra::DirectionOf; +template class LinearAlgebra::DirectionOf; +} \ No newline at end of file diff --git a/Direction.h b/Direction.h new file mode 100644 index 0000000..8c58b6c --- /dev/null +++ b/Direction.h @@ -0,0 +1,102 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https ://mozilla.org/MPL/2.0/. + +#ifndef DIRECTION_H +#define DIRECTION_H + +#include "Angle.h" + +namespace LinearAlgebra { + +struct Vector3; + +/// @brief A direction using angles in various representations +/// @tparam T The implementation type used for the representation of the angles +/// A direction is represented using two angles: +/// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive) +/// degrees which is a rotation in the horizontal plane +/// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees +/// which is the rotation in the up/down direction applied after the horizontal +/// rotation has been applied. +/// The angles are automatically normalized to stay within the abovenmentioned +/// ranges. +template +class DirectionOf { + public: + /// @brief horizontal angle, range= (-180..180] + AngleOf horizontal; + /// @brief vertical angle, range in degrees = (-90..90] + AngleOf vertical; + + /// @brief Create a new direction with zero angles + DirectionOf(); + /// @brief Create a new direction + /// @param horizontal The horizontal angle + /// @param vertical The vertical angle. + DirectionOf(AngleOf horizontal, AngleOf vertical); + + /// @brief Convert the direction into a carthesian vector + /// @return The carthesian vector corresponding to this direction. + Vector3 ToVector3() const; + /// @brief Convert a carthesian vector into a direction + /// @param v The carthesian vector + /// @return The direction. + /// @note Information about the length of the carthesian vector is not + /// included in this transformation. + static DirectionOf FromVector3(Vector3 vector); + + /// @brief Create a direction using angle values in degrees + /// @param horizontal The horizontal angle in degrees + /// @param vertical The vertical angle in degrees + /// @return The direction + static DirectionOf Degrees(float horizontal, float vertical); + /// @brief Create a direction using angle values in radians + /// @param horizontal The horizontal angle in radians + /// @param vertical The vertical angle in radians + /// @return The direction + static DirectionOf Radians(float horizontal, float vertical); + + /// @brief A forward direction with zero for both angles + const static DirectionOf forward; + /// @brief A backward direction with horizontal angle -180 and zero vertical + /// angle + const static DirectionOf back; + /// @brief A upward direction with zero horizontal angle and vertical angle 90 + const static DirectionOf up; + /// @brief A downward direction with zero horizontal angle and vertical angle + /// -90 + const static DirectionOf down; + /// @brief A left-pointing direction with horizontal angle -90 and zero + /// vertical angle + const static DirectionOf left; + /// @brief A right-pointing direction with horizontal angle 90 and zero + /// vertical angle + const static DirectionOf right; + + /// @brief Test whether this direction is equal to another direction + /// @param direction The direction to compare to + /// @return True when the direction angles are equal, false otherwise. + bool operator==(const DirectionOf direction) const; + + /// @brief Negate/reverse the direction + /// @return The reversed direction. + DirectionOf operator-() const; + + protected: + /// @brief Normalize this vector to the specified ranges + void Normalize(); +}; + +using DirectionSingle = DirectionOf; +using Direction16 = DirectionOf; + +#if defined(ARDUINO) +using Direction = Direction16; +#else +using Direction = DirectionSingle; +#endif + +} // namespace LinearAlgebra + +#endif \ No newline at end of file diff --git a/DoxyGen/DoxyWarnLogfile.txt b/DoxyGen/DoxyWarnLogfile.txt index d37d508..3f3c14a 100644 --- a/DoxyGen/DoxyWarnLogfile.txt +++ b/DoxyGen/DoxyWarnLogfile.txt @@ -1,420 +1,154 @@ -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_for_dummies.md:566: warning: multiple use of section label 'OrderedCalls' while adding section, (first occurrence: D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md, line 1674) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:411: warning: multiple use of section label 'DefaultValue' while adding section, (first occurrence: D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md, line 2088) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-message.h:62: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:158: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-output-test_.cc:47: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest-typed-test_test.cc:43: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-matchers.h:256: warning: found documented #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ but ignoring it because ENABLE_PREPROCESSING is NO. - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class testing::internal::FindFirstPrinter< T, E, Printers... >! - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class FindFirstPrinter< T, E, Printers... >! - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class testing::internal::FindFirstPrinter< T, E, Printers... >! - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class FindFirstPrinter< T, E, Printers... >! - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-cardinalities.cc:129: warning: documented symbol 'void testing::Cardinality::DescribeActualCallCountTo' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:248: warning: documented symbol 'bool testing::internal::MatchMatrix::NextGraph' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:262: warning: documented symbol 'void testing::internal::MatchMatrix::Randomize' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:271: warning: no uniquely matching class member found for - std::string testing::internal::MatchMatrix::DebugString() const - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:284: warning: documented symbol 'void testing::internal::UnorderedElementsAreMatcherImplBase::DescribeToImpl' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:325: warning: documented symbol 'void testing::internal::UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:371: warning: documented symbol 'bool testing::internal::UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:421: warning: documented symbol 'bool testing::internal::UnorderedElementsAreMatcherImplBase::FindPairing' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:82: warning: documented symbol 'testing::internal::ExpectationBase::ExpectationBase' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:98: warning: documented symbol 'testing::internal::ExpectationBase::~ExpectationBase' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:102: warning: documented symbol 'void testing::internal::ExpectationBase::SpecifyCardinality' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:108: warning: documented symbol 'void testing::internal::ExpectationBase::RetireAllPreRequisites' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:135: warning: documented symbol 'bool testing::internal::ExpectationBase::AllPrerequisitesAreSatisfied' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:155: warning: documented symbol 'void testing::internal::ExpectationBase::FindUnsatisfiedPrerequisites' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:186: warning: documented symbol 'void testing::internal::ExpectationBase::DescribeCallCountTo' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:209: warning: documented symbol 'void testing::internal::ExpectationBase::CheckActionCountIfNotDone' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:261: warning: documented symbol 'void testing::internal::ExpectationBase::UntypedTimes' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:308: warning: documented symbol 'testing::internal::UntypedFunctionMockerBase::UntypedFunctionMockerBase' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:311: warning: documented symbol 'testing::internal::UntypedFunctionMockerBase::~UntypedFunctionMockerBase' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:317: warning: documented symbol 'void testing::internal::UntypedFunctionMockerBase::RegisterOwner' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:329: warning: documented symbol 'void testing::internal::UntypedFunctionMockerBase::SetOwnerAndName' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:341: warning: documented symbol 'const void * testing::internal::UntypedFunctionMockerBase::MockObject' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:358: warning: documented symbol 'const char * testing::internal::UntypedFunctionMockerBase::Name' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:376: warning: documented symbol 'UntypedActionResultHolderBase * testing::internal::UntypedFunctionMockerBase::UntypedInvokeWith' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:505: warning: documented symbol 'Expectation testing::internal::UntypedFunctionMockerBase::GetHandleOf' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:525: warning: documented symbol 'bool testing::internal::UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:685: warning: documented symbol 'void Mock::AllowUninterestingCalls' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:692: warning: documented symbol 'void Mock::WarnUninterestingCalls' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:699: warning: documented symbol 'void Mock::FailUninterestingCalls' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:706: warning: documented symbol 'void Mock::UnregisterCallReaction' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:714: warning: documented symbol 'internal::CallReaction Mock::GetReactionOnUninterestingCalls' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:726: warning: documented symbol 'void Mock::AllowLeak' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:735: warning: documented symbol 'bool Mock::VerifyAndClearExpectations' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:744: warning: documented symbol 'bool Mock::VerifyAndClear' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:754: warning: documented symbol 'bool Mock::VerifyAndClearExpectationsLocked' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:779: warning: documented symbol 'bool Mock::IsNaggy' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:783: warning: documented symbol 'bool Mock::IsNice' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:787: warning: documented symbol 'bool Mock::IsStrict' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:793: warning: no uniquely matching class member found for - void Mock::Register(const void *mock_obj, internal::UntypedFunctionMockerBase *mocker) - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:803: warning: documented symbol 'void Mock::RegisterUseByOnCallOrExpectCall' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:824: warning: documented symbol 'void Mock::UnregisterLocked' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:842: warning: documented symbol 'void Mock::ClearDefaultActionsLocked' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:864: warning: documented symbol 'testing::Expectation::Expectation' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:866: warning: documented symbol 'testing::Expectation::Expectation' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:870: warning: documented symbol 'testing::Expectation::~Expectation' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:873: warning: documented symbol 'void testing::Sequence::AddExpectation' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:884: warning: documented symbol 'testing::InSequence::InSequence' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:895: warning: documented symbol 'testing::InSequence::~InSequence' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:111: warning: no matching file member found for -std::string testing::PrintToString(const T &value) +warning: source 'images' is not a readable file or directory... skipping. +d:/PlatformIO/linear-algebra/Quaternion.cpp:100: warning: no uniquely matching class member found for + Quaternion Quaternion::operator*(const Quaternion &r2) const Possible candidates: - '::std::string PrintToString(const T &value)' at line 1037 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:160: warning: no matching file member found for -testing::internal::GTEST_DISABLE_MSC_WARNINGS_PUSH_ + 'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(const AngleOf< T > &angle, float factor)' at line 117 of file d:/PlatformIO/linear-algebra/Angle.h + 'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(float factor, const AngleOf< T > &angle)' at line 124 of file d:/PlatformIO/linear-algebra/Angle.h + 'Vector3 Passer::LinearAlgebra::MatrixOf< T >::operator*(const Vector3 v) const' at line 64 of file d:/PlatformIO/linear-algebra/Matrix.h + 'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(const PolarOf &v, float f)' at line 118 of file d:/PlatformIO/linear-algebra/Polar.h + 'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(float f, const PolarOf &v)' at line 121 of file d:/PlatformIO/linear-algebra/Polar.h + 'Vector3 Passer::LinearAlgebra::Quaternion::operator*(const Vector3 &vector) const' at line 98 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'Quaternion Passer::LinearAlgebra::Quaternion::operator*(const Quaternion &rotation) const' at line 106 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(const SphericalOf< T > &v, float f)' at line 111 of file d:/PlatformIO/linear-algebra/Spherical.h + 'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(float f, const SphericalOf< T > &v)' at line 114 of file d:/PlatformIO/linear-algebra/Spherical.h + 'SphericalOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SphericalOf< T > &vector) const' at line 46 of file d:/PlatformIO/linear-algebra/SwingTwist.h + 'SwingTwistOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SwingTwistOf< T > &rotation) const' at line 54 of file d:/PlatformIO/linear-algebra/SwingTwist.h + 'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(const Vector2 &v, float f)' at line 141 of file d:/PlatformIO/linear-algebra/Vector2.h + 'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(float f, const Vector2 &v)' at line 144 of file d:/PlatformIO/linear-algebra/Vector2.h + 'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(const Vector3 &v, float f)' at line 149 of file d:/PlatformIO/linear-algebra/Vector3.h + 'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(float f, const Vector3 &v)' at line 152 of file d:/PlatformIO/linear-algebra/Vector3.h +d:/PlatformIO/linear-algebra/Quaternion.cpp:108: warning: no uniquely matching class member found for + Vector3 Quaternion::operator*(const Vector3 &p) const Possible candidates: - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 48 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-cardinalities.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 GMOCK_MAYBE_5046_) namespace testing' at line 283 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-matchers.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 84 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-spec-builders.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 GTEST_MAYBE_5046_) namespace testing' at line 59 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 38 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-spi.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 42 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-test-part.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) GTEST_DECLARE_bool_(also_run_disabled_tests)' at line 72 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) class GTEST_API_ DeathTest' at line 60 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-death-test-internal.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 47 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-filepath.h - 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) GTEST_DECLARE_bool_(death_test_use_fork)' at line 64 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-internal-inl.h - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-assertion-result.cc:59: warning: documented symbol 'AssertionResult testing::AssertionResult::operator!' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:373: warning: documented symbol 'testing::internal::DeathTest::DeathTest' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:383: warning: no matching class member found for - bool testing::internal::DeathTest::Create(const char *statement, Matcher< const std::string & > matcher, const char *file, int line, DeathTest **test) - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:390: warning: documented symbol 'const char * testing::internal::DeathTest::LastMessage' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:394: warning: documented symbol 'void testing::internal::DeathTest::set_last_death_test_message' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:398: warning: documented symbol 'std::string testing::internal::DeathTest::last_death_test_message_' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:94: warning: documented symbol 'FilePath testing::internal::FilePath::GetCurrentDir' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:121: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveExtension' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:133: warning: documented symbol 'const char * testing::internal::FilePath::FindLastPathSeparator' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:152: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveDirectoryName' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:163: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveFileName' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:180: warning: documented symbol 'FilePath testing::internal::FilePath::MakeFileName' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:196: warning: documented symbol 'FilePath testing::internal::FilePath::ConcatPaths' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:206: warning: documented symbol 'bool testing::internal::FilePath::FileOrDirectoryExists' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:220: warning: documented symbol 'bool testing::internal::FilePath::DirectoryExists' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:250: warning: documented symbol 'bool testing::internal::FilePath::IsRootDirectory' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:259: warning: documented symbol 'bool testing::internal::FilePath::IsAbsolutePath' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:280: warning: documented symbol 'FilePath testing::internal::FilePath::GenerateUniqueFileName' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:294: warning: documented symbol 'bool testing::internal::FilePath::IsDirectory' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:302: warning: documented symbol 'bool testing::internal::FilePath::CreateDirectoriesRecursively' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:319: warning: documented symbol 'bool testing::internal::FilePath::CreateFolder' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:343: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveTrailingPathSeparator' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:352: warning: no uniquely matching class member found for - void testing::internal::FilePath::Normalize() - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:45: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:49: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:55: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:59: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:64: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:70: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:76: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:82: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:86: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:92: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-port.cc:301: warning: no matching class member found for - void testing::internal::AutoHandle::Reset(HANDLE handle) + 'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(const AngleOf< T > &angle, float factor)' at line 117 of file d:/PlatformIO/linear-algebra/Angle.h + 'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(float factor, const AngleOf< T > &angle)' at line 124 of file d:/PlatformIO/linear-algebra/Angle.h + 'Vector3 Passer::LinearAlgebra::MatrixOf< T >::operator*(const Vector3 v) const' at line 64 of file d:/PlatformIO/linear-algebra/Matrix.h + 'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(const PolarOf &v, float f)' at line 118 of file d:/PlatformIO/linear-algebra/Polar.h + 'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(float f, const PolarOf &v)' at line 121 of file d:/PlatformIO/linear-algebra/Polar.h + 'Vector3 Passer::LinearAlgebra::Quaternion::operator*(const Vector3 &vector) const' at line 98 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'Quaternion Passer::LinearAlgebra::Quaternion::operator*(const Quaternion &rotation) const' at line 106 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(const SphericalOf< T > &v, float f)' at line 111 of file d:/PlatformIO/linear-algebra/Spherical.h + 'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(float f, const SphericalOf< T > &v)' at line 114 of file d:/PlatformIO/linear-algebra/Spherical.h + 'SphericalOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SphericalOf< T > &vector) const' at line 46 of file d:/PlatformIO/linear-algebra/SwingTwist.h + 'SwingTwistOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SwingTwistOf< T > &rotation) const' at line 54 of file d:/PlatformIO/linear-algebra/SwingTwist.h + 'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(const Vector2 &v, float f)' at line 141 of file d:/PlatformIO/linear-algebra/Vector2.h + 'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(float f, const Vector2 &v)' at line 144 of file d:/PlatformIO/linear-algebra/Vector2.h + 'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(const Vector3 &v, float f)' at line 149 of file d:/PlatformIO/linear-algebra/Vector3.h + 'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(float f, const Vector3 &v)' at line 152 of file d:/PlatformIO/linear-algebra/Vector3.h +d:/PlatformIO/linear-algebra/Quaternion.cpp:152: warning: no uniquely matching class member found for + Quaternion Quaternion::LookRotation(const Vector3 &forward, const Vector3 &up) Possible candidates: - 'void testing::internal::AutoHandle::Reset()' - 'void testing::internal::AutoHandle::Reset(Handle handle)' - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:44: warning: documented symbol 'std::string testing::TestPartResult::ExtractSummary' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:66: warning: no uniquely matching class member found for - void testing::TestPartResultArray::Append(const TestPartResult &result) - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:71: warning: no matching class member found for - const TestPartResult & testing::TestPartResultArray::GetTestPartResult(int index) const - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:81: warning: no uniquely matching class member found for - int testing::TestPartResultArray::size() const - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:87: warning: documented symbol 'testing::internal::HasNewFatalFailureHelper::HasNewFatalFailureHelper' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:94: warning: documented symbol 'testing::internal::HasNewFatalFailureHelper::~HasNewFatalFailureHelper' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:99: warning: no uniquely matching class member found for - void testing::internal::HasNewFatalFailureHelper::ReportTestPartResult(const TestPartResult &result) - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-typed-test.cc:58: warning: documented symbol 'const char * testing::internal::TypedTestSuitePState::VerifyRegisteredTestNames' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:858: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:868: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:875: warning: no uniquely matching class member found for - void testing::ScopedFakeTestPartResultReporter::Init() - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:888: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:899: warning: no uniquely matching class member found for - void testing::ScopedFakeTestPartResultReporter::ReportTestPartResult(const TestPartResult &result) - -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:965: warning: documented symbol 'testing::internal::SingleFailureChecker::SingleFailureChecker' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:974: warning: documented symbol 'testing::internal::SingleFailureChecker::~SingleFailureChecker' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:2602: warning: documented symbol 'testing::internal::GoogleTestFailureException::GoogleTestFailureException' was not declared or defined. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:52: warning: explicit link request to 'testing::AssertionResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:229: warning: explicit link request to 'Bar()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:283: warning: explicit link request to 'testing::Environment' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:283: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:376: warning: explicit link request to 'testing::PrintToString(x)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:786: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:813: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:850: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:953: warning: explicit link request to 'testing::Environment' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:970: warning: explicit link request to 'testing::AddGlobalTestEnvironment()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1243: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1364: warning: explicit link request to 'testing::Types' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1397: warning: explicit link request to 'including' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1496: warning: explicit link request to 'including' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1538: warning: explicit link request to 'testing::RegisterTest' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1764: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1813: warning: found at different nesting level (5) than expected (2) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1822: warning: found tag while expecting -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1823: warning: found tag while expecting -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1824: warning: found tag while expecting -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1986: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1986: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1987: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1987: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1988: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1988: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1989: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1989: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1990: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1990: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1991: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1991: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1992: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1992: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1994: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1994: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1996: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1996: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1997: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1997: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1998: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1998: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1999: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1999: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2000: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2000: warning: Unsupported xml/html tag found -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2380: warning: end of comment block while expecting command -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/faq.md:658: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cheat_sheet.md:6: warning: found subsection command (id: 'MockClass') outside of section context! -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:9: warning: explicit link request to 'testing::Foo' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:186: warning: found subsection command (id: 'MockingNonVirtualMethods') outside of section context! -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:1540: warning: explicit link request to 'Set()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:1950: warning: explicit link request to 'testing::ActionInterface' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2045: warning: explicit link request to 'testing::InSequence' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2098: warning: explicit link request to 'testing::DefaultValue' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2223: warning: explicit link request to 'testing::Invoke' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2309: warning: explicit link request to 'testing::InvokeWithoutArgs' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:4107: warning: explicit link request to 'testing::ActionInterface' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_for_dummies.md:524: warning: found subsection command (id: 'MultiExpectations') outside of section context! -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/primer.md:213: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/primer.md:457: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/actions.md:5: warning: explicit link request to 'testing' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/assertions.md:529: warning: explicit link request to 'testing::GTEST_FLAG(death_test_style)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/matchers.md:20: warning: explicit link request to 'testing' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/matchers.md:145: warning: explicit link request to 'std::tuple' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:92: warning: explicit link request to 'EXPECT_CALL.With' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:122: warning: explicit link request to 'EXPECT_CALL.Times' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:129: warning: explicit link request to 'testing' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:151: warning: explicit link request to 'EXPECT_CALL.InSequence' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:181: warning: explicit link request to 'EXPECT_CALL.After' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:222: warning: explicit link request to 'EXPECT_CALL.WillOnce' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:253: warning: explicit link request to 'EXPECT_CALL.WillRepeatedly' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:286: warning: explicit link request to 'EXPECT_CALL.RetiresOnSaturation' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:347: warning: explicit link request to 'ON_CALL.With' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:378: warning: explicit link request to 'ON_CALL.WillByDefault' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:413: warning: explicit link request to 'testing::DefaultValue' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:437: warning: explicit link request to 'testing::NiceMock' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:468: warning: explicit link request to 'testing::NaggyMock' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:495: warning: explicit link request to 'testing::StrictMock' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:527: warning: explicit link request to 'testing::Sequence' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:534: warning: explicit link request to 'testing::InSequence' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:559: warning: explicit link request to 'testing::Expectation' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:574: warning: explicit link request to 'testing::ExpectationSet' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:13: warning: found subsection command (id: 'TEST') outside of section context! -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:100: warning: explicit link request to 'testing' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:389: warning: explicit link request to 'testing::AssertionResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:403: warning: explicit link request to 'testing::AssertionException' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:410: warning: explicit link request to 'testing::EmptyTestEventListener' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:418: warning: explicit link request to 'testing::Environment' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:425: warning: explicit link request to 'Environment::SetUp' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:431: warning: explicit link request to 'Environment::TearDown' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:439: warning: explicit link request to 'testing::ScopedTrace' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:466: warning: explicit link request to 'testing::Test' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:472: warning: explicit link request to 'Test::SetUpTestSuite' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:479: warning: explicit link request to 'Test::TearDownTestSuite' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:486: warning: explicit link request to 'Test::HasFatalFailure' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:492: warning: explicit link request to 'Test::HasNonfatalFailure' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:498: warning: explicit link request to 'Test::HasFailure' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:505: warning: explicit link request to 'Test::IsSkipped' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:511: warning: explicit link request to 'Test::RecordProperty' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:538: warning: explicit link request to 'Test::SetUp' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:545: warning: explicit link request to 'Test::TearDown' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:554: warning: explicit link request to 'testing::TestWithParam' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:565: warning: explicit link request to 'TestSuite::name' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:571: warning: explicit link request to 'TestSuite::type_param' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:579: warning: explicit link request to 'TestSuite::should_run' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:585: warning: explicit link request to 'TestSuite::successful_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:591: warning: explicit link request to 'TestSuite::skipped_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:597: warning: explicit link request to 'TestSuite::failed_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:603: warning: explicit link request to 'TestSuite::reportable_disabled_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:609: warning: explicit link request to 'TestSuite::disabled_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:615: warning: explicit link request to 'TestSuite::reportable_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:621: warning: explicit link request to 'TestSuite::test_to_run_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:627: warning: explicit link request to 'TestSuite::total_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:633: warning: explicit link request to 'TestSuite::Passed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:639: warning: explicit link request to 'TestSuite::Failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:645: warning: explicit link request to 'TestSuite::elapsed_time' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:651: warning: explicit link request to 'TestSuite::start_timestamp' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:657: warning: explicit link request to 'TestSuite::GetTestInfo' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:665: warning: explicit link request to 'TestSuite::ad_hoc_test_result' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:674: warning: explicit link request to 'testing::TestInfo' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:680: warning: explicit link request to 'TestInfo::test_suite_name' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:686: warning: explicit link request to 'TestInfo::name' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:692: warning: explicit link request to 'TestInfo::type_param' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:700: warning: explicit link request to 'TestInfo::value_param' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:708: warning: explicit link request to 'TestInfo::file' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:714: warning: explicit link request to 'TestInfo::line' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:720: warning: explicit link request to 'TestInfo::is_in_another_shard' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:726: warning: explicit link request to 'TestInfo::should_run' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:739: warning: explicit link request to 'TestInfo::is_reportable' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:745: warning: explicit link request to 'TestInfo::result' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:753: warning: explicit link request to 'testing::TestParamInfo' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:763: warning: explicit link request to 'testing::UnitTest' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:774: warning: explicit link request to 'UnitTest::GetInstance' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:782: warning: explicit link request to 'UnitTest::original_working_dir' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:789: warning: explicit link request to 'UnitTest::current_test_suite' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:796: warning: explicit link request to 'UnitTest::current_test_info' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:803: warning: explicit link request to 'UnitTest::random_seed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:809: warning: explicit link request to 'UnitTest::successful_test_suite_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:815: warning: explicit link request to 'UnitTest::failed_test_suite_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:821: warning: explicit link request to 'UnitTest::total_test_suite_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:827: warning: explicit link request to 'UnitTest::test_suite_to_run_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:834: warning: explicit link request to 'UnitTest::successful_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:840: warning: explicit link request to 'UnitTest::skipped_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:846: warning: explicit link request to 'UnitTest::failed_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:852: warning: explicit link request to 'UnitTest::reportable_disabled_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:858: warning: explicit link request to 'UnitTest::disabled_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:864: warning: explicit link request to 'UnitTest::reportable_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:870: warning: explicit link request to 'UnitTest::total_test_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:876: warning: explicit link request to 'UnitTest::test_to_run_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:882: warning: explicit link request to 'UnitTest::start_timestamp' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:888: warning: explicit link request to 'UnitTest::elapsed_time' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:894: warning: explicit link request to 'UnitTest::Passed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:900: warning: explicit link request to 'UnitTest::Failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:907: warning: explicit link request to 'UnitTest::GetTestSuite' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:915: warning: explicit link request to 'UnitTest::ad_hoc_test_result' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:922: warning: explicit link request to 'UnitTest::listeners' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:931: warning: explicit link request to 'testing::TestEventListener' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:938: warning: explicit link request to 'TestEventListener::OnTestProgramStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:944: warning: explicit link request to 'TestEventListener::OnTestIterationStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:953: warning: explicit link request to 'TestEventListener::OnEnvironmentsSetUpStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:960: warning: explicit link request to 'TestEventListener::OnEnvironmentsSetUpEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:967: warning: explicit link request to 'TestEventListener::OnTestSuiteStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:973: warning: explicit link request to 'TestEventListener::OnTestStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:979: warning: explicit link request to 'TestEventListener::OnTestPartResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:988: warning: explicit link request to 'TestEventListener::OnTestEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:994: warning: explicit link request to 'TestEventListener::OnTestSuiteEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1000: warning: explicit link request to 'TestEventListener::OnEnvironmentsTearDownStart' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1007: warning: explicit link request to 'TestEventListener::OnEnvironmentsTearDownEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1014: warning: explicit link request to 'TestEventListener::OnTestIterationEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1021: warning: explicit link request to 'TestEventListener::OnTestProgramEnd' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1029: warning: explicit link request to 'testing::TestEventListeners' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1035: warning: explicit link request to 'TestEventListeners::Append' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1043: warning: explicit link request to 'TestEventListeners::Release' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1051: warning: explicit link request to 'TestEventListeners::default_result_printer' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1061: warning: explicit link request to 'TestEventListeners::default_xml_generator' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1074: warning: explicit link request to 'testing::TestPartResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1081: warning: explicit link request to 'TestPartResult::type' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1098: warning: explicit link request to 'TestPartResult::file_name' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1105: warning: explicit link request to 'TestPartResult::line_number' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1112: warning: explicit link request to 'TestPartResult::summary' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1118: warning: explicit link request to 'TestPartResult::message' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1124: warning: explicit link request to 'TestPartResult::skipped' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1130: warning: explicit link request to 'TestPartResult::passed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1136: warning: explicit link request to 'TestPartResult::nonfatally_failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1142: warning: explicit link request to 'TestPartResult::fatally_failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1148: warning: explicit link request to 'TestPartResult::failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1156: warning: explicit link request to 'testing::TestProperty' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1183: warning: explicit link request to 'testing::TestResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1191: warning: explicit link request to 'TestResult::total_part_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1198: warning: explicit link request to 'TestResult::test_property_count' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1204: warning: explicit link request to 'TestResult::Passed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1210: warning: explicit link request to 'TestResult::Skipped' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1216: warning: explicit link request to 'TestResult::Failed' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1222: warning: explicit link request to 'TestResult::HasFatalFailure' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1228: warning: explicit link request to 'TestResult::HasNonfatalFailure' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1234: warning: explicit link request to 'TestResult::elapsed_time' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1240: warning: explicit link request to 'TestResult::start_timestamp' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1246: warning: explicit link request to 'TestResult::GetTestPartResult' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1254: warning: explicit link request to 'TestResult::GetTestProperty' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1264: warning: explicit link request to 'testing::TimeInMillis' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1270: warning: explicit link request to 'testing::Types' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1286: warning: explicit link request to 'testing::WithParamInterface' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1312: warning: explicit link request to 'testing::InitGoogleTest(int* argc, char** argv)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1313: warning: explicit link request to 'testing::InitGoogleTest(int* argc, wchar_t** argv)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1314: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1331: warning: explicit link request to 'testing::AddGlobalTestEnvironment(Environment* env)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1383: warning: explicit link request to 'testing::AssertionSuccess()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1390: warning: explicit link request to 'testing::AssertionFailure()' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1403: warning: explicit link request to 'testing::StaticAssertTypeEq' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1412: warning: explicit link request to 'testing::PrintToString(x)' could not be resolved -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1422: warning: explicit link request to 'testing::PrintToStringParamName' could not be resolved -D:/C/VectorAlgebra/include/Vector2.h:233: warning: Member ToFactor(Vector2 a, Vector2 b) (function) of struct Vector2 is not documented. -D:/C/VectorAlgebra/include/Vector2.h:205: warning: argument 'axis' of command @param is not found in the argument list of Vector2::SignedAngle(Vector2 from, Vector2 to) -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:119: warning: Member testCatchesCxxExceptionsInFixtureConstructor(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:133: warning: Member testCatchesCxxExceptionsInFixtureDestructor(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:143: warning: Member testCatchesCxxExceptionsInSetUpTestCase(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:166: warning: Member testCatchesCxxExceptionsInTearDownTestCase(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:171: warning: Member testCatchesCxxExceptionsInSetUp(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:189: warning: Member testCatchesCxxExceptionsInTearDown(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:200: warning: Member testCatchesCxxExceptionsInTestBody(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:214: warning: Member testCatchesNonStdCxxExceptions(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:219: warning: Member testUnhandledCxxExceptionsAbortTheProgram(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:85: warning: Member TestSehExceptions(self, test_output) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:103: warning: Member testCatchesSehExceptionsWithCxxExceptionsEnabled(self) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:106: warning: Member testCatchesSehExceptionsWithCxxExceptionsDisabled(self) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:122: warning: Member testGoogletestFlag(self) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:187: warning: Member testEventListener(self) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:214: warning: Member assertXmlResultCount(self, result, count, xml) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:220: warning: Member assertXmlStatusCount(self, status, count, xml) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-filter-unittest.py:517: warning: Member testNegativeFilters(self) (function) of class googletest-filter-unittest::GTestFilterUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:134: warning: Member setUp(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:142: warning: Member tearDown(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:145: warning: Member DeleteFilesAndDir(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:159: warning: Member testOutfile1(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:162: warning: Member testOutfile2(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:138: warning: Member output_dir_ (variable) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:170: warning: Member setUp(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:173: warning: Member testShufflePreservesNumberOfTests(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:179: warning: Member testShuffleChangesTestOrder(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:187: warning: Member testShuffleChangesTestCaseOrder(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:200: warning: Member testShuffleDoesNotRepeatTest(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:214: warning: Member testShuffleDoesNotCreateNewTest(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:224: warning: Member testShuffleIncludesAllTests(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:234: warning: Member testShuffleLeavesDeathTestsAtFront(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:253: warning: Member testShuffleDoesNotInterleaveTestCases(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:259: warning: Member testShuffleRestoresOrderAfterEachIteration(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:291: warning: Member testShuffleGeneratesNewOrderInEachIteration(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:303: warning: Member testShuffleShardedTestsPreservesPartition(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:140: warning: Member testPrintsHelpWithFullFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:143: warning: Member testPrintsHelpWithShortFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:146: warning: Member testPrintsHelpWithQuestionFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:149: warning: Member testPrintsHelpWithWindowsStyleQuestionFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:152: warning: Member testPrintsHelpWithUnrecognizedGoogleTestFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:155: warning: Member testPrintsHelpWithIncorrectFlagStyle(self) (function) of class gtest_help_test::GTestHelpTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:75: warning: Member setUp(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:83: warning: Member tearDown(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:86: warning: Member DeleteFilesAndDir(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:100: warning: Member testOutfile1(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:103: warning: Member testOutfile2(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:79: warning: Member output_dir_ (variable) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented. -D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_test_utils.py:103: warning: Member identifying_attribute (variable) of class gtest_xml_test_utils::GTestXMLTestCase is not documented. + 'static Quaternion Passer::LinearAlgebra::Quaternion::LookRotation(const Vector3 &forward, const Vector3 &upwards)' at line 132 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'static Quaternion Passer::LinearAlgebra::Quaternion::LookRotation(const Vector3 &forward)' at line 143 of file d:/PlatformIO/linear-algebra/Quaternion.h +d:/PlatformIO/linear-algebra/Quaternion.cpp:330: warning: no uniquely matching class member found for + Quaternion Quaternion::Euler(Vector3 euler) +Possible candidates: + 'static Quaternion Passer::LinearAlgebra::Quaternion::Euler(float x, float y, float z)' at line 215 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'static Quaternion Passer::LinearAlgebra::Quaternion::Euler(Vector3 eulerAngles)' at line 222 of file d:/PlatformIO/linear-algebra/Quaternion.h +d:/PlatformIO/linear-algebra/Quaternion.cpp:362: warning: no uniquely matching class member found for + Quaternion Quaternion::EulerXYZ(Vector3 euler) +Possible candidates: + 'static Quaternion Passer::LinearAlgebra::Quaternion::EulerXYZ(float x, float y, float z)' at line 232 of file d:/PlatformIO/linear-algebra/Quaternion.h + 'static Quaternion Passer::LinearAlgebra::Quaternion::EulerXYZ(Vector3 eulerAngles)' at line 239 of file d:/PlatformIO/linear-algebra/Quaternion.h +d:/PlatformIO/linear-algebra/Spherical.cpp:137: warning: no uniquely matching class member found for + template < T > + SphericalOf< T > SphericalOf::operator-(const SphericalOf< T > &s2) const +Possible candidates: + 'AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator-() const' at line 99 of file d:/PlatformIO/linear-algebra/Angle.h + 'AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator-(const AngleOf< T > &angle) const' at line 103 of file d:/PlatformIO/linear-algebra/Angle.h + 'DirectionOf< T > Passer::LinearAlgebra::DirectionOf< T >::operator-() const' at line 84 of file d:/PlatformIO/linear-algebra/Direction.h + 'PolarOf Passer::LinearAlgebra::PolarOf< T >::operator-() const' at line 100 of file d:/PlatformIO/linear-algebra/Polar.h + 'PolarOf Passer::LinearAlgebra::PolarOf< T >::operator-(const PolarOf &v) const' at line 105 of file d:/PlatformIO/linear-algebra/Polar.h + 'SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator-() const' at line 93 of file d:/PlatformIO/linear-algebra/Spherical.h + 'SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator-(const SphericalOf< T > &v) const' at line 98 of file d:/PlatformIO/linear-algebra/Spherical.h + 'Vector2 Passer::LinearAlgebra::Vector2::operator-()' at line 116 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Vector2 Passer::LinearAlgebra::Vector2::operator-(const Vector2 &v) const' at line 121 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Vector3 Passer::LinearAlgebra::Vector3::operator-() const' at line 124 of file d:/PlatformIO/linear-algebra/Vector3.h + 'Vector3 Passer::LinearAlgebra::Vector3::operator-(const Vector3 &v) const' at line 129 of file d:/PlatformIO/linear-algebra/Vector3.h +d:/PlatformIO/linear-algebra/Vector2.cpp:20: warning: no uniquely matching class member found for + Vector2::Vector2(float _x, float _y) +Possible candidates: + 'Passer::LinearAlgebra::Vector2::Vector2()' at line 43 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(float right, float forward)' at line 47 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(Vector3 v)' at line 51 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(PolarOf< float > v)' at line 54 of file d:/PlatformIO/linear-algebra/Vector2.h +d:/PlatformIO/linear-algebra/Vector2.cpp:32: warning: no uniquely matching class member found for + Vector2::Vector2(PolarSingle p) +Possible candidates: + 'Passer::LinearAlgebra::Vector2::Vector2()' at line 43 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(float right, float forward)' at line 47 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(Vector3 v)' at line 51 of file d:/PlatformIO/linear-algebra/Vector2.h + 'Passer::LinearAlgebra::Vector2::Vector2(PolarOf< float > v)' at line 54 of file d:/PlatformIO/linear-algebra/Vector2.h +d:/PlatformIO/linear-algebra/Vector3.cpp:33: warning: no uniquely matching class member found for + Vector3::Vector3(SphericalOf< float > s) +Possible candidates: + 'Passer::LinearAlgebra::Vector3::Vector3()' at line 47 of file d:/PlatformIO/linear-algebra/Vector3.h + 'Passer::LinearAlgebra::Vector3::Vector3(float right, float up, float forward)' at line 52 of file d:/PlatformIO/linear-algebra/Vector3.h + 'Passer::LinearAlgebra::Vector3::Vector3(Vector2 v)' at line 55 of file d:/PlatformIO/linear-algebra/Vector3.h + 'Passer::LinearAlgebra::Vector3::Vector3(SphericalOf< float > v)' at line 59 of file d:/PlatformIO/linear-algebra/Vector3.h +d:/PlatformIO/linear-algebra/Direction.h:43: warning: argument 'v' of command @param is not found in the argument list of Passer::LinearAlgebra::DirectionOf< T >::FromVector3(Vector3 vector) +d:/PlatformIO/linear-algebra/Direction.h:43: warning: The following parameter of Passer::LinearAlgebra::DirectionOf::FromVector3(Vector3 vector) is not documented: + parameter 'vector' +d:/PlatformIO/linear-algebra/Matrix.h:12: warning: Member MatrixOf(unsigned int rows, unsigned int cols) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:13: warning: Member MatrixOf(unsigned int rows, unsigned int cols, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:17: warning: Member MatrixOf(Vector3 v) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:59: warning: Member Multiply(const MatrixOf< T > *m, MatrixOf< T > *r) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:64: warning: Member operator*(const Vector3 v) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:66: warning: Member Get(unsigned int rowIx, unsigned int colIx) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:71: warning: Member Set(unsigned int rowIx, unsigned int colIx, T value) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:77: warning: Member Set(const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:84: warning: Member SetRow(unsigned int rowIx, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:91: warning: Member SetCol(unsigned int colIx, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:98: warning: Member CopyFrom(const MatrixOf< T > *m) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:108: warning: Member RowCount() const (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:109: warning: Member ColCount() const (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:57: warning: Member Multiply(const MatrixOf< T > *m1, const MatrixOf< T > *m2, MatrixOf< T > *r) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Matrix.h:63: warning: Member Multiply(const MatrixOf< T > *m, Vector3 v) (function) of class Passer::LinearAlgebra::MatrixOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:106: warning: Member operator-=(const PolarOf &v) (function) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:111: warning: Member operator+=(const PolarOf &v) (function) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:124: warning: Member operator*=(float f) (function) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:136: warning: Member operator/=(float f) (function) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:121: warning: Member operator*(float f, const PolarOf &v) (friend) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:133: warning: Member operator/(float f, const PolarOf &v) (friend) of class Passer::LinearAlgebra::PolarOf is not documented. +d:/PlatformIO/linear-algebra/Polar.h:59: warning: argument 's' of command @param is not found in the argument list of Passer::LinearAlgebra::PolarOf< T >::FromSpherical(SphericalOf< T > v) +d:/PlatformIO/linear-algebra/Polar.h:59: warning: The following parameter of Passer::LinearAlgebra::PolarOf::FromSpherical(SphericalOf< T > v) is not documented: + parameter 'v' +d:/PlatformIO/linear-algebra/Spherical.h:29: warning: Member SphericalOf(float distance, AngleOf< T > horizontal, AngleOf< T > vertical) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:29: warning: Member SphericalOf(float distance, DirectionOf< T > direction) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:99: warning: Member operator-=(const SphericalOf< T > &v) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:104: warning: Member operator+=(const SphericalOf< T > &v) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:117: warning: Member operator*=(float f) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:129: warning: Member operator/=(float f) (function) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:54: warning: Member Rad (variable) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:114: warning: Member operator*(float f, const SphericalOf< T > &v) (friend) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/Spherical.h:126: warning: Member operator/(float f, const SphericalOf< T > &v) (friend) of class Passer::LinearAlgebra::SphericalOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member SwingTwistOf(DirectionOf< T > swing, AngleOf< T > twist) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member SwingTwistOf(AngleOf< T > horizontal, AngleOf< T > vertical, AngleOf< T > twist) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:31: warning: Member ToQuaternion() const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:34: warning: Member ToAngleAxis() const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:39: warning: Member operator==(const SwingTwistOf< T > d) const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:55: warning: Member operator*=(const SwingTwistOf< T > &rotation) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:69: warning: Member Normalize() (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:28: warning: Member Degrees(float horizontal, float vertical=0, float twist=0) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:32: warning: Member FromQuaternion(Quaternion q) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:35: warning: Member FromAngleAxis(SphericalOf< T > aa) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:57: warning: Member Inverse(SwingTwistOf< T > rotation) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:67: warning: Member Angle(const SwingTwistOf< T > &r1, const SwingTwistOf< T > &r2) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:21: warning: Member swing (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member twist (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/SwingTwist.h:37: warning: Member identity (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:122: warning: Member operator-=(const Vector2 &v) (function) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:127: warning: Member operator+=(const Vector2 &v) (function) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:148: warning: Member operator*=(float f) (function) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:159: warning: Member operator/=(float f) (function) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:144: warning: Member operator*(float f, const Vector2 &v) (friend) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector2.h:156: warning: Member operator/(float f, const Vector2 &v) (friend) of struct Passer::LinearAlgebra::Vector2 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:82: warning: Member Forward() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:83: warning: Member Up() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:84: warning: Member Right() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:130: warning: Member operator-=(const Vector3 &v) (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:135: warning: Member operator+=(const Vector3 &v) (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:156: warning: Member operator*=(float f) (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:168: warning: Member operator/=(float f) (function) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:152: warning: Member operator*(float f, const Vector3 &v) (friend) of struct Passer::LinearAlgebra::Vector3 is not documented. +d:/PlatformIO/linear-algebra/Vector3.h:164: warning: Member operator/(float f, const Vector3 &v) (friend) of struct Passer::LinearAlgebra::Vector3 is not documented. diff --git a/DoxyGen/Doxyfile b/DoxyGen/Doxyfile index 8f5e552..e57d669 100644 --- a/DoxyGen/Doxyfile +++ b/DoxyGen/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.2 +# Doxyfile 1.9.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -32,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = VectorAlgebra +PROJECT_NAME = LinearAlgebra # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -58,18 +68,30 @@ PROJECT_LOGO = //intranet/home/Afbeeldingen/PasserVR/Logos/Logo3NameRi # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = //serrarens.nl/web/apis/VectorAlgebra +OUTPUT_DIRECTORY = //intranet/web/passer_life/apis/LinearAlgebra -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -341,6 +363,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 0 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -452,7 +485,7 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing @@ -465,6 +498,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -546,7 +587,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = YES @@ -577,14 +619,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = NO @@ -836,11 +879,26 @@ WARN_IF_INCOMPLETE_DOC = YES WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -851,13 +909,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = DoxyWarnLogfile.txt @@ -871,8 +943,7 @@ WARN_LOGFILE = DoxyWarnLogfile.txt # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../include \ - ../src \ +INPUT = .. \ ../README.md # This tag can be used to specify the character encoding of the source files @@ -880,10 +951,21 @@ INPUT = ../include \ # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -895,12 +977,12 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, -# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C -# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, +# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php, +# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be +# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -978,16 +1060,14 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = gtest* \ + googletest* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -1033,6 +1113,11 @@ IMAGE_PATH = images \ # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1074,6 +1159,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1211,10 +1305,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1293,7 +1388,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = custom_doxygen.css @@ -1308,6 +1408,19 @@ HTML_EXTRA_STYLESHEET = custom_doxygen.css HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see @@ -1338,15 +1451,6 @@ HTML_COLORSTYLE_SAT = 0 HTML_COLORSTYLE_GAMMA = 103 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1366,6 +1470,13 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1402,6 +1513,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1489,6 +1607,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1606,7 +1734,7 @@ GENERATE_TREEVIEW = NO # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the -# project logo, title, and description. If either GENERATOR_TREEVIEW or +# project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1637,6 +1765,13 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1657,17 +1792,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1981,9 +2105,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2004,14 +2135,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2177,7 +2300,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -2188,6 +2311,28 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to Sqlite3 output #--------------------------------------------------------------------------- +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if an a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2262,7 +2407,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2329,15 +2475,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2351,25 +2497,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2378,7 +2508,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2395,49 +2525,73 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2497,7 +2651,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2506,7 +2662,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2546,16 +2705,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2592,11 +2761,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2605,10 +2775,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2646,18 +2816,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2670,6 +2828,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2683,3 +2843,19 @@ GENERATE_LEGEND = YES # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/FloatSingle.cpp b/FloatSingle.cpp index fb6f301..902d85e 100644 --- a/FloatSingle.cpp +++ b/FloatSingle.cpp @@ -2,16 +2,18 @@ // License, v. 2.0.If a copy of the MPL was not distributed with this // file, You can obtain one at https ://mozilla.org/MPL/2.0/. -#include #include "FloatSingle.h" +#include const float Float::epsilon = 1e-05f; const float Float::sqrEpsilon = 1e-10f; float Float::Clamp(float f, float min, float max) { - if (f < min) - return min; - if (f > max) - return max; + if (max < min) return f; + if (f < min) + return min; + if (f > max) + return max; + return f; } \ No newline at end of file diff --git a/FloatSingle.h b/FloatSingle.h index 7aa2251..db3e06e 100644 --- a/FloatSingle.h +++ b/FloatSingle.h @@ -5,11 +5,18 @@ #ifndef FLOAT_H #define FLOAT_H -class Float { -public: - static const float epsilon; - static const float sqrEpsilon; +namespace LinearAlgebra { - static float Clamp(float f, float min, float max); +class Float { + public: + static const float epsilon; + static const float sqrEpsilon; + + static float Clamp(float f, float min, float max); }; + +} // namespace LinearAlgebra + +using namespace LinearAlgebra; + #endif diff --git a/Matrix.cpp b/Matrix.cpp index 7a67504..c7e53c7 100644 --- a/Matrix.cpp +++ b/Matrix.cpp @@ -1,6 +1,290 @@ #include "Matrix.h" +#if !defined(NO_STD) +#include +#endif -template <> MatrixOf::MatrixOf(unsigned int rows, unsigned int cols) { +namespace LinearAlgebra { + +#pragma region Matrix1 + +Matrix1::Matrix1(int size) : size(size) { + if (this->size == 0) + data = nullptr; + else { + this->data = new float[size](); + this->externalData = false; + } +} + +Matrix1::Matrix1(float* data, int size) : data(data), size(size) { + this->externalData = true; +} + +Matrix1 LinearAlgebra::Matrix1::FromQuaternion(Quaternion q) { + Matrix1 r = Matrix1(4); + float* data = r.data; + data[0] = q.x; + data[1] = q.y; + data[2] = q.z; + data[3] = q.w; + return r; +} + +Quaternion LinearAlgebra::Matrix1::ToQuaternion() { + return Quaternion(this->data[0], this->data[1], this->data[2], this->data[3]); +} + +// Matrix1 +#pragma endregion + +#pragma region Matrix2 + +Matrix2::Matrix2() {} + +Matrix2::Matrix2(int nRows, int nCols) : nRows(nRows), nCols(nCols) { + this->nValues = nRows * nCols; + if (this->nValues == 0) + this->data = nullptr; + else { + this->data = new float[this->nValues]; + this->externalData = false; + } +} + +Matrix2::Matrix2(float* data, int nRows, int nCols) + : nRows(nRows), nCols(nCols), data(data) { + this->nValues = nRows * nCols; + this->externalData = true; +} + +Matrix2::Matrix2(const Matrix2& m) + : nRows(m.nRows), nCols(m.nCols), nValues(m.nValues) { + if (this->nValues == 0) + this->data = nullptr; + else { + this->data = new float[this->nValues]; + + for (int ix = 0; ix < this->nValues; ++ix) + this->data[ix] = m.data[ix]; + } +} + +Matrix2& Matrix2::operator=(const Matrix2& m) { + if (this != &m) { + delete[] this->data; // Free the current memory + + this->nRows = m.nRows; + this->nCols = m.nCols; + this->nValues = m.nValues; + if (this->nValues == 0) + this->data = nullptr; + else { + this->data = new float[this->nValues]; + for (int ix = 0; ix < this->nValues; ++ix) + this->data[ix] = m.data[ix]; + } + } + return *this; +} + +Matrix2::~Matrix2() { + if (!this->externalData) + delete[] data; +} + +Matrix2 Matrix2::Clone() const { + Matrix2 r = Matrix2(this->nRows, this->nCols); + for (int ix = 0; ix < this->nValues; ++ix) + r.data[ix] = this->data[ix]; + return r; +} + +// Move constructor +Matrix2::Matrix2(Matrix2&& other) noexcept + : nRows(other.nRows), + nCols(other.nCols), + nValues(other.nValues), + data(other.data) { + other.data = nullptr; // Set the other object's pointer to nullptr to avoid + // double deletion +} + +// Move assignment operator +Matrix2& Matrix2::operator=(Matrix2&& other) noexcept { + if (this != &other) { + delete[] data; // Clean up current data + nRows = other.nRows; + nCols = other.nCols; + nValues = other.nValues; + data = other.data; + other.data = nullptr; // Avoid double deletion + } + return *this; +} + +Matrix2 Matrix2::Zero(int nRows, int nCols) { + Matrix2 r = Matrix2(nRows, nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = 0; + return r; +} + +void Matrix2::Clear() { + for (int ix = 0; ix < this->nValues; ix++) + this->data[ix] = 0; +} + +Matrix2 Matrix2::Identity(int size) { + return Diagonal(1, size); +} + +Matrix2 Matrix2::Diagonal(float f, int size) { + Matrix2 r = Matrix2::Zero(size, size); + float* data = r.data; + int valueIx = 0; + for (int ix = 0; ix < size; ix++) { + data[valueIx] = f; + valueIx += size + 1; + } + return r; +} + +Matrix2 Matrix2::SkewMatrix(const Vector3& v) { + Matrix2 r = Matrix2(3, 3); + float* data = r.data; + data[0 * 3 + 1] = -v.z; // result(0, 1) + data[0 * 3 + 2] = v.y; // result(0, 2) + data[1 * 3 + 0] = v.z; // result(1, 0) + data[1 * 3 + 2] = -v.x; // result(1, 2) + data[2 * 3 + 0] = -v.y; // result(2, 0) + data[2 * 3 + 1] = v.x; // result(2, 1) + return r; +} + +Matrix2 Matrix2::Transpose() const { + Matrix2 r = Matrix2(this->nCols, this->nRows); + + for (int rowIx = 0; rowIx < this->nRows; rowIx++) { + for (int colIx = 0; colIx < this->nCols; colIx++) + r.data[colIx * this->nCols + rowIx] = + this->data[rowIx * this->nCols + colIx]; + } + return r; +} + +Matrix2 LinearAlgebra::Matrix2::operator-() const { + Matrix2 r = Matrix2(this->nRows, this->nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = -this->data[ix]; + return r; +} + +Matrix2 LinearAlgebra::Matrix2::operator+(const Matrix2& v) const { + Matrix2 r = Matrix2(this->nRows, this->nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = this->data[ix] + v.data[ix]; + return r; +} + +Matrix2 Matrix2::operator+=(const Matrix2& v) { + for (int ix = 0; ix < this->nValues; ix++) + this->data[ix] += v.data[ix]; + return *this; +} + +Matrix2 LinearAlgebra::Matrix2::operator*(const Matrix2& B) const { + Matrix2 r = Matrix2(this->nRows, B.nCols); + + int ACols = this->nCols; + int BCols = B.nCols; + int ARows = this->nRows; + // int BRows = B.nRows; + + for (int i = 0; i < ARows; ++i) { + // Pre-compute row offsets + int ARowOffset = i * ACols; // ARowOffset is constant for each row of A + int BColOffset = i * BCols; // BColOffset is constant for each row of B + for (int j = 0; j < BCols; ++j) { + float sum = 0; + std::cout << " 0"; + int BIndex = j; + for (int k = 0; k < ACols; ++k) { + std::cout << " + " << this->data[ARowOffset + k] << " * " + << B.data[BIndex]; + sum += this->data[ARowOffset + k] * B.data[BIndex]; + BIndex += BCols; + } + r.data[BColOffset + j] = sum; + std::cout << " = " << sum << " ix: " << BColOffset + j << "\n"; + } + } + return r; +} + +Matrix2 Matrix2::Slice(int rowStart, int rowStop, int colStart, int colStop) { + Matrix2 r = Matrix2(rowStop - rowStart, colStop - colStart); + + int resultRowIx = 0; + int resultColIx = 0; + for (int i = rowStart; i < rowStop; i++) { + for (int j = colStart; j < colStop; j++) + r.data[resultRowIx * r.nCols + resultColIx] = + this->data[i * this->nCols + j]; + } + return r; +} + +void Matrix2::UpdateSlice(int rowStart, + int rowStop, + int colStart, + int colStop, + const Matrix2& m) const { + // for (int i = rowStart; i < rowStop; i++) { + // for (int j = colStart; j < colStop; j++) + // this->data[i * this->nCols + j] = + // m.data[(i - rowStart) * m.nCols + (j - colStart)]; + // } + + int rRowDataIx = rowStart * this->nCols; + int mRowDataIx = 0; + for (int rowIx = rowStart; rowIx < rowStop; rowIx++) { + rRowDataIx = rowIx * this->nCols; + // rRowDataIx += this->nCols; + mRowDataIx += m.nCols; + for (int colIx = colStart; colIx < colStop; colIx++) { + this->data[rRowDataIx + colIx] = m.data[mRowDataIx + (colIx - colStart)]; + } + } +} + +/// @brief Compute the Omega matrix of a 3D vector +/// @param v The vector +/// @return 4x4 Omega matrix +Matrix2 LinearAlgebra::Matrix2::Omega(const Vector3& v) { + Matrix2 r = Matrix2::Zero(4, 4); + r.UpdateSlice(0, 3, 0, 3, -Matrix2::SkewMatrix(v)); + + // set last row to -v + int ix = 3 * 4; + r.data[ix++] = -v.x; + r.data[ix++] = -v.y; + r.data[ix] = -v.z; + + // Set last column to v + ix = 3; + r.data[ix += 4] = v.x; + r.data[ix += 4] = v.y; + r.data[ix] = v.z; + return r; +} + +// Matrix2 +#pragma endregion + +} // namespace LinearAlgebra + +template <> +MatrixOf::MatrixOf(unsigned int rows, unsigned int cols) { if (rows <= 0 || cols <= 0) { this->rows = 0; this->cols = 0; @@ -14,20 +298,22 @@ template <> MatrixOf::MatrixOf(unsigned int rows, unsigned int cols) { this->data = new float[matrixSize]{0.0f}; } -template <> MatrixOf::MatrixOf(Vector3 v) : MatrixOf(3, 1) { - Set(0, 0, v.x); - Set(1, 0, v.y); - Set(2, 0, v.z); +template <> +MatrixOf::MatrixOf(Vector3 v) : MatrixOf(3, 1) { + Set(0, 0, v.Right()); + Set(1, 0, v.Up()); + Set(2, 0, v.Forward()); } template <> -void MatrixOf::Multiply(const MatrixOf *m1, - const MatrixOf *m2, MatrixOf *r) { +void MatrixOf::Multiply(const MatrixOf* m1, + const MatrixOf* m2, + MatrixOf* r) { for (unsigned int rowIx1 = 0; rowIx1 < m1->rows; rowIx1++) { for (unsigned int colIx2 = 0; colIx2 < m2->cols; colIx2++) { unsigned int rDataIx = colIx2 * m2->cols + rowIx1; r->data[rDataIx] = 0.0F; - for (int kIx = 0; kIx < m2->rows; kIx++) { + for (unsigned int kIx = 0; kIx < m2->rows; kIx++) { unsigned int dataIx1 = rowIx1 * m1->cols + kIx; unsigned int dataIx2 = kIx * m2->cols + colIx2; r->data[rDataIx] += m1->data[dataIx1] * m2->data[dataIx2]; @@ -37,7 +323,7 @@ void MatrixOf::Multiply(const MatrixOf *m1, } template <> -Vector3 MatrixOf::Multiply(const MatrixOf *m, Vector3 v) { +Vector3 MatrixOf::Multiply(const MatrixOf* m, Vector3 v) { MatrixOf v_m = MatrixOf(v); MatrixOf r_m = MatrixOf(3, 1); @@ -47,10 +333,11 @@ Vector3 MatrixOf::Multiply(const MatrixOf *m, Vector3 v) { return r; } -template Vector3 MatrixOf::operator*(const Vector3 v) const { - float *vData = new float[3]{v.x, v.y, v.z}; +template +Vector3 MatrixOf::operator*(const Vector3 v) const { + float* vData = new float[3]{v.Right(), v.Up(), v.Forward()}; MatrixOf v_m = MatrixOf(3, 1, vData); - float *rData = new float[3]{}; + float* rData = new float[3]{}; MatrixOf r_m = MatrixOf(3, 1, rData); Multiply(this, &v_m, &r_m); diff --git a/Matrix.h b/Matrix.h index 5ef0588..ef72922 100644 --- a/Matrix.h +++ b/Matrix.h @@ -1,17 +1,129 @@ #ifndef MATRIX_H #define MATRIX_H +#include "Quaternion.h" #include "Vector3.h" +namespace LinearAlgebra { + +/// @brief A 1-dimensional matrix or vector of arbitrary size +class Matrix1 { + public: + float* data = nullptr; + int size = 0; + + Matrix1(int size); + Matrix1(float* data, int size); + + static Matrix1 FromQuaternion(Quaternion q); + Quaternion ToQuaternion(); + + private: + bool externalData = true; +}; + +/// @brief A 2-dimensional matrix of arbitrary size +class Matrix2 { + public: + int nRows = 0; + int nCols = 0; + int nValues = 0; + float* data = nullptr; + + Matrix2(); + Matrix2(int nRows, int nCols); + Matrix2(float* data, int nRows, int nCols); + Matrix2(const Matrix2& m); + Matrix2& operator=(const Matrix2& other); + + ~Matrix2(); + + Matrix2 Clone() const; + + static Matrix2 Zero(int nRows, int nCols); + void Clear(); + + static Matrix2 Identity(int size); + + static Matrix2 Diagonal(float f, int size); + + static Matrix2 SkewMatrix(const Vector3& v); + + Matrix2 Transpose() const; + + Matrix2 operator-() const; + + /// @brief Add a matrix to this matrix + /// @param m The matrix to add to this matrix + /// @return The result of the addition + Matrix2 operator+(const Matrix2& v) const; + Matrix2 operator+=(const Matrix2& v); + + Matrix2 operator*(const Matrix2& m) const; + friend Matrix2 operator*(const Matrix2& m, float f) { + Matrix2 r = Matrix2(m.nRows, m.nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = m.data[ix] * f; + return r; + } + friend Matrix2 operator*(float f, const Matrix2& m) { + Matrix2 r = Matrix2(m.nRows, m.nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = f * m.data[ix]; + return r; + } + + friend Matrix1 operator*(const Matrix2& m, const Matrix1& v) { + Matrix1 r = Matrix1(m.nRows); + for (int rowIx = 0; rowIx < m.nRows; rowIx++) { + int mRowIx = rowIx * m.nCols; + for (int colIx = 0; colIx < m.nCols; colIx++) + r.data[rowIx] += m.data[mRowIx + colIx] * v.data[rowIx]; + } + return r; + } + + friend Matrix2 operator/(const Matrix2& m, float f) { + Matrix2 r = Matrix2(m.nRows, m.nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = m.data[ix] / f; + return r; + } + friend Matrix2 operator/(float f, const Matrix2& m) { + Matrix2 r = Matrix2(m.nRows, m.nCols); + for (int ix = 0; ix < r.nValues; ix++) + r.data[ix] = f / m.data[ix]; + return r; + } + + Matrix2 Slice(int rawStart, int rowStop, int colStart, int colStop); + + void UpdateSlice(int rowStart, + int rowStop, + int colStart, + int colStop, + const Matrix2& m) const; + // private: + // move constructor and move assignment operator + Matrix2(Matrix2&& other) noexcept; + Matrix2& operator=(Matrix2&& other) noexcept; + + static Matrix2 Omega(const Vector3& v); + + private: + bool externalData = true; +}; + /// @brief Single precision float matrix -template class MatrixOf { -public: +template +class MatrixOf { + public: MatrixOf(unsigned int rows, unsigned int cols); - MatrixOf(unsigned int rows, unsigned int cols, const T *source) + MatrixOf(unsigned int rows, unsigned int cols, const T* source) : MatrixOf(rows, cols) { Set(source); } - MatrixOf(Vector3 v); // creates a 3,1 matrix + MatrixOf(Vector3 v); // creates a 3,1 matrix ~MatrixOf() { if (this->data == nullptr) @@ -22,7 +134,7 @@ public: /// @brief Transpose with result in matrix m /// @param r The matrix in which the transposed matrix is stored - void Transpose(MatrixOf *r) const { + void Transpose(MatrixOf* r) const { // Check dimensions first // We dont care about the rows and cols (we overwrite them) // but the data size should be equal to avoid problems @@ -33,7 +145,7 @@ public: // Return a null matrix; // We dont set data to nullptr because it is allocated memory // Instead we write all zeros - for (int dataIx = 0; dataIx < resultSize; dataIx++) + for (unsigned int dataIx = 0; dataIx < resultSize; dataIx++) r->data[dataIx] = 0.0f; r->rows = 0; r->cols = 0; @@ -43,7 +155,7 @@ public: r->cols = this->rows; r->rows = this->cols; - for (int rDataIx = 0; rDataIx < matrixSize; rDataIx++) { + for (unsigned int rDataIx = 0; rDataIx < matrixSize; rDataIx++) { unsigned int rowIx = rDataIx / this->rows; unsigned int colIx = rDataIx % this->rows; unsigned int mDataIx = this->cols * colIx + rowIx; @@ -51,13 +163,14 @@ public: } } - static void Multiply(const MatrixOf *m1, const MatrixOf *m2, - MatrixOf *r); - void Multiply(const MatrixOf *m, MatrixOf *r) const { + static void Multiply(const MatrixOf* m1, + const MatrixOf* m2, + MatrixOf* r); + void Multiply(const MatrixOf* m, MatrixOf* r) const { Multiply(this, m, r); } - static Vector3 Multiply(const MatrixOf *m, Vector3 v); + static Vector3 Multiply(const MatrixOf* m, Vector3 v); Vector3 operator*(const Vector3 v) const; T Get(unsigned int rowIx, unsigned int colIx) const { @@ -71,28 +184,28 @@ public: } // This function does not check on source size! - void Set(const T *source) { + void Set(const T* source) { unsigned int matrixSize = this->cols * this->rows; for (unsigned int dataIx = 0; dataIx < matrixSize; dataIx++) this->data[dataIx] = source[dataIx]; } // This function does not check on source size! - void SetRow(unsigned int rowIx, const T *source) { + void SetRow(unsigned int rowIx, const T* source) { unsigned int dataIx = rowIx * this->cols; for (unsigned int sourceIx = 0; sourceIx < this->cols; dataIx++, sourceIx++) this->data[dataIx] = source[sourceIx]; } // This function does not check on source size! - void SetCol(unsigned int colIx, const T *source) { + void SetCol(unsigned int colIx, const T* source) { unsigned int dataIx = colIx; for (unsigned int sourceIx = 0; sourceIx < this->cols; dataIx += this->cols, sourceIx++) this->data[dataIx] = source[sourceIx]; } - void CopyFrom(const MatrixOf *m) { + void CopyFrom(const MatrixOf* m) { unsigned int thisMatrixSize = this->cols * this->rows; unsigned int mMatrixSize = m->cols * m->rows; if (mMatrixSize != thisMatrixSize) @@ -105,10 +218,13 @@ public: unsigned int RowCount() const { return rows; } unsigned int ColCount() const { return cols; } -private: + private: unsigned int rows; unsigned int cols; - T *data; + T* data; }; +} // namespace LinearAlgebra +// using namespace LinearAlgebra; + #endif \ No newline at end of file diff --git a/Polar.cpp b/Polar.cpp index f72a692..15ac40f 100644 --- a/Polar.cpp +++ b/Polar.cpp @@ -1,84 +1,179 @@ #include -#include "Angle.h" #include "Polar.h" #include "Vector2.h" -Polar::Polar() { - angle = 0.0F; - distance = 0.0F; +template +PolarOf::PolarOf() { + this->distance = 0.0f; + this->angle = AngleOf(); } - -Polar::Polar(float newAngle, float newDistance) { +template +PolarOf::PolarOf(float distance, AngleOf angle) { // distance should always be 0 or greater - if (newDistance < 0) { - angle = Angle::Normalize(newAngle - 180); - distance = -newDistance; + if (distance < 0.0f) { + this->distance = -distance; + this->angle = AngleOf::Normalize(angle - AngleOf::Degrees(180)); } else { - angle = Angle::Normalize(newAngle); - distance = newDistance; + this->distance = distance; + if (this->distance == 0.0f) + // angle is always 0 if distance is 0 + this->angle = AngleOf(); + else + this->angle = AngleOf::Normalize(angle); } } -Polar::Polar(Vector2 v) { - float signY = (v.y >= 0) - (v.y < 0); - angle = atan2(v.y, signY * sqrt(v.y * v.y + v.x * v.x)) * Angle::Rad2Deg; - distance = v.magnitude(); +template +PolarOf PolarOf::Degrees(float distance, float degrees) { + AngleOf angle = AngleOf::Degrees(degrees); + PolarOf r = PolarOf(distance, angle); + return r; } -const Polar Polar::zero = Polar(0, 0); +template +PolarOf PolarOf::Radians(float distance, float radians) { + return PolarOf(distance, AngleOf::Radians(radians)); +} -float Polar::Distance(const Polar &v1, const Polar &v2) { +template +PolarOf PolarOf::FromVector2(Vector2 v) { + float distance = v.magnitude(); + AngleOf angle = + AngleOf::Degrees(Vector2::SignedAngle(Vector2::forward, v)); + PolarOf p = PolarOf(distance, angle); + return p; +} +template +PolarOf PolarOf::FromSpherical(SphericalOf v) { + float distance = + v.distance * cosf(v.direction.vertical.InDegrees() * Deg2Rad); + AngleOf angle = v.direction.horizontal; + PolarOf p = PolarOf(distance, angle); + return p; +} + +template +const PolarOf PolarOf::zero = PolarOf(0.0f, AngleOf()); +template +const PolarOf PolarOf::forward = PolarOf(1.0f, AngleOf()); +template +const PolarOf PolarOf::back = PolarOf(1.0, AngleOf::Degrees(180)); +template +const PolarOf PolarOf::right = PolarOf(1.0, AngleOf::Degrees(90)); +template +const PolarOf PolarOf::left = PolarOf(1.0, AngleOf::Degrees(-90)); + +template +bool PolarOf::operator==(const PolarOf& v) const { + return (this->distance == v.distance && + this->angle.InDegrees() == v.angle.InDegrees()); +} + +template +PolarOf PolarOf::Normalize(const PolarOf& v) { + PolarOf r = PolarOf(1, v.angle); + return r; +} +template +PolarOf PolarOf::normalized() const { + PolarOf r = PolarOf(1, this->angle); + return r; +} + +template +PolarOf PolarOf::operator-() const { + PolarOf v = + PolarOf(this->distance, this->angle + AngleOf::Degrees(180)); + return v; +} + +template +PolarOf PolarOf::operator-(const PolarOf& v) const { + PolarOf r = -v; + return *this + r; +} +template +PolarOf PolarOf::operator-=(const PolarOf& v) { + *this = *this - v; + return *this; + // angle = AngleOf::Normalize(newAngle); + // distance = newDistance; +} + +// Polar::Polar(Vector2 v) { +// float signY = (v.y >= 0) - (v.y < 0); +// angle = atan2(v.y, signY * sqrt(v.y * v.y + v.x * v.x)) * Angle::Rad2Deg; +// distance = v.magnitude(); +// } + +// const Polar Polar::zero = Polar(0, 0); + +// float Polar::Distance(const Polar &v1, const Polar &v2) { +// float d = +// Angle::CosineRuleSide(v1.distance, v2.distance, v2.angle - v1.angle); +// return d; +// } + +template +PolarOf PolarOf::operator+(const PolarOf& v) const { + if (v.distance == 0) + return PolarOf(this->distance, this->angle); + if (this->distance == 0.0f) + return v; + + float deltaAngle = AngleOf::Normalize(v.angle - this->angle).InDegrees(); + float rotation = + deltaAngle < 0.0f ? 180.0f + deltaAngle : 180.0f - deltaAngle; + + if (rotation == 180.0f && v.distance > 0.0f) { + // angle is too small, take this angle and add the distances + return PolarOf(this->distance + v.distance, this->angle); + } + + float newDistance = AngleOf::CosineRuleSide(v.distance, this->distance, + AngleOf::Degrees(rotation)); + + float angle = + AngleSingle::CosineRuleAngle(newDistance, this->distance, v.distance) + .InDegrees(); + + float newAngle = deltaAngle < 0.0f ? this->angle.InDegrees() - angle + : this->angle.InDegrees() + angle; + AngleOf newAngleA = AngleOf::Normalize(AngleOf::Degrees(newAngle)); + PolarOf vector = PolarOf(newDistance, newAngleA); + return vector; +} +template +PolarOf PolarOf::operator+=(const PolarOf& v) { + *this = *this + v; + return *this; +} + +template +PolarOf PolarOf::operator*=(float f) { + this->distance *= f; + return *this; +} +template +PolarOf PolarOf::operator/=(float f) { + this->distance /= f; + return *this; +} + +template +float PolarOf::Distance(const PolarOf& v1, const PolarOf& v2) { float d = - Angle::CosineRuleSide(v1.distance, v2.distance, v2.angle - v1.angle); + AngleOf::CosineRuleSide(v1.distance, v2.distance, v2.angle - v1.angle); return d; } -Polar Polar::operator+(const Polar &v2) const { - if (v2.distance == 0) - return Polar(this->angle, this->distance); - if (this->distance == 0) - return v2; - - float deltaAngle = Angle::Normalize(v2.angle - this->angle); - float rotation = deltaAngle < 0 ? 180 + deltaAngle : 180 - deltaAngle; - - if (rotation == 180 && v2.distance > 0) { - // angle is too small, take this angle and add the distances - return Polar(this->angle, this->distance + v2.distance); - } - - float newDistance = - Angle::CosineRuleSide(v2.distance, this->distance, rotation); - - float angle = - Angle::CosineRuleAngle(newDistance, this->distance, v2.distance); - - float newAngle = deltaAngle < 0 ? Angle::Normalize(this->angle - angle) - : Angle::Normalize(this->angle + angle); - Polar vector = Polar(newAngle, newDistance); - return vector; +template +PolarOf PolarOf::Rotate(const PolarOf& v, AngleOf angle) { + AngleOf a = AngleOf::Normalize(v.angle + angle); + PolarOf r = PolarOf(v.distance, a); + return r; } -Polar Polar::operator-() { - Polar vector = Polar(this->angle - 180, this->distance); - return vector; -} - -Polar Polar::operator-(const Polar &v2) const { - Polar vector = *this + (Polar(v2.angle - 180, v2.distance)); - return vector; -} - -Polar Polar::operator*(float f) const { - return Polar(this->angle, this->distance * f); -} - -Polar Polar::operator/(const float &f) { - return Polar(this->angle, this->distance / f); -} - -Polar Polar::Rotate(Polar v, float angle) { - v.angle = Angle::Normalize(v.angle + angle); - return v; -} \ No newline at end of file +template class LinearAlgebra::PolarOf; +template class LinearAlgebra::PolarOf; \ No newline at end of file diff --git a/Polar.h b/Polar.h index 6060364..541bec8 100644 --- a/Polar.h +++ b/Polar.h @@ -5,98 +5,158 @@ #ifndef POLAR_H #define POLAR_H -class Vector2; +#include "Angle.h" -/// -/// A polar vector -/// -/// This will use the polar coordinate system consisting of a angle from a -/// reference direction and a distance. -struct Polar { -public: - /// - /// The angle in degrees, clockwise rotation - /// - /// The angle is normalized to -180 .. 180 - float angle; - /// - /// The distance in meters - /// - /// The distance should never be negative +namespace LinearAlgebra { + +struct Vector2; +template +class SphericalOf; + +/// @brief A polar vector using an angle in various representations +/// @tparam T The implementation type used for the representation of the angle +template +class PolarOf { + public: + /// @brief The distance in meters + /// @remark The distance shall never be negative float distance; + /// @brief The angle in degrees clockwise rotation + /// @remark The angle shall be between -180 .. 180 + AngleOf angle; - /// - /// Create a new polar vector with zero degrees and distance - /// - Polar(); - /// - /// Create a new polar vector - /// - /// The angle in degrees, clockwise rotation - /// The distance in meters - Polar(float angle, float distance); + /// @brief A new vector with polar coordinates with zero degrees and + /// distance + PolarOf(); + /// @brief A new vector with polar coordinates + /// @param distance The distance in meters + /// @param angle The angle in degrees, clockwise rotation + /// @note The distance is automatically converted to a positive value. + /// @note The angle is automatically normalized to -180 .. 180 + PolarOf(float distance, AngleOf angle); - Polar(Vector2 v); + /// @brief Create polar vector without using AngleOf type. All given angles + /// are in degrees + /// @param distance The distance in meters + /// @param degrees The angle in degrees + /// @return The polar vector + static PolarOf Degrees(float distance, float degrees); + /// @brief Short-hand Deg alias for the Degrees function + constexpr static auto Deg = Degrees; + /// @brief Create polar vector without using AngleOf type. All given angles + /// are in radians. + /// @param distance The distance in meters + /// @param radians The angle in radians + /// @return The polar vector + static PolarOf Radians(float distance, float radians); + /// @brief Short-hand Rad alias for the Radians function + constexpr static auto Rad = Radians; - /// - /// A polar vector with zero degrees and distance - /// - const static Polar zero; + /// @brief Convert a vector from 2D carthesian coordinates to polar + /// coordinates + /// @param v The vector to convert + static PolarOf FromVector2(Vector2 v); + /// @brief Convert a vector from spherical coordinates to polar coordinates + /// @param s The vector to convert + /// @note The resulting vector will be projected on the horizontal plane + static PolarOf FromSpherical(SphericalOf v); - /// - /// Negate the polar vector. - /// + /// @brief A polar vector with zero degrees and distance + const static PolarOf zero; + /// @brief A normalized forward-oriented vector + const static PolarOf forward; + /// @brief A normalized back-oriented vector + const static PolarOf back; + /// @brief A normalized right-oriented vector + const static PolarOf right; + /// @brief A normalized left-oriented vector + const static PolarOf left; + + /// @brief Equality test to another vector + /// @param v The vector to check against + /// @return true: if it is identical to the given vector + /// @note This uses float comparison to check equality which may have + /// strange effects. Equality on floats should be avoided. + bool operator==(const PolarOf& v) const; + + /// @brief The vector length + /// @param v The vector for which you need the length + /// @return The vector length; + inline static float Magnitude(const PolarOf& v) { return v.distance; } + /// @brief The vector length + /// @return The vector length + inline float magnitude() const { return this->distance; } + + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + static PolarOf Normalize(const PolarOf& v); + /// @brief Convert the vector to a length of a + /// @return The vector normalized to a length of 1 + PolarOf normalized() const; + + /// @brief Negate the vector + /// @return The negated vector /// This will rotate the vector by 180 degrees. Distance will stay the same. - /// The negated vector + PolarOf operator-() const; - Polar operator-(); - /// - /// Substract a polar vector from this coordinate - /// - /// The vector to subtract from this vector - /// The result of the subtraction - Polar operator-(const Polar &v) const; + /// @brief Subtract a polar vector from this vector + /// @param v The vector to subtract + /// @return The result of the subtraction + PolarOf operator-(const PolarOf& v) const; + PolarOf operator-=(const PolarOf& v); + /// @brief Add a polar vector to this vector + /// @param v The vector to add + /// @return The result of the addition + PolarOf operator+(const PolarOf& v) const; + PolarOf operator+=(const PolarOf& v); - /// - /// Add another polar vector to this polar vector - /// - /// The vector to add - /// The result of adding the vector - Polar operator+(const Polar &v) const; + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + friend PolarOf operator*(const PolarOf& v, float f) { + return PolarOf(v.distance * f, v.angle); + } + friend PolarOf operator*(float f, const PolarOf& v) { + return PolarOf(f * v.distance, v.angle); + } + PolarOf operator*=(float f); + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled factor + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + friend PolarOf operator/(const PolarOf& v, float f) { + return PolarOf(v.distance / f, v.angle); + } + friend PolarOf operator/(float f, const PolarOf& v) { + return PolarOf(f / v.distance, v.angle); + } + PolarOf operator/=(float f); - /// - /// Scale the vector uniformly up - /// - /// The scaling factor - /// The scaled vector - /// This operation will scale the distance of the vector. The angle will be - /// unaffected. - Polar operator*(float factor) const; + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + static float Distance(const PolarOf& v1, const PolarOf& v2); - /// - /// Scale the vector uniformly down - /// - /// The scaling factor - /// The scaled vector - /// This operation will scale the distance of the vector. The angle will be - /// unaffected. - Polar operator/(const float &factor); - - /// - /// The distance between two vectors - /// - /// The first vector - /// The second vector - /// The distance between the two vectors - static float Distance(const Polar &v1, const Polar &v2); - - /// - /// Rotate the vector - /// - /// The vector to rotate - /// Angle in radias to rotate - /// The rotated vector - static Polar Rotate(Polar v, float angle); + /// @brief Rotate a vector + /// @param v The vector to rotate + /// @param a The angle in degreesto rotate + /// @return The rotated vector + static PolarOf Rotate(const PolarOf& v, AngleOf a); }; +using PolarSingle = PolarOf; +using Polar16 = PolarOf; +// using Polar = PolarSingle; + +} // namespace LinearAlgebra +using namespace LinearAlgebra; + +#include "Spherical.h" +#include "Vector2.h" + #endif \ No newline at end of file diff --git a/Quaternion.cpp b/Quaternion.cpp index e621bb0..dda8c18 100644 --- a/Quaternion.cpp +++ b/Quaternion.cpp @@ -5,6 +5,8 @@ #include "Quaternion.h" #include #include +#include "Angle.h" +#include "Matrix.h" #include "Vector3.h" void CopyQuat(const Quat& q1, Quat& q2) { @@ -96,6 +98,28 @@ Vector3 Quaternion::ToAngles(const Quaternion& q1) { } } +Matrix2 LinearAlgebra::Quaternion::ToRotationMatrix() { + Matrix2 r = Matrix2(3, 3); + + float x = this->x; + float y = this->y; + float z = this->z; + float w = this->w; + + float* data = r.data; + data[0 * 3 + 0] = 1 - 2 * (y * y + z * z); + data[0 * 3 + 1] = 2 * (x * y - w * z); + data[0 * 3 + 2] = 2 * (x * z + w * y); + data[1 * 3 + 0] = 2 * (x * y + w * z); + data[1 * 3 + 1] = 1 - 2 * (x * x + z * z); + data[1 * 3 + 2] = 2 * (y * z - w * x); + data[2 * 3 + 0] = 2 * (x * z - w * y); + data[2 * 3 + 1] = 2 * (y * z + w * x); + data[2 * 3 + 2] = 1 - 2 * (x * x + y * y); + + return r; +} + Quaternion Quaternion::operator*(const Quaternion& r2) const { return Quaternion( this->x * r2.w + this->y * r2.z - this->z * r2.y + this->w * r2.x, @@ -117,17 +141,25 @@ Vector3 Quaternion::operator*(const Vector3& p) const { float num10 = this->w * num; float num11 = this->w * num2; float num12 = this->w * num3; - Vector3 result = Vector3::zero; - result.x = - (1 - (num5 + num6)) * p.x + (num7 - num12) * p.y + (num8 + num11) * p.z; - result.y = - (num7 + num12) * p.x + (1 - (num4 + num6)) * p.y + (num9 - num10) * p.z; - result.z = - (num8 - num11) * p.x + (num9 + num10) * p.y + (1 - (num4 + num5)) * p.z; + + float px = p.Right(); + float py = p.Up(); + float pz = p.Forward(); + // Vector3 result = Vector3::zero; + // result.x = + float rx = + (1 - (num5 + num6)) * px + (num7 - num12) * py + (num8 + num11) * pz; + // result.y = + float ry = + (num7 + num12) * px + (1 - (num4 + num6)) * py + (num9 - num10) * pz; + // result.z = + float rz = + (num8 - num11) * px + (num9 + num10) * py + (1 - (num4 + num5)) * pz; + Vector3 result = Vector3(rx, ry, rz); return result; } -bool Quaternion::operator==(const Quaternion& q) { +bool Quaternion::operator==(const Quaternion& q) const { return (this->x == q.x && this->y == q.y && this->z == q.z && this->w == q.w); } @@ -144,15 +176,15 @@ Quaternion Quaternion::LookRotation(const Vector3& forward, const Vector3& up) { Vector3 nForward = Vector3::Normalize(forward); Vector3 nRight = Vector3::Normalize(Vector3::Cross(up, nForward)); Vector3 nUp = Vector3::Cross(nForward, nRight); - float m00 = nRight.x; - float m01 = nRight.y; - float m02 = nRight.z; - float m10 = nUp.x; - float m11 = nUp.y; - float m12 = nUp.z; - float m20 = nForward.x; - float m21 = nForward.y; - float m22 = nForward.z; + float m00 = nRight.Right(); // x; + float m01 = nRight.Up(); // y; + float m02 = nRight.Forward(); // z; + float m10 = nUp.Right(); // x; + float m11 = nUp.Up(); // y; + float m12 = nUp.Forward(); // z; + float m20 = nForward.Right(); // x; + float m21 = nForward.Up(); // y; + float m22 = nForward.Forward(); // z; float num8 = (m00 + m11) + m22; Quaternion quaternion = Quaternion(); @@ -196,8 +228,8 @@ Quaternion Quaternion::FromToRotation(Vector3 fromDirection, Vector3 toDirection) { Vector3 axis = Vector3::Cross(fromDirection, toDirection); axis = Vector3::Normalize(axis); - float angle = Vector3::SignedAngle(fromDirection, toDirection, axis); - Quaternion rotation = Quaternion::AngleAxis(angle, axis); + AngleOf angle = Vector3::SignedAngle(fromDirection, toDirection, axis); + Quaternion rotation = Quaternion::AngleAxis(angle.InDegrees(), axis); return rotation; } @@ -221,9 +253,9 @@ Quaternion Quaternion::AngleAxis(float angle, const Vector3& axis) { radians *= 0.5f; Vector3 axis2 = axis * (float)sin(radians); - result.x = axis2.x; - result.y = axis2.y; - result.z = axis2.z; + result.x = axis2.Right(); // x; + result.y = axis2.Up(); // y; + result.z = axis2.Forward(); // z; result.w = (float)cos(radians); return Quaternion::Normalize(result); @@ -246,7 +278,7 @@ void Quaternion::ToAxisAngleRad(const Quaternion& q, *angle = 2.0f * acosf(q1.w); // angle float den = sqrtf(1.0F - q1.w * q1.w); if (den > 0.0001f) { - *axis = q1.xyz() / den; + *axis = Vector3::Normalize(q1.xyz() / den); } else { // This occurs when the angle is zero. // Not a problem: just set an arbitrary normalized axis. @@ -297,7 +329,8 @@ Quaternion Quaternion::SlerpUnclamped(const Quaternion& a, blendB = t; } Vector3 v = axyz * blendA + b2.xyz() * blendB; - Quaternion result = Quaternion(v.x, v.y, v.z, blendA * a.w + blendB * b2.w); + Quaternion result = + Quaternion(v.Right(), v.Up(), v.Forward(), blendA * a.w + blendB * b2.w); if (result.GetLengthSquared() > 0.0f) return Quaternion::Normalize(result); else @@ -322,9 +355,9 @@ Quaternion Quaternion::Euler(Vector3 euler) { } Quaternion Quaternion::FromEulerRad(Vector3 euler) { - float yaw = euler.x; - float pitch = euler.y; - float roll = euler.z; + float yaw = euler.Right(); + float pitch = euler.Up(); + float roll = euler.Forward(); float rollOver2 = roll * 0.5f; float sinRollOver2 = (float)sin((float)rollOver2); float cosRollOver2 = (float)cos((float)rollOver2); @@ -353,9 +386,9 @@ Quaternion Quaternion::EulerXYZ(Vector3 euler) { return Quaternion::FromEulerRadXYZ(euler * Deg2Rad); } Quaternion Quaternion::FromEulerRadXYZ(Vector3 euler) { - float yaw = euler.x; - float pitch = euler.y; - float roll = euler.z; + float yaw = euler.Right(); // x; + float pitch = euler.Up(); // y; + float roll = euler.Forward(); // z; float rollOver2 = roll * 0.5f; float sinRollOver2 = (float)sin((float)rollOver2); float cosRollOver2 = (float)cos((float)rollOver2); @@ -394,7 +427,7 @@ Quaternion Quaternion::GetRotationAround(Vector3 axis, Quaternion rotation) { Vector3 ra = Vector3(rotation.x, rotation.y, rotation.z); // rotation axis Vector3 p = Vector3::Project( ra, axis); // return projection ra on to axis (parallel component) - Quaternion twist = Quaternion(p.x, p.y, p.z, rotation.w); + Quaternion twist = Quaternion(p.Right(), p.Up(), p.Forward(), rotation.w); twist = Quaternion::Normalize(twist); return twist; } diff --git a/Quaternion.h b/Quaternion.h index eb40a5d..1687dc9 100644 --- a/Quaternion.h +++ b/Quaternion.h @@ -9,7 +9,7 @@ extern "C" { /// -/// A quaternion +/// A quaternion (C-style) /// /// This is a C-style implementation typedef struct Quat { @@ -32,6 +32,10 @@ typedef struct Quat { } Quat; } +namespace LinearAlgebra { + +class Matrix2; + /// /// A quaternion /// @@ -54,6 +58,9 @@ struct Quaternion : Quat { /// /// Quaternion(Quat q); + /// + /// Quaternion destructor + /// ~Quaternion(); /// @@ -84,6 +91,8 @@ struct Quaternion : Quat { /// The euler angles performed in the order: Z, X, Y static Vector3 ToAngles(const Quaternion& q); + Matrix2 ToRotationMatrix(); + /// /// Rotate a vector using this quaterion /// @@ -108,7 +117,7 @@ struct Quaternion : Quat { /// themselves. Two quaternions with the same rotational effect may have /// different components. Use Quaternion::Angle to check if the rotations are /// the same. - bool operator==(const Quaternion& quaternion); + bool operator==(const Quaternion& quaternion) const; /// /// The inverse of quaterion @@ -282,4 +291,7 @@ struct Quaternion : Quat { Vector3 xyz() const; }; -#endif \ No newline at end of file +} // namespace LinearAlgebra +using namespace LinearAlgebra; + +#endif diff --git a/README.md b/README.md index 42397d5..afc4fbb 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ -\mainpage Vector Algebra +\mainpage Linear Algebra -Vector algebra library +Linear algebra library Main components --------------- -* [Vector3](https://passervr.com/apis/VectorAlgebra/struct_vector3.html) -* [Quaternion](https://passervr.com/apis/VectorAlgebra/struct_quaternion.html) +Carthesian coordinate systems +* [Vector3](#Passer::LinearAlgebra::Vector3): A 3D carthesian vector +* [Vector2](#Passer::LinearAlgebra::Vector2): A 2D carthesian vector -* [Vector2](https://passervr.com/apis/VectorAlgebra/struct_vector2.html) +Other coodinate systems +* [Polar](#Passer::LinearAlgebra::PolarOf): A 2D polar vector +* [Spherical](#Passer::LinearAlgebra::SphericalOf): A 3D spherical vector -* [Polar](https://passervr.com/apis/VectorAlgebra/struct_polar.html) +Rotations +* [Quaternion](#Passer::LinearAlgebra::Quaternion): A quaternion rotation +* [SwingTwist](#Passer::LinearAlgebra::SwingTwistOf): A swing/twist angular rotation + +Basics +* [Angle](#Passer::LinearAlgebra::AngleOf): An angle +* [Direction](#Passer::LinearAlgebra::DirectionOf): A direction using angles diff --git a/Spherical.cpp b/Spherical.cpp index 026d33b..0371f92 100644 --- a/Spherical.cpp +++ b/Spherical.cpp @@ -1,50 +1,307 @@ #include "Spherical.h" #include "Angle.h" +#include "Quaternion.h" #include -// using Angle = float; +namespace LinearAlgebra { -Spherical::Spherical() { - this->horizontalAngle = 0; - this->verticalAngle = 0; - this->distance = 0; +template +SphericalOf::SphericalOf() { + this->distance = 0.0f; + this->direction = DirectionOf(); } -// Spherical::Spherical(float polarAngle, float elevationAngle, float distance) -// { -// this->horizontalAngle = polarAngle; -// this->verticalAngle = elevationAngle; -// this->distance = distance; -// } - -Spherical::Spherical(Polar polar) { - this->horizontalAngle = polar.angle; - this->verticalAngle = 0.0F; - this->distance = polar.distance; +template +SphericalOf::SphericalOf(float distance, + AngleOf horizontal, + AngleOf vertical) { + if (distance < 0) { + this->distance = -distance; + this->direction = -DirectionOf(horizontal, vertical); + } else { + this->distance = distance; + this->direction = DirectionOf(horizontal, vertical); + } } -Spherical::Spherical(float distance, Angle horizontalAngle, Angle verticalAngle) - : distance(distance), horizontalAngle(horizontalAngle), - verticalAngle(verticalAngle) {} - -Spherical::Spherical(Vector3 v) { - float signZ = (v.z >= 0) - (v.z < 0); - horizontalAngle = - atan2(v.y, signZ * sqrt(v.z * v.z + v.x * v.x)) * Angle::Rad2Deg; - verticalAngle = -atan2(v.x, sqrt(v.z * v.z + v.y * v.y)) * Angle::Rad2Deg; - distance = v.magnitude(); +template +SphericalOf::SphericalOf(float distance, DirectionOf direction) { + if (distance < 0) { + this->distance = -distance; + this->direction = -direction; + } else { + this->distance = distance; + this->direction = direction; + } } -const Spherical Spherical::zero = Spherical(0.0F, (Angle)0.0F, (Angle)0.0F); - -float Spherical::GetSwing() { - // Not sure if this is correct - return sqrtf(horizontalAngle * horizontalAngle + - verticalAngle * verticalAngle); +template +SphericalOf SphericalOf::Degrees(float distance, + float horizontal, + float vertical) { + AngleOf horizontalAngle = AngleOf::Degrees(horizontal); + AngleOf verticalAngle = AngleOf::Degrees(vertical); + SphericalOf r = SphericalOf(distance, horizontalAngle, verticalAngle); + return r; } -Polar Spherical::ProjectOnHorizontalPlane() { - return Polar(horizontalAngle, distance); -} \ No newline at end of file +template +SphericalOf SphericalOf::Radians(float distance, + float horizontal, + float vertical) { + return SphericalOf(distance, AngleOf::Radians(horizontal), + AngleOf::Radians(vertical)); +} + +template +SphericalOf SphericalOf::FromPolar(PolarOf polar) { + AngleOf horizontal = polar.angle; + AngleOf vertical = AngleOf(); + SphericalOf r = SphericalOf(polar.distance, horizontal, vertical); + return r; +} + +template +SphericalOf SphericalOf::FromVector3(Vector3 v) { + float distance = v.magnitude(); + if (distance == 0.0f) { + return SphericalOf(distance, AngleOf(), AngleOf()); + } else { + AngleOf verticalAngle = + AngleOf::Radians((pi / 2 - acosf(v.Up() / distance))); + AngleOf horizontalAngle = + AngleOf::Radians(atan2f(v.Right(), v.Forward())); + return SphericalOf(distance, horizontalAngle, verticalAngle); + } +} + +/** + * @brief Converts spherical coordinates to a 3D vector. + * + * This function converts the spherical coordinates represented by the + * SphericalOf object to a 3D vector (Vector3). The conversion is based + * on the distance and direction (vertical and horizontal angles) of the + * spherical coordinates. + * + * @tparam T The type of the distance and direction values. + * @return Vector3 The 3D vector representation of the spherical coordinates. + */ +template +Vector3 SphericalOf::ToVector3() const { + float verticalRad = (pi / 2) - this->direction.vertical.InRadians(); + float horizontalRad = this->direction.horizontal.InRadians(); + + float cosVertical = cosf(verticalRad); + float sinVertical = sinf(verticalRad); + float cosHorizontal = cosf(horizontalRad); + float sinHorizontal = sinf(horizontalRad); + + float x = this->distance * sinVertical * sinHorizontal; + float y = this->distance * cosVertical; + float z = this->distance * sinVertical * cosHorizontal; + + Vector3 v = Vector3(x, y, z); + return v; +} + +template +const SphericalOf SphericalOf::zero = + SphericalOf(0.0f, AngleOf(), AngleOf()); +template +const SphericalOf SphericalOf::forward = + SphericalOf(1.0f, AngleOf(), AngleOf()); +template +const SphericalOf SphericalOf::back = + SphericalOf(1.0f, AngleOf::Degrees(180), AngleOf()); +template +const SphericalOf SphericalOf::right = + SphericalOf(1.0f, AngleOf::Degrees(90), AngleOf()); +template +const SphericalOf SphericalOf::left = + SphericalOf(1.0f, AngleOf::Degrees(-90), AngleOf()); +template +const SphericalOf SphericalOf::up = + SphericalOf(1.0f, AngleOf(), AngleOf::Degrees(90)); +template +const SphericalOf SphericalOf::down = + SphericalOf(1.0f, AngleOf(), AngleOf::Degrees(-90)); + +template +SphericalOf SphericalOf::WithDistance(float distance) { + SphericalOf v = SphericalOf(distance, this->direction); + return v; +} + +template +SphericalOf SphericalOf::operator-() const { + SphericalOf v = SphericalOf( + this->distance, this->direction.horizontal + AngleOf::Degrees(180), + this->direction.vertical + AngleOf::Degrees(180)); + return v; +} + +template +SphericalOf SphericalOf::operator-(const SphericalOf& s2) const { + // let's do it the easy way... + Vector3 v1 = this->ToVector3(); + Vector3 v2 = s2.ToVector3(); + Vector3 v = v1 - v2; + SphericalOf r = SphericalOf::FromVector3(v); + return r; +} +template +SphericalOf SphericalOf::operator-=(const SphericalOf& v) { + *this = *this - v; + return *this; +} + +template +SphericalOf SphericalOf::operator+(const SphericalOf& s2) const { + // let's do it the easy way... + Vector3 v1 = this->ToVector3(); + Vector3 v2 = s2.ToVector3(); + Vector3 v = v1 + v2; + SphericalOf r = SphericalOf::FromVector3(v); + return r; + /* + // This is the hard way... + if (v2.distance <= 0) + return Spherical(this->distance, this->horizontalAngle, + this->verticalAngle); + if (this->distance <= 0) + return v2; + + float deltaHorizontalAngle = + (float)Angle::Normalize(v2.horizontalAngle - this->horizontalAngle); + float horizontalRotation = deltaHorizontalAngle < 0 + ? 180 + deltaHorizontalAngle + : 180 - deltaHorizontalAngle; + float deltaVerticalAngle = + Angle::Normalize(v2.verticalAngle - this->verticalAngle); + float verticalRotation = deltaVerticalAngle < 0 ? 180 + deltaVerticalAngle + : 180 - deltaVerticalAngle; + + if (horizontalRotation == 180 && verticalRotation == 180) + // angle is too small, take this angle and add the distances + return Spherical(this->distance + v2.distance, this->horizontalAngle, + this->verticalAngle); + + Angle rotation = AngleBetween(*this, v2); + float newDistance = + Angle::CosineRuleSide(v2.distance, this->distance, rotation); + float angle = + Angle::CosineRuleAngle(newDistance, this->distance, v2.distance); + + // Now we have to project the angle to the horizontal and vertical planes... + // The axis for the angle is the cross product of the two spherical vectors + // (which function we do not have either...) + float horizontalAngle = 0; + float verticalAngle = 0; + + float newHorizontalAngle = + deltaHorizontalAngle < 0 + ? Angle::Normalize(this->horizontalAngle - horizontalAngle) + : Angle::Normalize(this->horizontalAngle + horizontalAngle); + float newVerticalAngle = + deltaVerticalAngle < 0 + ? Angle::Normalize(this->verticalAngle - verticalAngle) + : Angle::Normalize(this->verticalAngle + verticalAngle); + + Spherical v = Spherical(newDistance, newHorizontalAngle, newVerticalAngle); + */ +} +template +SphericalOf SphericalOf::operator+=(const SphericalOf& v) { + *this = *this + v; + return *this; +} + +template +SphericalOf SphericalOf::operator*=(float f) { + this->distance *= f; + return *this; +} + +template +SphericalOf SphericalOf::operator/=(float f) { + this->distance /= f; + return *this; +} + +#include "FloatSingle.h" +#include "Vector3.h" + +const float epsilon = 1E-05f; + +template +float SphericalOf::DistanceBetween(const SphericalOf& v1, + const SphericalOf& v2) { + // SphericalOf difference = v1 - v2; + // return difference.distance; + Vector3 vec1 = v1.ToVector3(); + Vector3 vec2 = v2.ToVector3(); + float distance = Vector3::Distance(vec1, vec2); + return distance; +} + +template +AngleOf SphericalOf::AngleBetween(const SphericalOf& v1, + const SphericalOf& v2) { + // float denominator = v1.distance * v2.distance; + // if (denominator < epsilon) + // return 0.0f; + + Vector3 v1_3 = v1.ToVector3(); + Vector3 v2_3 = v2.ToVector3(); + // float dot = Vector3::Dot(v1_3, v2_3); + // float fraction = dot / denominator; + // if (isnan(fraction)) + // return fraction; // short cut to returning NaN universally + + // float cdot = Float::Clamp(fraction, -1.0, 1.0); + // float r = ((float)acos(cdot)) * Rad2Deg; + AngleSingle r = Vector3::Angle(v1_3, v2_3); + return AngleOf::Degrees(r.InDegrees()); +} + +template +AngleOf SphericalOf::SignedAngleBetween(const SphericalOf& v1, + const SphericalOf& v2, + const SphericalOf& axis) { + Vector3 v1_vector = v1.ToVector3(); + Vector3 v2_vector = v2.ToVector3(); + Vector3 axis_vector = axis.ToVector3(); + AngleSingle r = Vector3::SignedAngle(v1_vector, v2_vector, axis_vector); + return AngleOf::Degrees(r.InDegrees()); +} + +template +SphericalOf SphericalOf::Rotate(const SphericalOf& v, + AngleOf horizontalAngle, + AngleOf verticalAngle) { + SphericalOf r = + SphericalOf(v.distance, v.direction.horizontal + horizontalAngle, + v.direction.vertical + verticalAngle); + return r; +} +template +SphericalOf SphericalOf::RotateHorizontal(const SphericalOf& v, + AngleOf a) { + SphericalOf r = + SphericalOf(v.distance, v.direction.horizontal + a, v.direction.vertical); + return r; +} +template +SphericalOf SphericalOf::RotateVertical(const SphericalOf& v, + AngleOf a) { + SphericalOf r = + SphericalOf(v.distance, v.direction.horizontal, v.direction.vertical + a); + return r; +} + +template class SphericalOf; +template class SphericalOf; + +} // namespace LinearAlgebra \ No newline at end of file diff --git a/Spherical.h b/Spherical.h index 7c98263..309db03 100644 --- a/Spherical.h +++ b/Spherical.h @@ -1,66 +1,193 @@ -/// @copyright -/// This Source Code Form is subject to the terms of the Mozilla Public -/// License, v. 2.0.If a copy of the MPL was not distributed with this -/// file, You can obtain one at https ://mozilla.org/MPL/2.0/. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https ://mozilla.org/MPL/2.0/. #ifndef SPHERICAL_H #define SPHERICAL_H -#include "Angle.h" -#include "Polar.h" +#include "Direction.h" + +namespace LinearAlgebra { struct Vector3; +template +class PolarOf; -namespace Passer { - -/// @brief A spherical vector -/// @details -/// This is a vector in 3D space using a spherical coordinate system. -/// It consists of a distance and the polar and elevation angles from a -/// reference direction. The reference direction is typically thought of -/// as a forward direction. -struct Spherical { -public: +/// @brief A spherical vector using angles in various representations +/// @tparam T The implementation type used for the representations of the agles +template +class SphericalOf { + public: + /// @brief The distance in meters + /// @remark The distance should never be negative float distance; + /// @brief The direction of the vector + DirectionOf direction; - /// @brief The angle in the horizontal plane in degrees, clockwise rotation - /// @details The angle is automatically normalized to -180 .. 180 - Angle horizontalAngle; - /// @brief The angle in the vertical plane in degrees. Positive is upward. - /// @details The angle is automatically normalized to -180 .. 180 - Angle verticalAngle; + SphericalOf(); + SphericalOf(float distance, AngleOf horizontal, AngleOf vertical); + SphericalOf(float distance, DirectionOf direction); - /// @brief Create a new spherical vector with zero degrees and distance - Spherical(); - /// @brief Create a new spherical vector - /// @param polarAngle The angle in the horizontal plane in degrees, - /// clockwise rotation - /// @param elevationAngle The angle in the vertical plan in degrees, - /// zero is forward, positive is upward + /// @brief Create spherical vector without using AngleOf type. All given + /// angles are in degrees /// @param distance The distance in meters - // Spherical(float polarAngle, float elevationAngle, float distance); + /// @param horizontal The horizontal angle in degrees + /// @param vertical The vertical angle in degrees + /// @return The spherical vector + static SphericalOf Degrees(float distance, + float horizontal, + float vertical); + /// @brief Short-hand Deg alias for the Degrees function + constexpr static auto Deg = Degrees; + /// @brief Create sperical vector without using the AngleOf type. All given + /// angles are in radians + /// @param distance The distance in meters + /// @param horizontal The horizontal angle in radians + /// @param vertical The vertical angle in radians + /// @return The spherical vectpr + static SphericalOf Radians(float distance, + float horizontal, + float vertical); + // Short-hand Rad alias for the Radians function + constexpr static auto Rad = Radians; - Spherical(float distance, Angle horizontalAngle, Angle verticalAngle); + /// @brief Create a Spherical coordinate from a Polar coordinate + /// @param v The polar coordinate + /// @return The spherical coordinate with the vertical angle set to zero. + static SphericalOf FromPolar(PolarOf v); - /// @brief Convert polar coordinates to spherical coordinates - /// @param polar The polar coordinate - Spherical(Polar polar); - - /// @brief Convert 3D carthesian coordinates to spherical coordinates - /// @param v Vector in 3D carthesian coordinates; - Spherical(Vector3 v); + /// @brief Create a Spherical coordinate from a Vector3 coordinate + /// @param v The vector coordinate + /// @return The spherical coordinate + static SphericalOf FromVector3(Vector3 v); + /// @brief Convert the spherical coordinate to a Vector3 coordinate + /// @return The vector coordinate + Vector3 ToVector3() const; /// @brief A spherical vector with zero degree angles and distance - const static Spherical zero; + const static SphericalOf zero; + /// @brief A normalized forward-oriented vector + const static SphericalOf forward; + /// @brief A normalized back-oriented vector + const static SphericalOf back; + /// @brief A normalized right-oriented vector + const static SphericalOf right; + /// @brief A normalized left-oriented vector + const static SphericalOf left; + /// @brief A normalized up-oriented vector + const static SphericalOf up; + /// @brief A normalized down-oriented vector + const static SphericalOf down; - float GetSwing(); + /// @brief Update the distance component of the spherical coordinate + /// @param distance The new distance + /// @return The updated coordinate + SphericalOf WithDistance(float distance); - Polar ProjectOnHorizontalPlane(); + /// @brief Negate the vector + /// @return The negated vector + /// This will rotate the vector by 180 degrees horizontally and + /// vertically. Distance will stay the same. + SphericalOf operator-() const; + + /// @brief Subtract a spherical vector from this vector + /// @param v The vector to subtract + /// @return The result of the subtraction + SphericalOf operator-(const SphericalOf& v) const; + SphericalOf operator-=(const SphericalOf& v); + /// @brief Add a spherical vector to this vector + /// @param v The vector to add + /// @return The result of the addition + SphericalOf operator+(const SphericalOf& v) const; + SphericalOf operator+=(const SphericalOf& v); + + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + friend SphericalOf operator*(const SphericalOf& v, float f) { + return SphericalOf(v.distance * f, v.direction); + } + friend SphericalOf operator*(float f, const SphericalOf& v) { + return SphericalOf(f * v.distance, v.direction); + } + SphericalOf operator*=(float f); + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled factor + /// @remark This operation will scale the distance of the vector. The angle + /// will be unaffected. + friend SphericalOf operator/(const SphericalOf& v, float f) { + return SphericalOf(v.distance / f, v.direction); + } + friend SphericalOf operator/(float f, const SphericalOf& v) { + return SphericalOf(f / v.distance, v.direction); + } + SphericalOf operator/=(float f); + + /// @brief Calculate the distance between two spherical coordinates + /// @param v1 The first coordinate + /// @param v2 The second coordinate + /// @return The distance between the coordinates in meters + static float DistanceBetween(const SphericalOf& v1, + const SphericalOf& v2); + /// @brief Calculate the unsigned angle between two spherical vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The unsigned angle between the vectors + static AngleOf AngleBetween(const SphericalOf& v1, + const SphericalOf& v2); + /// @brief Calculate the signed angle between two spherical vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @param axis The axis are which the angle is calculated + /// @return The signed angle between the vectors + static AngleOf SignedAngleBetween(const SphericalOf& v1, + const SphericalOf& v2, + const SphericalOf& axis); + + /// @brief Rotate a spherical vector + /// @param v The vector to rotate + /// @param horizontalAngle The horizontal rotation angle in local space + /// @param verticalAngle The vertical rotation angle in local space + /// @return The rotated vector + static SphericalOf Rotate(const SphericalOf& v, + AngleOf horizontalAngle, + AngleOf verticalAngle); + /// @brief Rotate a spherical vector horizontally + /// @param v The vector to rotate + /// @param angle The horizontal rotation angle in local space + /// @return The rotated vector + static SphericalOf RotateHorizontal(const SphericalOf& v, + AngleOf angle); + /// @brief Rotate a spherical vector vertically + /// @param v The vector to rotate + /// @param angle The vertical rotation angle in local space + /// @return The rotated vector + static SphericalOf RotateVertical(const SphericalOf& v, + AngleOf angle); }; -} // namespace Passer -using namespace Passer; +/// @brief Shorthand notation for a spherical vector using single precision +/// floats for the angles This is the fastest implementation on devices with +/// floating point harware +using SphericalSingle = SphericalOf; +/// @brief Shorthand notation for a spherical vector using signed 16-bit words +/// for the angles +/// @note This is the fastest implementation on devices without floating point +/// hardware +using Spherical16 = SphericalOf; +#if defined(ARDUINO) +using Spherical = Spherical16; +#else +using Spherical = SphericalSingle; +#endif + +} // namespace LinearAlgebra + +#include "Polar.h" #include "Vector3.h" #endif \ No newline at end of file diff --git a/SwingTwist.cpp b/SwingTwist.cpp new file mode 100644 index 0000000..deca73c --- /dev/null +++ b/SwingTwist.cpp @@ -0,0 +1,172 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https ://mozilla.org/MPL/2.0/. + +#include "SwingTwist.h" + +namespace LinearAlgebra { + +template +SwingTwistOf::SwingTwistOf() { + this->swing = DirectionOf(AngleOf(), AngleOf()); + this->twist = AngleOf(); +} + +template +SwingTwistOf::SwingTwistOf(DirectionOf swing, AngleOf twist) { + // Normalize angles + AngleOf deg90 = AngleOf::Degrees(90); + AngleOf deg180 = AngleOf::Degrees(180); + + if (swing.vertical > deg90 || swing.vertical < -deg90) { + swing.horizontal += deg180; + swing.vertical = deg180 - swing.vertical; + twist += deg180; + } + + this->swing = swing; + this->twist = twist; +} + +template +SwingTwistOf::SwingTwistOf(AngleOf horizontal, + AngleOf vertical, + AngleOf twist) { + // Normalize angles + AngleOf deg90 = AngleOf::Degrees(90); + AngleOf deg180 = AngleOf::Degrees(180); + + if (vertical > deg90 || vertical < -deg90) { + horizontal += deg180; + vertical = deg180 - vertical; + twist += deg180; + } + + this->swing = DirectionOf(horizontal, vertical); + this->twist = twist; +} + +template +SwingTwistOf SwingTwistOf::Degrees(float horizontal, + float vertical, + float twist) { + SwingTwistOf orientation = SwingTwistOf(AngleOf::Degrees(horizontal), + -AngleOf::Degrees(vertical), + AngleOf::Degrees(twist)); + // DirectionOf swing = DirectionOf::Degrees(horizontal, vertical); + // AngleOf twistAngle = AngleOf::Degrees(twist); + // SwingTwistOf orientation = SwingTwistOf(swing, twistAngle); + return orientation; +} + +template +Quaternion SwingTwistOf::ToQuaternion() const { + Quaternion q = Quaternion::Euler(-this->swing.vertical.InDegrees(), + this->swing.horizontal.InDegrees(), + this->twist.InDegrees()); + return q; +} + +template +SwingTwistOf SwingTwistOf::FromQuaternion(Quaternion q) { + Vector3 angles = Quaternion::ToAngles(q); + SwingTwistOf r = + SwingTwistOf::Degrees(angles.Up(), angles.Right(), angles.Forward()); + r.Normalize(); + return r; +} + +template +SphericalOf SwingTwistOf::ToAngleAxis() const { + Quaternion q = this->ToQuaternion(); + float angle; + Vector3 axis; + q.ToAngleAxis(&angle, &axis); + DirectionOf direction = DirectionOf::FromVector3(axis); + + SphericalOf aa = SphericalOf(angle, direction); + return aa; +} + +template +SwingTwistOf SwingTwistOf::FromAngleAxis(SphericalOf aa) { + Vector3 vectorAxis = aa.direction.ToVector3(); + Quaternion q = Quaternion::AngleAxis(aa.distance, vectorAxis); + return SwingTwistOf(); +} + +template +bool SwingTwistOf::operator==(const SwingTwistOf s) const { + return (this->swing == s.swing) && (this->twist == s.twist); +} + +template +const SwingTwistOf SwingTwistOf::identity = SwingTwistOf(); + +template +SphericalOf SwingTwistOf::operator*(const SphericalOf& vector) const { + SphericalOf v = SphericalOf( + vector.distance, vector.direction.horizontal + this->swing.horizontal, + vector.direction.vertical + this->swing.vertical); + return v; +} + +template +SwingTwistOf SwingTwistOf::operator*( + const SwingTwistOf& rotation) const { + SwingTwistOf r = + SwingTwistOf(this->swing.horizontal + rotation.swing.horizontal, + this->swing.vertical + rotation.swing.vertical, + this->twist + rotation.twist); + return r; +} + +template +SwingTwistOf SwingTwistOf::operator*=(const SwingTwistOf& rotation) { + this->swing.horizontal += rotation.swing.horizontal; + this->swing.vertical += rotation.swing.vertical; + this->twist += rotation.twist; + return *this; +} + +template +SwingTwistOf SwingTwistOf::Inverse(SwingTwistOf rotation) { + SwingTwistOf r = SwingTwistOf( + -rotation.swing.horizontal, -rotation.swing.vertical, -rotation.twist); + return r; +} + +template +SwingTwistOf SwingTwistOf::AngleAxis(float angle, + const DirectionOf& axis) { + Vector3 axis_vector = axis.ToVector3(); + Quaternion q = Quaternion::AngleAxis(angle, axis_vector); + SwingTwistOf r = SwingTwistOf::FromQuaternion(q); + return r; +} + +template +AngleOf SwingTwistOf::Angle(const SwingTwistOf& r1, + const SwingTwistOf& r2) { + Quaternion q1 = r1.ToQuaternion(); + Quaternion q2 = r2.ToQuaternion(); + float angle = Quaternion::Angle(q1, q2); + return AngleOf::Degrees(angle); +} + +template +void SwingTwistOf::Normalize() { + AngleOf deg90 = AngleOf::Degrees(90); + AngleOf deg180 = AngleOf::Degrees(180); + + if (this->swing.vertical > deg90 || this->swing.vertical < -deg90) { + this->swing.horizontal += deg180; + this->swing.vertical = deg180 - this->swing.vertical; + this->twist += deg180; + } +} + +template class SwingTwistOf; +template class SwingTwistOf; + +} \ No newline at end of file diff --git a/SwingTwist.h b/SwingTwist.h new file mode 100644 index 0000000..1800e43 --- /dev/null +++ b/SwingTwist.h @@ -0,0 +1,85 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https ://mozilla.org/MPL/2.0/. + +#ifndef SWINGTWIST_H +#define SWINGTWIST_H + +#include "Angle.h" +#include "Direction.h" +#include "Quaternion.h" +#include "Spherical.h" + +namespace LinearAlgebra { + +/// @brief An orientation using swing and twist angles in various +/// representations +/// @tparam T The implmentation type used for the representation of the angles +template +class SwingTwistOf { + public: + DirectionOf swing; + AngleOf twist; + + SwingTwistOf(); + SwingTwistOf(DirectionOf swing, AngleOf twist); + SwingTwistOf(AngleOf horizontal, AngleOf vertical, AngleOf twist); + + static SwingTwistOf Degrees(float horizontal, + float vertical = 0, + float twist = 0); + + Quaternion ToQuaternion() const; + static SwingTwistOf FromQuaternion(Quaternion q); + + SphericalOf ToAngleAxis() const; + static SwingTwistOf FromAngleAxis(SphericalOf aa); + + const static SwingTwistOf identity; + + bool operator==(const SwingTwistOf d) const; + + /// + /// Rotate a vector using this rotation + /// + /// The vector to rotate + /// The rotated vector + SphericalOf operator*(const SphericalOf& vector) const; + /// + /// Multiply this rotation with another rotation + /// + /// The swing/twist rotation to multiply with + /// The resulting swing/twist rotation + /// The result will be this rotation rotated according to + /// the give rotation. + SwingTwistOf operator*(const SwingTwistOf& rotation) const; + SwingTwistOf operator*=(const SwingTwistOf& rotation); + + static SwingTwistOf Inverse(SwingTwistOf rotation); + + /// + /// Convert an angle/axis representation to a swingt + /// + /// The angle + /// The axis + /// The resulting quaternion + static SwingTwistOf AngleAxis(float angle, const DirectionOf& axis); + + static AngleOf Angle(const SwingTwistOf& r1, const SwingTwistOf& r2); + + void Normalize(); +}; + +using SwingTwistSingle = SwingTwistOf; +using SwingTwist16 = SwingTwistOf; + +#if defined(ARDUINO) +using SwingTwist = SwingTwist16; +#else +using SwingTwist = SwingTwistSingle; +#endif + +} // namespace LinearAlgebra +using namespace LinearAlgebra; + +#endif diff --git a/Vector2.cpp b/Vector2.cpp index 150b12f..1e34a99 100644 --- a/Vector2.cpp +++ b/Vector2.cpp @@ -5,26 +5,37 @@ #include "Vector2.h" #include "Angle.h" #include "FloatSingle.h" +#include "Vector3.h" -#if defined(AVR) -#include -#else +// #if defined(AVR) +// #include +// #else #include -#endif +// #endif Vector2::Vector2() { x = 0; y = 0; } - Vector2::Vector2(float _x, float _y) { x = _x; y = _y; } +// Vector2::Vector2(Vec2 v) { +// x = v.x; +// y = v.y; +// } +Vector2::Vector2(Vector3 v) { + x = v.Right(); // x; + y = v.Forward(); // z; +} +Vector2::Vector2(PolarSingle p) { + float horizontalRad = p.angle.InDegrees() * Deg2Rad; + float cosHorizontal = cosf(horizontalRad); + float sinHorizontal = sinf(horizontalRad); -Vector2::Vector2(Vec2 v) { - x = v.x; - y = v.y; + x = p.distance * sinHorizontal; + y = p.distance * cosHorizontal; } Vector2::~Vector2() {} @@ -38,15 +49,24 @@ const Vector2 Vector2::down = Vector2(0, -1); const Vector2 Vector2::forward = Vector2(0, 1); const Vector2 Vector2::back = Vector2(0, -1); -float Vector2::Magnitude(const Vector2 &a) { - return sqrtf(a.x * a.x + a.y * a.y); +bool Vector2::operator==(const Vector2& v) { + return (this->x == v.x && this->y == v.y); } -float Vector2::magnitude() const { return (float)sqrtf(x * x + y * y); } -float Vector2::SqrMagnitude(const Vector2 &a) { return a.x * a.x + a.y * a.y; } -float Vector2::sqrMagnitude() const { return (x * x + y * y); } +float Vector2::Magnitude(const Vector2& v) { + return sqrtf(v.x * v.x + v.y * v.y); +} +float Vector2::magnitude() const { + return (float)sqrtf(x * x + y * y); +} +float Vector2::SqrMagnitude(const Vector2& v) { + return v.x * v.x + v.y * v.y; +} +float Vector2::sqrMagnitude() const { + return (x * x + y * y); +} -Vector2 Vector2::Normalize(Vector2 v) { +Vector2 Vector2::Normalize(const Vector2& v) { float num = Vector2::Magnitude(v); Vector2 result = Vector2::zero; if (num > Float::epsilon) { @@ -63,56 +83,67 @@ Vector2 Vector2::normalized() const { return result; } -Vector2 Vector2::ClampMagnitude(const Vector2 &v, float magnitude) { - float length = Vector2::Magnitude(v); - Vector2 r = v; - if (length > magnitude) - r = v / (length * magnitude); - - return r; +Vector2 Vector2::operator-() { + return Vector2(-this->x, -this->y); } -Vector2 Vector2::operator-(const Vector2 &v2) const { - return Vector2(this->x - v2.x, this->y - v2.y); +Vector2 Vector2::operator-(const Vector2& v) const { + return Vector2(this->x - v.x, this->y - v.y); +} +Vector2 Vector2::operator-=(const Vector2& v) { + this->x -= v.x; + this->y -= v.y; + return *this; +} +Vector2 Vector2::operator+(const Vector2& v) const { + return Vector2(this->x + v.x, this->y + v.y); +} +Vector2 Vector2::operator+=(const Vector2& v) { + this->x += v.x; + this->y += v.y; + return *this; } -Vector2 Vector2::operator-() { return Vector2(-this->x, -this->y); } - -Vector2 Vector2::operator+(const Vector2 &v2) const { - return Vector2(this->x + v2.x, this->y + v2.y); +Vector2 Vector2::Scale(const Vector2& v1, const Vector2& v2) { + return Vector2(v1.x * v2.x, v1.y * v2.y); +} +// Vector2 Passer::LinearAlgebra::operator*(const Vector2 &v, float f) { +// return Vector2(v.x * f, v.y * f); +// } +// Vector2 Passer::LinearAlgebra::operator*(float f, const Vector2 &v) { +// return Vector2(v.x * f, v.y * f); +// } +Vector2 Vector2::operator*=(float f) { + this->x *= f; + this->y *= f; + return *this; +} +// Vector2 Passer::LinearAlgebra::operator/(const Vector2 &v, float f) { +// return Vector2(v.x / f, v.y / f); +// } +// Vector2 Passer::LinearAlgebra::operator/(float f, const Vector2 &v) { +// return Vector2(v.x / f, v.y / f); +// } +Vector2 Vector2::operator/=(float f) { + this->x /= f; + this->y /= f; + return *this; } -Vector2 Vector2::Scale(const Vector2 &p1, const Vector2 &p2) { - return Vector2(p1.x * p2.x, p1.y * p2.y); -} - -Vector2 Vector2::operator*(float f) const { - return Vector2(this->x * f, this->y * f); -} - -Vector2 Vector2::operator/(const float &d) const { - return Vector2(this->x / d, this->y / d); -} - -float Vector2::Dot(const Vector2 &v1, const Vector2 &v2) { +float Vector2::Dot(const Vector2& v1, const Vector2& v2) { return v1.x * v2.x + v1.y * v2.y; } -bool Vector2::operator==(const Vector2 &v) { - return (this->x == v.x && this->y == v.y); +float Vector2::Distance(const Vector2& v1, const Vector2& v2) { + return Magnitude(v1 - v2); } -float Vector2::Distance(const Vector2 &p1, const Vector2 &p2) { - return Magnitude(p1 - p2); +float Vector2::Angle(const Vector2& v1, const Vector2& v2) { + return (float)fabs(SignedAngle(v1, v2)); } - -float Vector2::Angle(Vector2 from, Vector2 to) { - return (float)fabs(SignedAngle(from, to)); -} - -float Vector2::SignedAngle(Vector2 from, Vector2 to) { - float sqrMagFrom = from.sqrMagnitude(); - float sqrMagTo = to.sqrMagnitude(); +float Vector2::SignedAngle(const Vector2& v1, const Vector2& v2) { + float sqrMagFrom = v1.sqrMagnitude(); + float sqrMagTo = v2.sqrMagnitude(); if (sqrMagFrom == 0 || sqrMagTo == 0) return 0; @@ -123,16 +154,16 @@ float Vector2::SignedAngle(Vector2 from, Vector2 to) { return nanf(""); #endif - float angleFrom = atan2(from.y, from.x); - float angleTo = atan2(to.y, to.x); - return (angleTo - angleFrom) * Angle::Rad2Deg; + float angleFrom = atan2f(v1.y, v1.x); + float angleTo = atan2f(v2.y, v2.x); + return -(angleTo - angleFrom) * Rad2Deg; } -Vector2 Vector2::Rotate(Vector2 v, float angle) { - float angleRad = angle * Angle::Deg2Rad; +Vector2 Vector2::Rotate(const Vector2& v, AngleSingle a) { + float angleRad = a.InDegrees() * Deg2Rad; #if defined(AVR) float sinValue = sin(angleRad); - float cosValue = cos(angleRad); // * Angle::Deg2Rad); + float cosValue = cos(angleRad); // * Angle::Deg2Rad); #else float sinValue = (float)sinf(angleRad); float cosValue = (float)cosf(angleRad); @@ -140,16 +171,12 @@ Vector2 Vector2::Rotate(Vector2 v, float angle) { float tx = v.x; float ty = v.y; - v.x = (cosValue * tx) - (sinValue * ty); - v.y = (sinValue * tx) + (cosValue * ty); - return v; + Vector2 r = Vector2((cosValue * tx) - (sinValue * ty), + (sinValue * tx) + (cosValue * ty)); + return r; } -Vector2 Vector2::Lerp(Vector2 from, Vector2 to, float f) { - Vector2 v = from + (to - from) * f; +Vector2 Vector2::Lerp(const Vector2& v1, const Vector2& v2, float f) { + Vector2 v = v1 + (v2 - v1) * f; return v; } - -float Vector2::ToFactor(Vector2 a, Vector2 b) { - return (1 - Vector2::Dot(a, b)) / 2; -} diff --git a/Vector2.h b/Vector2.h index c2b0d11..04fa669 100644 --- a/Vector2.h +++ b/Vector2.h @@ -5,9 +5,11 @@ #ifndef VECTOR2_H #define VECTOR2_H +#include "Angle.h" + extern "C" { /// -/// 2-dimensional Vector representation +/// 2-dimensional Vector representation (C-style) /// /// This is a C-style implementation /// This uses the right-handed coordinate system. @@ -24,215 +26,184 @@ typedef struct Vec2 { } Vec2; } -/// -/// A 2-dimensional vector -/// -/// This uses the right-handed coordinate system. -struct Vector2 : Vec2 { -public: - /// - /// Create a new 2-dimensinal zero vector - /// - Vector2(); - /// - /// Create a new 2-dimensional vector - /// - /// x axis value - /// y axis value - Vector2(float x, float y); - /// - /// Create a vector from C-style Vec2 - /// - /// The C-style Vec - Vector2(Vec2 v); +namespace LinearAlgebra { +struct Vector3; +template +class PolarOf; + +/// @brief A 2-dimensional vector +/// @remark This uses the right=handed carthesian coordinate system. +/// @note This implementation intentionally avoids the use of x and y +struct Vector2 : Vec2 { + friend struct Vec2; + + public: + /// @brief A new 2-dimensional zero vector + Vector2(); + /// @brief A new 2-dimensional vector + /// @param right The distance in the right direction in meters + /// @param forward The distance in the forward direction in meters + Vector2(float right, float forward); + /// @brief Convert a Vector3 to a Vector2 + /// @param v The 3D vector + /// @note This will project the vector to the horizontal plane + Vector2(Vector3 v); + /// @brief Convert a Polar vector to a 2-dimensional vector + /// @param v The vector in polar coordinates + Vector2(PolarOf v); + + /// @brief Vector2 destructor ~Vector2(); - /// - /// A vector with zero for all axis - /// + /// @brief A vector with zero for all axis const static Vector2 zero; - /// - /// A vector with values (1, 1) - /// + /// @brief A vector with one for all axis const static Vector2 one; - /// - /// A vector with values (1, 0) - /// - /// - const static Vector2 right; - /// - /// A vector3 with values (-1, 0) - /// - const static Vector2 left; - /// - /// A vector with values (0, 1) - /// - const static Vector2 up; - /// - /// A vector with values (0, -1) - /// - const static Vector2 down; - /// - /// A vector with values (0, 1) - /// + /// @brief A normalized forward-oriented vector const static Vector2 forward; - /// - /// A vector with values (0, -1) - /// + /// @brief A normalized back-oriented vector const static Vector2 back; + /// @brief A normalized right-oriented vector + const static Vector2 right; + /// @brief A normalized left-oriented vector + const static Vector2 left; + /// @brief A normalized up-oriented vector + /// @note This is a convenience function which is equal to Vector2::forward + const static Vector2 up; + /// @brief A normalized down-oriented vector + /// @note This is a convenience function which is equal to Vector2::down + const static Vector2 down; - /// - /// The length of a vector - /// - /// The vector for which you need the length - /// The length of the given vector - static float Magnitude(const Vector2 &vector); - /// - /// The length of this vector - /// - /// The length of this vector + /// @brief Check if this vector to the given vector + /// @param v The vector to check against + /// @return true if it is identical to the given vector + /// @note This uses float comparison to check equality which may have strange + /// effects. Equality on floats should be avoided. + bool operator==(const Vector2& v); + + /// @brief The vector length + /// @param v The vector for which you need the length + /// @return The vector length + static float Magnitude(const Vector2& v); + /// @brief The vector length + /// @return The vector length float magnitude() const; - /// - /// The squared length of a vector - /// - /// The vector for which you need the squared - /// length The squatred length The squared length - /// is computationally simpler than the real length. Think of Pythagoras A^2 + - /// B^2 = C^2. This leaves out the calculation of the squared root of C. - static float SqrMagnitude(const Vector2 &vector); - /// - /// The squared length of this vector - /// - /// The squared length - /// The squared length is computationally simpler than the real length. - /// Think of Pythagoras A^2 + B^2 = C^2. - /// This leaves out the calculation of the squared root of C. + /// @brief The squared vector length + /// @param v The vector for which you need the squared length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation + /// of the squared root of C. + static float SqrMagnitude(const Vector2& v); + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This prevents the calculation + /// of the squared root of C. float sqrMagnitude() const; - /// - /// Connvert a vector to a length of 1 - /// - /// The vector to convert - /// The vector with length 1 - static Vector2 Normalize(Vector2 vector); - /// - /// Convert the vector to a length of a - /// - /// The vector with length 1 + + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + static Vector2 Normalize(const Vector2& v); + /// @brief Convert the vector to a length 1 + /// @return The vector normalized to a length of 1 Vector2 normalized() const; - static Vector2 ClampMagnitude(const Vector2 &v, float magnitude); - - /// - /// Negate the vector - /// - /// The negated vector - /// This will result in a vector pointing in the opposite direction + /// @brief Negate the vector such that it points in the opposite direction + /// @return The negated vector Vector2 operator-(); - /// - /// Subtract a vector from this vector - /// - /// The vector to subtract from this vector - /// The result of the subtraction - Vector2 operator-(const Vector2 &vector) const; - /// - /// Add another vector to this vector - /// - /// The vector to add - /// The result of adding the vector - Vector2 operator+(const Vector2 &vector2) const; + /// @brief Subtract a vector from this vector + /// @param v The vector to subtract from this vector + /// @return The result of the subtraction + Vector2 operator-(const Vector2& v) const; + Vector2 operator-=(const Vector2& v); + /// @brief Add a vector to this vector + /// @param v The vector to add to this vector + /// @return The result of the addition + Vector2 operator+(const Vector2& v) const; + Vector2 operator+=(const Vector2& v); - /// - /// Scale a vector using another vector - /// - /// The vector to scale - /// A vector with scaling factors - /// The scaled vector - /// Each component of the vector v1 will be multiplied with the - /// component from the scaling vector v2. - static Vector2 Scale(const Vector2 &vector1, const Vector2 &vector2); - /// - /// Scale a vector uniformly up - /// - /// The scaling factor - /// The scaled vector - /// Each component of the vector will be multipled with the same factor. - Vector2 operator*(float factor) const; - /// - /// Scale a vector uniformy down - /// - /// The scaling factor - /// The scaled vector - /// Each componet of the vector will be divided by the same factor. - Vector2 operator/(const float &factor) const; + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + static Vector2 Scale(const Vector2& v1, const Vector2& v2); + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each component of the vector will be multipled with the same + /// factor f. + friend Vector2 operator*(const Vector2& v, float f) { + return Vector2(v.x * f, v.y * f); + } + friend Vector2 operator*(float f, const Vector2& v) { + return Vector2(v.x * f, v.y * f); + // return Vector2(f * v.x, f * v.y); + } + Vector2 operator*=(float f); + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each componet of the vector will be divided by the same factor. + friend Vector2 operator/(const Vector2& v, float f) { + return Vector2(v.x / f, v.y / f); + } + friend Vector2 operator/(float f, const Vector2& v) { + return Vector2(f / v.x, f / v.y); + } + Vector2 operator/=(float f); - /// - /// The dot product of two vectors - /// - /// The first vector - /// The second vector - /// The dot product of the two vectors - static float Dot(const Vector2 &vector1, const Vector2 &vector2); + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + static float Dot(const Vector2& v1, const Vector2& v2); - /// - /// Check is this vector is equal to the given vector - /// - /// The vector to check against - /// True if it is identical to the given vector - /// Note this uses float comparison to check equality which - /// may have strange effects. Equality on float should be avoided. - bool operator==(const Vector2 &vector); + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + static float Distance(const Vector2& v1, const Vector2& v2); - /// - /// The distance between two vectors - /// - /// The first vector - /// The second vectors - /// The distance between the two vectors - static float Distance(const Vector2 &vector1, const Vector2 &vector2); + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector2::SignedAngle if a signed angle is + /// needed. + static float Angle(const Vector2& v1, const Vector2& v2); + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @return The signed angle between the two vectors + static float SignedAngle(const Vector2& v1, const Vector2& v2); - /// - /// Calculate the angle between two vectors - /// - /// The first vector - /// The second vector - /// The angle - /// This reterns an unsigned angle which is the shortest distance - /// between the two vectors. Use Vector3::SignedAngle if a - /// signed angle is needed. - static float Angle(Vector2 vector1, Vector2 vector2); + /// @brief Rotate the vector + /// @param v The vector to rotate + /// @param a The angle in degrees to rotate + /// @return The rotated vector + static Vector2 Rotate(const Vector2& v, AngleSingle a); - /// - /// Calculate the angle between two vectors rotation around an axis. - /// - /// The starting vector - /// The ending vector - /// The axis to rotate around - /// The signed angle - static float SignedAngle(Vector2 from, Vector2 to); - - /// - /// Rotate the vector - /// - /// The vector to rotate - /// Angle in radias to rotate - /// The rotated vector - static Vector2 Rotate(Vector2 v, float angle); - - /// - /// Lerp between two vectors - /// - /// The from vector - /// The to vector - /// The interpolation distance (0..1) - /// The lerped vector - /// The factor f is unclamped. Value 0 matches the *from* vector, Value 1 - /// matches the *to* vector Value -1 is *from* vector minus the difference - /// between *from* and *to* etc. - static Vector2 Lerp(Vector2 from, Vector2 to, float f); - - static float ToFactor(Vector2 a, Vector2 b); + /// @brief Lerp (linear interpolation) between two vectors + /// @param v1 The starting vector + /// @param v2 The end vector + /// @param f The interpolation distance + /// @return The lerped vector + /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value + /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference + /// between *v1* and *v2* etc. + static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float f); }; +} // namespace LinearAlgebra +using namespace LinearAlgebra; + +#include "Polar.h" + #endif \ No newline at end of file diff --git a/Vector3.cpp b/Vector3.cpp index c08c1c0..7ec6a95 100644 --- a/Vector3.cpp +++ b/Vector3.cpp @@ -3,6 +3,9 @@ // file, You can obtain one at https ://mozilla.org/MPL/2.0/. #include "Vector3.h" +#include "Angle.h" +#include "Spherical.h" + #include const float Deg2Rad = 0.0174532924F; @@ -10,21 +13,38 @@ const float Rad2Deg = 57.29578F; const float epsilon = 1E-05f; Vector3::Vector3() { - x = 0; - y = 0; - z = 0; + this->x = 0; + this->y = 0; + this->z = 0; } -Vector3::Vector3(float _x, float _y, float _z) { - x = _x; - y = _y; - z = _z; +Vector3::Vector3(float right, float up, float forward) { + this->x = right; + this->y = up; + this->z = forward; } -Vector3::Vector3(Vec3 v) { - x = v.x; - y = v.y; - z = v.z; +Vector3::Vector3(Vector2 v) { + this->x = v.x; + this->y = 0.0f; + this->z = v.y; +} + +Vector3::Vector3(SphericalOf s) { + float verticalRad = (90.0f - s.direction.vertical.InDegrees()) * Deg2Rad; + float horizontalRad = s.direction.horizontal.InDegrees() * Deg2Rad; + float cosVertical = cosf(verticalRad); + float sinVertical = sinf(verticalRad); + float cosHorizontal = cosf(horizontalRad); + float sinHorizontal = sinf(horizontalRad); + + x = s.distance * sinVertical * sinHorizontal; + y = s.distance * cosVertical; + z = s.distance * sinVertical * cosHorizontal; + // Vector3 v = Vector3(s.distance * sinVertical * sinHorizontal, + // s.distance * cosVertical, + // ); + // return v; } Vector3::~Vector3() {} @@ -41,21 +61,25 @@ const Vector3 Vector3::back = Vector3(0, 0, -1); // inline float Vector3::Forward() { return z; } // inline float Vector3::Up() { return y; } // inline float Vector3::Right() { return x; } -Vector3 Vector3::FromHorizontal(const Vector2 &v) { - return Vector3(v.x, 0, v.y); +// Vector3 Vector3::FromHorizontal(const Vector2 &v) { +// return Vector3(v.x, 0, v.y); +// } + +float Vector3::Magnitude(const Vector3& v) { + return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); +} +float Vector3::magnitude() const { + return (float)sqrtf(x * x + y * y + z * z); } -float Vector3::Magnitude(const Vector3 &a) { - return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z); +float Vector3::SqrMagnitude(const Vector3& v) { + return v.x * v.x + v.y * v.y + v.z * v.z; } -float Vector3::magnitude() const { return (float)sqrtf(x * x + y * y + z * z); } - -float Vector3::SqrMagnitude(const Vector3 &a) { - return a.x * a.x + a.y * a.y + a.z * a.z; +float Vector3::sqrMagnitude() const { + return (x * x + y * y + z * z); } -float Vector3::sqrMagnitude() const { return (x * x + y * y + z * z); } -Vector3 Vector3::Normalize(const Vector3 &v) { +Vector3 Vector3::Normalize(const Vector3& v) { float num = Vector3::Magnitude(v); Vector3 result = Vector3::zero; if (num > epsilon) { @@ -72,64 +96,87 @@ Vector3 Vector3::normalized() const { return result; } -Vector3 Vector3::operator-(const Vector3 &v2) const { - return Vector3(this->x - v2.x, this->y - v2.y, this->z - v2.z); +Vector3 Vector3::operator-() const { + return Vector3(-this->x, -this->y, -this->z); } -Vector3 Vector3::operator-() { return Vector3(-this->x, -this->y, -this->z); } - -Vector3 Vector3::operator+(const Vector3 &v2) const { - return Vector3(this->x + v2.x, this->y + v2.y, this->z + v2.z); +Vector3 Vector3::operator-(const Vector3& v) const { + return Vector3(this->x - v.x, this->y - v.y, this->z - v.z); +} +Vector3 Vector3::operator-=(const Vector3& v) { + this->x -= v.x; + this->y -= v.y; + this->z -= v.z; + return *this; +} +Vector3 Vector3::operator+(const Vector3& v) const { + return Vector3(this->x + v.x, this->y + v.y, this->z + v.z); +} +Vector3 Vector3::operator+=(const Vector3& v) { + this->x += v.x; + this->y += v.y; + this->z += v.z; + return *this; } -Vector3 Vector3::Scale(const Vector3 &p1, const Vector3 &p2) { - return Vector3(p1.x * p2.x, p1.y * p2.y, p1.z * p2.z); +Vector3 Vector3::Scale(const Vector3& v1, const Vector3& v2) { + return Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); +} +// Vector3 Passer::LinearAlgebra::operator*(const Vector3 &v, float f) { +// return Vector3(v.x * f, v.y * f, v.z * f); +// } +// Vector3 Passer::LinearAlgebra::operator*(float f, const Vector3 &v) { +// return Vector3(v.x * f, v.y * f, v.z * f); +// } +Vector3 Vector3::operator*=(float f) { + this->x *= f; + this->y *= f; + this->z *= f; + return *this; +} +// Vector3 Passer::LinearAlgebra::operator/(const Vector3 &v, float f) { +// return Vector3(v.x / f, v.y / f, v.z / f); +// } +// Vector3 Passer::LinearAlgebra::operator/(float f, const Vector3 &v) { +// return Vector3(v.x / f, v.y / f, v.z / f); +// } +Vector3 Vector3::operator/=(float f) { + this->x /= f; + this->y /= f; + this->z /= f; + return *this; } -Vector3 Vector3::operator*(float f) const { - return Vector3(this->x * f, this->y * f, this->z * f); -} - -Vector3 Vector3::operator/(float d) const { - return Vector3(this->x / d, this->y / d, this->z / d); -} - -float Vector3::Dot(const Vector3 &v1, const Vector3 &v2) { +float Vector3::Dot(const Vector3& v1, const Vector3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } -bool Vector3::operator==(const Vector3 &v) { +bool Vector3::operator==(const Vector3& v) const { return (this->x == v.x && this->y == v.y && this->z == v.z); } -float Vector3::Distance(const Vector3 &p1, const Vector3 &p2) { - return Magnitude(p1 - p2); +float Vector3::Distance(const Vector3& v1, const Vector3& v2) { + return Magnitude(v1 - v2); } -Vector3 Vector3::Cross(const Vector3 &v1, const Vector3 &v2) { +Vector3 Vector3::Cross(const Vector3& v1, const Vector3& v2) { return Vector3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); } -Vector3 Vector3::Project(const Vector3 &vector, const Vector3 &onNormal) { - float sqrMagnitude = Dot(onNormal, onNormal); +Vector3 Vector3::Project(const Vector3& v, const Vector3& n) { + float sqrMagnitude = Dot(n, n); if (sqrMagnitude < epsilon) return Vector3::zero; else { - float dot = Dot(vector, onNormal); - Vector3 r = onNormal * dot / sqrMagnitude; + float dot = Dot(v, n); + Vector3 r = n * dot / sqrMagnitude; return r; } } -Vector3 Vector3::ProjectOnPlane(const Vector3 &vector, - const Vector3 &planeNormal) { - Vector3 r = vector - Project(vector, planeNormal); - return r; -} - -Vector2 Vector3::ProjectHorizontalPlane(const Vector3 &vector) { - Vector2 r = Vector2(vector.x, vector.z); +Vector3 Vector3::ProjectOnPlane(const Vector3& v, const Vector3& n) { + Vector3 r = v - Project(v, n); return r; } @@ -139,37 +186,39 @@ float clamp(float x, float lower, float upper) { return upperClamp; } -float Vector3::Angle(const Vector3 &from, const Vector3 &to) { - float denominator = sqrtf(from.sqrMagnitude() * to.sqrMagnitude()); +AngleOf Vector3::Angle(const Vector3& v1, const Vector3& v2) { + float denominator = sqrtf(v1.sqrMagnitude() * v2.sqrMagnitude()); if (denominator < epsilon) - return 0; + return AngleOf(); - float dot = Vector3::Dot(from, to); + float dot = Vector3::Dot(v1, v2); float fraction = dot / denominator; if (isnan(fraction)) - return fraction; // short cut to returning NaN universally + return AngleOf::Degrees( + fraction); // short cut to returning NaN universally float cdot = clamp(fraction, -1.0, 1.0); - float r = ((float)acos(cdot)) * Rad2Deg; - return r; + float r = ((float)acos(cdot)); + return AngleOf::Radians(r); } -float Vector3::SignedAngle(const Vector3 &from, const Vector3 &to, - const Vector3 &axis) { +AngleOf Vector3::SignedAngle(const Vector3& v1, + const Vector3& v2, + const Vector3& axis) { // angle in [0,180] - float angle = Vector3::Angle(from, to); + AngleOf angle = Vector3::Angle(v1, v2); - Vector3 cross = Vector3::Cross(from, to); + Vector3 cross = Vector3::Cross(v1, v2); float b = Vector3::Dot(axis, cross); float signd = b < 0 ? -1.0F : (b > 0 ? 1.0F : 0.0F); // angle in [-179,180] - float signed_angle = angle * signd; + AngleOf signed_angle = angle * signd; - return signed_angle; + return AngleOf(signed_angle); } -Vector3 Vector3::Lerp(const Vector3 &from, const Vector3 &to, float f) { - Vector3 v = from + (to - from) * f; +Vector3 Vector3::Lerp(const Vector3& v1, const Vector3& v2, float f) { + Vector3 v = v1 + (v2 - v1) * f; return v; -} \ No newline at end of file +} diff --git a/Vector3.h b/Vector3.h index 50fc1f3..914d72a 100644 --- a/Vector3.h +++ b/Vector3.h @@ -9,11 +9,12 @@ extern "C" { /// -/// 3-dimensional Vector representation +/// 3-dimensional Vector representation (C-style) /// /// This is a C-style implementation /// This uses the right-handed coordinate system. typedef struct Vec3 { + public: /// /// The right axis of the vector /// @@ -30,242 +31,203 @@ typedef struct Vec3 { } Vec3; } -/// -/// A 3-dimensional vector -/// -/// This uses the right-handed coordinate system. +namespace LinearAlgebra { + +template +class SphericalOf; + +/// @brief A 3-dimensional vector +/// @remark This uses a right-handed carthesian coordinate system. +/// @note This implementation intentionally avoids the use of x, y and z values. struct Vector3 : Vec3 { -public: - /// - /// Create a new 3-dimensinal zero vector - /// + friend struct Vec3; + + public: + /// @brief A new 3-dimensional zero vector Vector3(); - /// - /// Create a new 3-dimensional vector - /// - /// x axis value - /// y axis value - /// z axis value - Vector3(float x, float y, float z); - /// - /// Create a vector from C-style Vec3 - /// - /// The C-style Vec - Vector3(Vec3 v); + /// @brief A new 3-dimensional vector + /// @param right The distance in the right direction in meters + /// @param up The distance in the upward direction in meters + /// @param forward The distance in the forward direction in meters + Vector3(float right, float up, float forward); + /// @brief Convert a 2-dimenstional vector to a 3-dimensional vector + /// @param v The vector to convert + Vector3(Vector2 v); + /// @brief Convert vector in spherical coordinates to 3d carthesian + /// coordinates + /// @param v The vector to convert + Vector3(SphericalOf v); + + /// @brief Vector3 destructor ~Vector3(); - /// - /// A vector with zero for all axis - /// + /// @brief A vector with zero for all axis const static Vector3 zero; - /// - /// A vector with one for all axis - /// + /// @brief A vector with one for all axis const static Vector3 one; - /// - /// A normalized vector pointing in the right direction - /// - const static Vector3 right; - /// - /// A normalized vector pointing in the left direction - /// - const static Vector3 left; - /// - /// A normalized vector pointing in the upward direction - /// - const static Vector3 up; - /// - /// A normalized vector pointing in the downward direcion - /// - const static Vector3 down; - /// - /// A normalized vector pointing in the forward direction - /// + /// @brief A normalized forward-oriented vector const static Vector3 forward; - /// - /// A normalized vector pointing in the backward direction - /// + /// @brief A normalized back-oriented vector const static Vector3 back; + /// @brief A normalized right-oriented vector + const static Vector3 right; + /// @brief A normalized left-oriented vector + const static Vector3 left; + /// @brief A normalized up-oriented vector + const static Vector3 up; + /// @brief A normalized down-oriented vector + const static Vector3 down; - // Experimental Access functions which are intended to replace the use of XYZ - inline float Forward() { return z; }; - inline float Up() { return y; }; - inline float Right() { return x; }; - static Vector3 FromHorizontal(const Vector2 &vector); + // Access functions which are intended to replace the use of XYZ + inline float Forward() const { return z; }; + inline float Up() const { return y; }; + inline float Right() const { return x; }; - /// - /// The length of a vector - /// - /// The vector for which you need the length - /// The length of the given vector - static float Magnitude(const Vector3 &vector); - /// - /// The length of this vector - /// - /// The length of this vector + /// @brief Check if this vector to the given vector + /// @param v The vector to check against + /// @return true if it is identical to the given vector + /// @note This uses float comparison to check equality which may have strange + /// effects. Equality on floats should be avoided. + bool operator==(const Vector3& v) const; + + /// @brief The vector length + /// @param v The vector for which you need the length + /// @return The vector length + static float Magnitude(const Vector3& v); + /// @brief The vector length + /// @return The vector length float magnitude() const; - /// - /// The squared length of a vector - /// - /// The vector for which you need the squared - /// length The squatred length The squared length - /// is computationally simpler than the real length. Think of Pythagoras A^2 + - /// B^2 = C^2. This leaves out the calculation of the squared root of C. - static float SqrMagnitude(const Vector3 &vector); - /// - /// The squared length of this vector - /// - /// The squared length - /// The squared length is computationally simpler than the real length. - /// Think of Pythagoras A^2 + B^2 = C^2. - /// This leaves out the calculation of the squared root of C. + /// @brief The squared vector length + /// @param v The vector for which you need the length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. + static float SqrMagnitude(const Vector3& v); + /// @brief The squared vector length + /// @return The squared vector length + /// @remark The squared length is computationally simpler than the real + /// length. Think of Pythagoras A^2 + B^2 = C^2. This leaves out the + /// calculation of the squared root of C. float sqrMagnitude() const; - /// - /// Connvert a vector to a length of 1 - /// - /// The vector to convert - /// The vector with length 1 - static Vector3 Normalize(const Vector3 &vector); - /// - /// Convert the vector to a length of a - /// - /// The vector with length 1 + + /// @brief Convert the vector to a length of 1 + /// @param v The vector to convert + /// @return The vector normalized to a length of 1 + static Vector3 Normalize(const Vector3& v); + /// @brief Convert the vector to a length of 1 + /// @return The vector normalized to a length of 1 Vector3 normalized() const; - /// - /// Negate the vector - /// - /// The negated vector - /// This will result in a vector pointing in the opposite direction - Vector3 operator-(); - /// - /// Subtract a vector from this vector - /// - /// The vector to subtract from this vector - /// The result of the subtraction - Vector3 operator-(const Vector3 &vector) const; + /// @brief Negate te vector such that it points in the opposite direction + /// @return The negated vector + Vector3 operator-() const; - /// - /// Add another vector to this vector - /// - /// The vector to add - /// The result of adding the vector - Vector3 operator+(const Vector3 &vector2) const; + /// @brief Subtract a vector from this vector + /// @param v The vector to subtract from this vector + /// @return The result of this subtraction + Vector3 operator-(const Vector3& v) const; + Vector3 operator-=(const Vector3& v); + /// @brief Add a vector to this vector + /// @param v The vector to add to this vector + /// @return The result of the addition + Vector3 operator+(const Vector3& v) const; + Vector3 operator+=(const Vector3& v); - /// - /// Scale a vector using another vector - /// - /// The vector to scale - /// A vector with scaling factors - /// The scaled vector - /// Each component of the vector v1 will be multiplied with the - /// component from the scaling vector v2. - static Vector3 Scale(const Vector3 &vector1, const Vector3 &vector2); - /// - /// Scale a vector uniformly up - /// - /// The scaling factor - /// The scaled vector - /// Each component of the vector will be multipled with the same factor. - Vector3 operator*(const float factor) const; - /// - /// Scale a vector uniformy down - /// - /// The scaling factor - /// The scaled vector - /// Each componet of the vector will be divided by the same factor. - Vector3 operator/(const float factor) const; + /// @brief Scale the vector using another vector + /// @param v1 The vector to scale + /// @param v2 A vector with the scaling factors + /// @return The scaled vector + /// @remark Each component of the vector v1 will be multiplied with the + /// matching component from the scaling vector v2. + static Vector3 Scale(const Vector3& v1, const Vector3& v2); + /// @brief Scale the vector uniformly up + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each component of the vector will be multipled with the same + /// factor f. + friend Vector3 operator*(const Vector3& v, float f) { + return Vector3(v.x * f, v.y * f, v.z * f); + } + friend Vector3 operator*(float f, const Vector3& v) { + // return Vector3(f * v.x, f * v.y, f * v.z); + return Vector3(v.x * f, v.y * f, v.z * f); + } + Vector3 operator*=(float f); + /// @brief Scale the vector uniformly down + /// @param f The scaling factor + /// @return The scaled vector + /// @remark Each componet of the vector will be divided by the same factor. + friend Vector3 operator/(const Vector3& v, float f) { + return Vector3(v.x / f, v.y / f, v.z / f); + } + friend Vector3 operator/(float f, const Vector3& v) { + // return Vector3(f / v.x, f / v.y, f / v.z); + return Vector3(v.x / f, v.y / f, v.z / f); + } + Vector3 operator/=(float f); - /// - /// The dot product of two vectors - /// - /// The first vector - /// The second vector - /// The dot product of the two vectors - static float Dot(const Vector3 &vector1, const Vector3 &vector2); + /// @brief The distance between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The distance between the two vectors + static float Distance(const Vector3& v1, const Vector3& v2); - /// - /// Check is this vector is equal to the given vector - /// - /// The vector to check against - /// True if it is identical to the given vector - /// Note this uses float comparison to check equality which - /// may have strange effects. Equality on float should be avoided. - bool operator==(const Vector3 &vector); + /// @brief The dot product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The dot product of the two vectors + static float Dot(const Vector3& v1, const Vector3& v2); - /// - /// The distance between two vectors - /// - /// The first vector - /// The second vectors - /// The distance between the two vectors - static float Distance(const Vector3 &vector1, const Vector3 &vector2); + /// @brief The cross product of two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The cross product of the two vectors + static Vector3 Cross(const Vector3& v1, const Vector3& v2); - /// - /// The cross product of two vectors - /// - /// The first vector - /// The second vector - /// The cross product of the two vectors - static Vector3 Cross(const Vector3 &vector1, const Vector3 &vector2); - - /// - /// Project a vector on another vector - /// - /// The vector to project - /// The normal vector to project on - /// The projected vector - static Vector3 Project(const Vector3 &vector, const Vector3 &onNormal); - /// - /// Projects a vector onto a plane defined by a normal orthogonal to the + /// @brief Project the vector on another vector + /// @param v The vector to project + /// @param n The normal vecto to project on + /// @return The projected vector + static Vector3 Project(const Vector3& v, const Vector3& n); + /// @brief Project the vector on a plane defined by a normal orthogonal to the /// plane. - /// - /// The vector to project - /// The normal of the plane to project on - /// - static Vector3 ProjectOnPlane(const Vector3 &vector, - const Vector3 &planeNormal); + /// @param v The vector to project + /// @param n The normal of the plane to project on + /// @return Teh projected vector + static Vector3 ProjectOnPlane(const Vector3& v, const Vector3& n); - /// - /// Projects a vector onto the horizontal plane. - /// - /// The vector to project - /// A 2D carthesian vector with the coordinates in the horizontal - /// plane. - static Vector2 ProjectHorizontalPlane(const Vector3 &vector); + /// @brief The angle between two vectors + /// @param v1 The first vector + /// @param v2 The second vector + /// @return The angle between the two vectors + /// @remark This reterns an unsigned angle which is the shortest distance + /// between the two vectors. Use Vector3::SignedAngle if a signed angle is + /// needed. + static AngleOf Angle(const Vector3& v1, const Vector3& v2); + /// @brief The signed angle between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param axis The axis to rotate around + /// @return The signed angle between the two vectors + static AngleOf SignedAngle(const Vector3& v1, + const Vector3& v2, + const Vector3& axis); - /// - /// Calculate the angle between two vectors - /// - /// The first vector - /// The second vector - /// - /// This reterns an unsigned angle which is the shortest distance - /// between the two vectors. Use Vector3::SignedAngle if a - /// signed angle is needed. - static float Angle(const Vector3 &vector1, const Vector3 &vector2); - - /// - /// Calculate the angle between two vectors rotation around an axis. - /// - /// The starting vector - /// The ending vector - /// The axis to rotate around - /// The signed angle - static float SignedAngle(const Vector3 &from, const Vector3 &to, - const Vector3 &axis); - - /// - /// Lerp between two vectors - /// - /// The from vector - /// The to vector - /// The interpolation distance (0..1) - /// The lerped vector - /// The factor f is unclamped. Value 0 matches the *from* vector, Value 1 - /// matches the *to* vector Value -1 is *from* vector minus the difference - /// between *from* and *to* etc. - static Vector3 Lerp(const Vector3 &from, const Vector3 &to, float f); + /// @brief Lerp (linear interpolation) between two vectors + /// @param v1 The starting vector + /// @param v2 The ending vector + /// @param f The interpolation distance + /// @return The lerped vector + /// @remark The factor f is unclamped. Value 0 matches the vector *v1*, Value + /// 1 matches vector *v2*. Value -1 is vector *v1* minus the difference + /// between *v1* and *v2* etc. + static Vector3 Lerp(const Vector3& v1, const Vector3& v2, float f); }; +} // namespace LinearAlgebra +using namespace LinearAlgebra; + +#include "Spherical.h" + #endif \ No newline at end of file diff --git a/float16.cpp b/float16.cpp new file mode 100644 index 0000000..041b3d3 --- /dev/null +++ b/float16.cpp @@ -0,0 +1,250 @@ +// +// FILE: float16.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.1.8 +// PURPOSE: library for Float16s for Arduino +// URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format + +#include "float16.h" +// #include +#include + +// CONSTRUCTOR +float16::float16(float f) { _value = f32tof16(f); } + +// PRINTING +// size_t float16::printTo(Print& p) const +// { +// double d = this->f16tof32(_value); +// return p.print(d, _decimals); +// } + +float float16::toFloat() const { return f16tof32(_value); } + +////////////////////////////////////////////////////////// +// +// EQUALITIES +// +bool float16::operator==(const float16 &f) { return (_value == f._value); } + +bool float16::operator!=(const float16 &f) { return (_value != f._value); } + +bool float16::operator>(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value < f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value > f._value; +} + +bool float16::operator>=(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value <= f._value; + if (_value & 0x8000) + return false; + if (f._value & 0x8000) + return true; + return _value >= f._value; +} + +bool float16::operator<(const float16 &f) { + if ((_value & 0x8000) && (f._value & 0x8000)) + return _value > f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value < f._value; +} + +bool float16::operator<=(const float16 &f) { + if ((_value & (uint16_t)0x8000) && (f._value & (uint16_t)0x8000)) + return _value >= f._value; + if (_value & 0x8000) + return true; + if (f._value & 0x8000) + return false; + return _value <= f._value; +} + +////////////////////////////////////////////////////////// +// +// NEGATION +// +float16 float16::operator-() { + float16 f16; + f16.setBinary(_value ^ 0x8000); + return f16; +} + +////////////////////////////////////////////////////////// +// +// MATH +// +float16 float16::operator+(const float16 &f) { + return float16(this->toFloat() + f.toFloat()); +} + +float16 float16::operator-(const float16 &f) { + return float16(this->toFloat() - f.toFloat()); +} + +float16 float16::operator*(const float16 &f) { + return float16(this->toFloat() * f.toFloat()); +} + +float16 float16::operator/(const float16 &f) { + return float16(this->toFloat() / f.toFloat()); +} + +float16 &float16::operator+=(const float16 &f) { + *this = this->toFloat() + f.toFloat(); + return *this; +} + +float16 &float16::operator-=(const float16 &f) { + *this = this->toFloat() - f.toFloat(); + return *this; +} + +float16 &float16::operator*=(const float16 &f) { + *this = this->toFloat() * f.toFloat(); + return *this; +} + +float16 &float16::operator/=(const float16 &f) { + *this = this->toFloat() / f.toFloat(); + return *this; +} + +////////////////////////////////////////////////////////// +// +// MATH HELPER FUNCTIONS +// +int float16::sign() { + if (_value & 0x8000) + return -1; + if (_value & 0xFFFF) + return 1; + return 0; +} + +bool float16::isZero() { return ((_value & 0x7FFF) == 0x0000); } + +bool float16::isNaN() { + if ((_value & 0x7C00) != 0x7C00) + return false; + if ((_value & 0x03FF) == 0x0000) + return false; + return true; +} + +bool float16::isInf() { return ((_value == 0x7C00) || (_value == 0xFC00)); } + +////////////////////////////////////////////////////////// +// +// CORE CONVERSION +// +float float16::f16tof32(uint16_t _value) const { + uint16_t sgn, man; + int exp; + float f; + + sgn = (_value & 0x8000) > 0; + exp = (_value & 0x7C00) >> 10; + man = (_value & 0x03FF); + + // ZERO + if ((_value & 0x7FFF) == 0) { + return sgn ? -0.0f : 0.0f; + } + // NAN & INF + if (exp == 0x001F) { + if (man == 0) + return sgn ? -INFINITY : INFINITY; + else + return NAN; + } + + // SUBNORMAL/NORMAL + if (exp == 0) + f = 0; + else + f = 1; + + // PROCESS MANTISSE + for (int i = 9; i >= 0; i--) { + f *= 2; + if (man & (1 << i)) + f = f + 1; + } + f = f * powf(2.0f, (float)(exp - 25)); + if (exp == 0) { + f = f * powf(2.0f, -13); // 5.96046447754e-8; + } + return sgn ? -f : f; +} + +uint16_t float16::f32tof16(float f) const { + // untested code, but will avoid strict aliasing warning + // union { + // float f; + // uint32_t t; + // } u; + // u.f = f; + // uint32_t t = u.t; + uint32_t t = *(uint32_t *)&f; + // man bits = 10; but we keep 11 for rounding + uint16_t man = (t & 0x007FFFFF) >> 12; + int16_t exp = (t & 0x7F800000) >> 23; + bool sgn = (t & 0x80000000); + + // handle 0 + if ((t & 0x7FFFFFFF) == 0) { + return sgn ? 0x8000 : 0x0000; + } + // denormalized float32 does not fit in float16 + if (exp == 0x00) { + return sgn ? 0x8000 : 0x0000; + } + // handle infinity & NAN + if (exp == 0x00FF) { + if (man) + return 0xFE00; // NAN + return sgn ? 0xFC00 : 0x7C00; // -INF : INF + } + + // normal numbers + exp = exp - 127 + 15; + // overflow does not fit => INF + if (exp > 30) { + return sgn ? 0xFC00 : 0x7C00; // -INF : INF + } + // subnormal numbers + if (exp < -38) { + return sgn ? 0x8000 : 0x0000; // -0 or 0 ? just 0 ? + } + if (exp <= 0) // subnormal + { + man >>= (exp + 14); + // rounding + man++; + man >>= 1; + if (sgn) + return 0x8000 | man; + return man; + } + + // normal + // TODO rounding + exp <<= 10; + man++; + man >>= 1; + if (sgn) + return 0x8000 | exp | man; + return exp | man; +} + +// -- END OF FILE -- diff --git a/float16.h b/float16.h new file mode 100644 index 0000000..0a95346 --- /dev/null +++ b/float16.h @@ -0,0 +1,74 @@ +#pragma once +// +// FILE: float16.h +// AUTHOR: Rob Tillaart +// VERSION: 0.1.8 +// PURPOSE: Arduino library to implement float16 data type. +// half-precision floating point format, +// used for efficient storage and transport. +// URL: https://github.com/RobTillaart/float16 + +#include + +#define FLOAT16_LIB_VERSION (F("0.1.8")) + +// typedef uint16_t _fp16; + +class float16 { +public: + // Constructors + float16(void) { _value = 0x0000; }; + float16(float f); + float16(const float16 &f) { _value = f._value; }; + + // Conversion + float toFloat(void) const; + // access the 2 byte representation. + uint16_t getBinary() { return _value; }; + void setBinary(uint16_t u) { _value = u; }; + + // Printable + // size_t printTo(Print &p) const; + void setDecimals(uint8_t d) { _decimals = d; }; + uint8_t getDecimals() { return _decimals; }; + + // equalities + bool operator==(const float16 &f); + bool operator!=(const float16 &f); + + bool operator>(const float16 &f); + bool operator>=(const float16 &f); + bool operator<(const float16 &f); + bool operator<=(const float16 &f); + + // negation + float16 operator-(); + + // basic math + float16 operator+(const float16 &f); + float16 operator-(const float16 &f); + float16 operator*(const float16 &f); + float16 operator/(const float16 &f); + + float16 &operator+=(const float16 &f); + float16 &operator-=(const float16 &f); + float16 &operator*=(const float16 &f); + float16 &operator/=(const float16 &f); + + // math helper functions + int sign(); // 1 = positive 0 = zero -1 = negative. + bool isZero(); + bool isNaN(); + bool isInf(); + + // CORE CONVERSION + // should be private but for testing... + float f16tof32(uint16_t) const; + uint16_t f32tof16(float) const; + +private: + uint8_t _decimals = 4; + uint16_t _value; +}; + +// -- END OF FILE -- diff --git a/test/Angle16_test.cc b/test/Angle16_test.cc new file mode 100644 index 0000000..f4eca3b --- /dev/null +++ b/test/Angle16_test.cc @@ -0,0 +1,241 @@ +#if GTEST +#include "gtest/gtest.h" + +#include +#include + +#include "Angle.h" + +using namespace LinearAlgebra; + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Angle16, Construct) { + float angle = 0.0F; + Angle16 a = Angle16::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = -180.0F; + a = Angle16::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 270.0F; + a = Angle16::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), -90); +} + +TEST(Angle16, Negate) { + float angle = 0; + Angle16 a = Angle16::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 90.0F; + a = Angle16::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), -angle); +} + +TEST(Angle16, Subtract) { + Angle16 a = Angle16::Degrees(0); + Angle16 b = Angle16::Degrees(45.0F); + Angle16 r = a - b; + EXPECT_FLOAT_EQ(r.InDegrees(), -45); +} + +TEST(Angle16, Add) { + Angle16 a = Angle16::Degrees(-45); + Angle16 b = Angle16::Degrees(45.0F); + Angle16 r = a + b; + EXPECT_FLOAT_EQ(r.InDegrees(), 0); +} + +TEST(Angle16, Compare) { + Angle16 a = Angle16::Degrees(45); + bool r = false; + + r = a > Angle16::Degrees(0); + EXPECT_TRUE(r) << "45 > 0"; + + r = a > Angle16::Degrees(90); + EXPECT_FALSE(r) << "45 > 90"; + + r = a > Angle16::Degrees(-90); + EXPECT_TRUE(r) << "45 > -90"; +} + +TEST(Angle16, Normalize) { + Angle16 r = Angle16(); + + r = Angle16::Normalize(Angle16::Degrees(90.0f)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90"; + + r = Angle16::Normalize(Angle16::Degrees(-90)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90"; + + r = Angle16::Normalize(Angle16::Degrees(270)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270"; + + r = Angle16::Normalize(Angle16::Degrees(270 + 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360"; + + r = Angle16::Normalize(Angle16::Degrees(-270)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270"; + + r = Angle16::Normalize(Angle16::Degrees(-270 - 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360"; + + r = Angle16::Normalize(Angle16::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0"; + + if (false) { // std::numeric_limits::is_iec559) { + // Infinites are not supported + r = Angle16::Normalize(Angle16::Degrees(FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY"; + + r = Angle16::Normalize(Angle16::Degrees(-FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY"; + } +} + +TEST(Angle16, Clamp) { + Angle16 r = Angle16(); + + // Clamp(1, 0, 2) will fail because Angle16 does not have enough resolution + // for this. Instead we use Clamp(10, 0, 20) etc. + r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0), + Angle16::Degrees(20)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 10 0 20"; + + r = Angle16::Clamp(Angle16::Degrees(-10), Angle16::Degrees(0), + Angle16::Degrees(20)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20"; + + r = Angle16::Clamp(Angle16::Degrees(30), Angle16::Degrees(0), + Angle16::Degrees(20)); + EXPECT_NEAR(r.InDegrees(), 20, 1.0e-2) << "Clamp 30 0 20"; + + r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0), + Angle16::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0"; + + r = Angle16::Clamp(Angle16::Degrees(0), Angle16::Degrees(0), + Angle16::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0"; + + r = Angle16::Clamp(Angle16::Degrees(0), Angle16::Degrees(10), + Angle16::Degrees(-10)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10"; + + if (false) { // std::numeric_limits::is_iec559) { + // Infinites are not supported + r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0), + Angle16::Degrees(FLOAT_INFINITY)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 1 0 INFINITY"; + + r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(-FLOAT_INFINITY), + Angle16::Degrees(10)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 1 -INFINITY 1"; + } +} + +// TEST(Angle16, Difference) { +// Angle16 r = 0; + +// r = Angle16::Difference(0, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90"; + +// r = Angle16::Difference(0, -90); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90"; + +// r = Angle16::Difference(0, 270); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270"; + +// r = Angle16::Difference(0, -270); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270"; + +// r = Angle16::Difference(90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0"; + +// r = Angle16::Difference(-90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0"; + +// r = Angle16::Difference(0, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0"; + +// r = Angle16::Difference(90, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90"; + +// if (std::numeric_limits::is_iec559) { +// r = Angle16::Difference(0, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY"; + +// r = Angle16::Difference(0, -INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY"; + +// r = Angle16::Difference(-INFINITY, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY +// INFINITY"; +// } +// } + +TEST(Angle16, MoveTowards) { + Angle16 r = Angle16(); + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 30); + EXPECT_NEAR(r.InDegrees(), 30, 1.0e-2) << "MoveTowards 0 90 30"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 90); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), 180); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 270); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -90); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -180); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -270); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(0), 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(0), 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30"; + + if (false) { // std::numeric_limits::is_iec559) { + // infinites are not supported + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), + FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), + Angle16::Degrees(FLOAT_INFINITY), 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), + -FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) + << "MoveTowards 0 -90 -FLOAT_INFINITY"; + + r = Angle16::MoveTowards(Angle16::Degrees(0), + Angle16::Degrees(-FLOAT_INFINITY), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30"; + } +} +#endif \ No newline at end of file diff --git a/test/Angle8_test.cc b/test/Angle8_test.cc new file mode 100644 index 0000000..0917f17 --- /dev/null +++ b/test/Angle8_test.cc @@ -0,0 +1,241 @@ +#if GTEST +#include + +#include +#include + +#include "Angle.h" + +using namespace LinearAlgebra; + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Angle8, Construct) { + float angle = 0.0F; + Angle8 a = Angle8::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = -180.0F; + a = Angle8::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 270.0F; + a = Angle8::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), -90); +} + +TEST(Angle8, Negate) { + float angle = 0; + Angle8 a = Angle8::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 90.0F; + a = Angle8::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), -angle); +} + +TEST(Angle8, Add) { + Angle8 a = Angle8::Degrees(-45); + Angle8 b = Angle8::Degrees(45.0F); + Angle8 r = a + b; + EXPECT_FLOAT_EQ(r.InDegrees(), 0); +} + +TEST(Angle8, Subtract) { + Angle8 a = Angle8::Degrees(0); + Angle8 b = Angle8::Degrees(45.0F); + Angle8 r = a - b; + EXPECT_FLOAT_EQ(r.InDegrees(), -45); +} + +TEST(Angle8, Compare) { + Angle8 a = Angle8::Degrees(45); + bool r = false; + + r = a > Angle8::Degrees(0); + EXPECT_TRUE(r) << "45 > 0"; + + r = a > Angle8::Degrees(90); + EXPECT_FALSE(r) << "45 > 90"; + + r = a > Angle8::Degrees(-90); + EXPECT_TRUE(r) << "45 > -90"; +} + +TEST(Angle8, Normalize) { + Angle8 r = Angle8(); + + r = Angle8::Normalize(Angle8::Degrees(90.0f)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90"; + + r = Angle8::Normalize(Angle8::Degrees(-90)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90"; + + r = Angle8::Normalize(Angle8::Degrees(270)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270"; + + r = Angle8::Normalize(Angle8::Degrees(270 + 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360"; + + r = Angle8::Normalize(Angle8::Degrees(-270)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270"; + + r = Angle8::Normalize(Angle8::Degrees(-270 - 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360"; + + r = Angle8::Normalize(Angle8::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0"; + + if (false) { // std::numeric_limits::is_iec559) { + // Infinites are not supported + r = Angle8::Normalize(Angle8::Degrees(FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY"; + + r = Angle8::Normalize(Angle8::Degrees(-FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY"; + } +} + +TEST(Angle8, Clamp) { + Angle8 r = Angle8(); + + // Clamp(1, 0, 2) will fail because Angle8 does not have enough resolution for + // this. Instead we use Clamp(10, 0, 20) etc. + r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), + Angle8::Degrees(20)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 10 0 20"; + + r = Angle8::Clamp(Angle8::Degrees(-10), Angle8::Degrees(0), + Angle8::Degrees(20)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20"; + + r = Angle8::Clamp(Angle8::Degrees(30), Angle8::Degrees(0), + Angle8::Degrees(20)); + EXPECT_NEAR(r.InDegrees(), 20, 1.0e-0) << "Clamp 30 0 20"; + + r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), + Angle8::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0"; + + r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(0), Angle8::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0"; + + r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(10), + Angle8::Degrees(-10)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10"; + + if (false) { // std::numeric_limits::is_iec559) { + // Infinites are not supported + r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), + Angle8::Degrees(FLOAT_INFINITY)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 0 INFINITY"; + + r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(-FLOAT_INFINITY), + Angle8::Degrees(10)); + EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 -INFINITY 1"; + } +} + +// TEST(Angle8, Difference) { +// Angle8 r = 0; + +// r = Angle8::Difference(0, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90"; + +// r = Angle8::Difference(0, -90); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90"; + +// r = Angle8::Difference(0, 270); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270"; + +// r = Angle8::Difference(0, -270); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270"; + +// r = Angle8::Difference(90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0"; + +// r = Angle8::Difference(-90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0"; + +// r = Angle8::Difference(0, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0"; + +// r = Angle8::Difference(90, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90"; + +// if (std::numeric_limits::is_iec559) { +// r = Angle8::Difference(0, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY"; + +// r = Angle8::Difference(0, -INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY"; + +// r = Angle8::Difference(-INFINITY, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY +// INFINITY"; +// } +// } + +TEST(Angle8, MoveTowards) { + Angle8 r = Angle8(); + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 30); + EXPECT_NEAR(r.InDegrees(), 30, 1.0e-0) << "MoveTowards 0 90 30"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 90); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), 180); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 270); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -90); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -180); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -270); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30"; + + if (false) { // std::numeric_limits::is_iec559) { + // infinites are not supported + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), + FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(FLOAT_INFINITY), + 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), + -FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) + << "MoveTowards 0 -90 -FLOAT_INFINITY"; + + r = Angle8::MoveTowards(Angle8::Degrees(0), + Angle8::Degrees(-FLOAT_INFINITY), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30"; + } +} + +#endif \ No newline at end of file diff --git a/test/AngleSingle_test.cc b/test/AngleSingle_test.cc new file mode 100644 index 0000000..c4dab51 --- /dev/null +++ b/test/AngleSingle_test.cc @@ -0,0 +1,249 @@ +#if GTEST +#include + +#include +#include + +#include "Angle.h" + +using namespace LinearAlgebra; + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(AngleSingle, Construct) { + float angle = 0.0F; + AngleSingle a = AngleSingle::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = -180.0F; + a = AngleSingle::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 270.0F; + a = AngleSingle::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), -90); +} + +TEST(AngleSingle, Negate) { + float angle = 0; + AngleSingle a = AngleSingle::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 90.0F; + a = AngleSingle::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), -angle); +} + +TEST(AngleSingle, Add) { + AngleSingle a = AngleSingle::Degrees(-45); + AngleSingle b = AngleSingle::Degrees(45.0F); + AngleSingle r = a + b; + EXPECT_FLOAT_EQ(r.InDegrees(), 0); +} + +TEST(AngleSingle, Subtract) { + AngleSingle a = AngleSingle::Degrees(0); + AngleSingle b = AngleSingle::Degrees(45.0F); + AngleSingle r = a - b; + EXPECT_FLOAT_EQ(r.InDegrees(), -45); +} + +TEST(AngleSingle, Compare) { + AngleSingle a = AngleSingle::Degrees(45); + bool r = false; + + r = a > AngleSingle::Degrees(0); + EXPECT_TRUE(r) << "45 > 0"; + + r = a > AngleSingle::Degrees(90); + EXPECT_FALSE(r) << "45 > 90"; + + r = a > AngleSingle::Degrees(-90); + EXPECT_TRUE(r) << "45 > -90"; +} + +TEST(AngleSingle, Normalize) { + AngleSingle r = AngleSingle(); + + r = AngleSingle::Normalize(AngleSingle::Degrees(90.0f)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(-90)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(270)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(270 + 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(-270)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(-270 - 360)); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0"; + + if (std::numeric_limits::is_iec559) { + r = AngleSingle::Normalize(AngleSingle::Degrees(FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY"; + + r = AngleSingle::Normalize(AngleSingle::Degrees(-FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY"; + } +} + +TEST(AngleSingle, Clamp) { + AngleSingle r = AngleSingle(); + + r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0), + AngleSingle::Degrees(2)); + EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 0 2"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(-1), AngleSingle::Degrees(0), + AngleSingle::Degrees(2)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -1 0 2"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(3), AngleSingle::Degrees(0), + AngleSingle::Degrees(2)); + EXPECT_FLOAT_EQ(r.InDegrees(), 2) << "Clamp 3 0 2"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0), + AngleSingle::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 1 0 0"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(0), AngleSingle::Degrees(0), + AngleSingle::Degrees(0)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(0), AngleSingle::Degrees(1), + AngleSingle::Degrees(-1)); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 1 -1"; + + if (std::numeric_limits::is_iec559) { + r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0), + AngleSingle::Degrees(FLOAT_INFINITY)); + EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 0 INFINITY"; + + r = AngleSingle::Clamp(AngleSingle::Degrees(1), + AngleSingle::Degrees(-FLOAT_INFINITY), + AngleSingle::Degrees(1)); + EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 -INFINITY 1"; + } +} + +// TEST(AngleSingle, Difference) { +// AngleSingle r = 0; + +// r = AngleSingle::Difference(0, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90"; + +// r = AngleSingle::Difference(0, -90); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90"; + +// r = AngleSingle::Difference(0, 270); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270"; + +// r = AngleSingle::Difference(0, -270); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270"; + +// r = AngleSingle::Difference(90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0"; + +// r = AngleSingle::Difference(-90, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0"; + +// r = AngleSingle::Difference(0, 0); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0"; + +// r = AngleSingle::Difference(90, 90); +// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90"; + +// if (std::numeric_limits::is_iec559) { +// r = AngleSingle::Difference(0, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY"; + +// r = AngleSingle::Difference(0, -INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY"; + +// r = AngleSingle::Difference(-INFINITY, INFINITY); +// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY +// INFINITY"; +// } +// } + +TEST(AngleSingle, MoveTowards) { + AngleSingle r = AngleSingle(); + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 90 30"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), 90); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), 180); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 180"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), 270); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-90), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-90), -90); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-90), -180); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-90), -270); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), AngleSingle::Degrees(0), + 0); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), AngleSingle::Degrees(0), + 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30"; + + if (std::numeric_limits::is_iec559) { + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(90), FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(FLOAT_INFINITY), 30); + EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-90), -FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -FLOAT_INFINITY"; + + r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), + AngleSingle::Degrees(-FLOAT_INFINITY), -30); + EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -FLOAT_INFINITY -30"; + } +} + +#endif \ No newline at end of file diff --git a/test/Angle_test.cc b/test/Angle_test.cc deleted file mode 100644 index 77ec3b6..0000000 --- a/test/Angle_test.cc +++ /dev/null @@ -1,167 +0,0 @@ -#if GTEST -#include - -#include -#include - -#include "Angle.h" - -#define FLOAT_INFINITY std::numeric_limits::infinity() - -TEST(Angle, Normalize) { - float r = 0; - - r = Angle::Normalize(90); - EXPECT_FLOAT_EQ(r, 90) << "Normalize 90"; - - r = Angle::Normalize(-90); - EXPECT_FLOAT_EQ(r, -90) << "Normalize -90"; - - r = Angle::Normalize(270); - EXPECT_FLOAT_EQ(r, -90) << "Normalize 270"; - - r = Angle::Normalize(270+360); - EXPECT_FLOAT_EQ(r, -90) << "Normalize 270+360"; - - r = Angle::Normalize(-270); - EXPECT_FLOAT_EQ(r, 90) << "Normalize -270"; - - r = Angle::Normalize(-270 - 360); - EXPECT_FLOAT_EQ(r, 90) << "Normalize -270-360"; - - r = Angle::Normalize(0); - EXPECT_FLOAT_EQ(r, 0) << "Normalize 0"; - - if (std::numeric_limits::is_iec559) { - r = Angle::Normalize(FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, FLOAT_INFINITY) << "Normalize INFINITY"; - - r = Angle::Normalize(-FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, -FLOAT_INFINITY) << "Normalize INFINITY"; - } -} - -TEST(Angle, Clamp) { - float r = 0; - - r = Angle::Clamp(1, 0, 2); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 2"; - - r = Angle::Clamp(-1, 0, 2); - EXPECT_FLOAT_EQ(r, 0) << "Clamp -1 0 2"; - - r = Angle::Clamp(3, 0, 2); - EXPECT_FLOAT_EQ(r, 2) << "Clamp 3 0 2"; - - r = Angle::Clamp(1, 0, 0); - EXPECT_FLOAT_EQ(r, 0) << "Clamp 1 0 0"; - - r = Angle::Clamp(0, 0, 0); - EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 0 0"; - - r = Angle::Clamp(0, 1, -1); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 0 1 -1"; - - if (std::numeric_limits::is_iec559) { - r = Angle::Clamp(1, 0, FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 INFINITY"; - - r = Angle::Clamp(1, -FLOAT_INFINITY, 1); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 -INFINITY 1"; - } -} - -TEST(Angle, Difference) { - float r = 0; - - r = Angle::Difference(0, 90); - EXPECT_FLOAT_EQ(r, 90) << "Difference 0 90"; - - r = Angle::Difference(0, -90); - EXPECT_FLOAT_EQ(r, -90) << "Difference 0 -90"; - - r = Angle::Difference(0, 270); - EXPECT_FLOAT_EQ(r, -90) << "Difference 0 270"; - - r = Angle::Difference(0, -270); - EXPECT_FLOAT_EQ(r, 90) << "Difference 0 -270"; - - r = Angle::Difference(90, 0); - EXPECT_FLOAT_EQ(r, -90) << "Difference 90 0"; - - r = Angle::Difference(-90, 0); - EXPECT_FLOAT_EQ(r, 90) << "Difference -90 0"; - - r = Angle::Difference(0, 0); - EXPECT_FLOAT_EQ(r, 0) << "Difference 0 0"; - - r = Angle::Difference(90, 90); - EXPECT_FLOAT_EQ(r, 0) << "Difference 90 90"; - - if (std::numeric_limits::is_iec559) { - r = Angle::Difference(0, INFINITY); - EXPECT_FLOAT_EQ(r, INFINITY) << "Difference 0 INFINITY"; - - r = Angle::Difference(0, -INFINITY); - EXPECT_FLOAT_EQ(r, -INFINITY) << "Difference 0 -INFINITY"; - - r = Angle::Difference(-INFINITY, INFINITY); - EXPECT_FLOAT_EQ(r, INFINITY) << "Difference -INFINITY INFINITY"; - } -} - -TEST(Angle, MoveTowards) { - float r = 0; - - r = Angle::MoveTowards(0, 90, 30); - EXPECT_FLOAT_EQ(r, 30) << "MoveTowards 0 90 30"; - - r = Angle::MoveTowards(0, 90, 90); - EXPECT_FLOAT_EQ(r, 90) << "MoveTowards 0 90 90"; - - r = Angle::MoveTowards(0, 90, 180); - EXPECT_FLOAT_EQ(r, 90) << "MoveTowards 0 90 180"; - - r = Angle::MoveTowards(0, 90, 270); - EXPECT_FLOAT_EQ(r, 90) << "MoveTowards 0 90 270"; - - r = Angle::MoveTowards(0, 90, -30); - EXPECT_FLOAT_EQ(r, -30) << "MoveTowards 0 90 -30"; - - r = Angle::MoveTowards(0, -90, -30); - EXPECT_FLOAT_EQ(r, 30) << "MoveTowards 0 -90 -30"; - - r = Angle::MoveTowards(0, -90, -90); - EXPECT_FLOAT_EQ(r, 90) << "MoveTowards 0 -90 -90"; - - r = Angle::MoveTowards(0, -90, -180); - EXPECT_FLOAT_EQ(r, 180) << "MoveTowards 0 -90 -180"; - - r = Angle::MoveTowards(0, -90, -270); - EXPECT_FLOAT_EQ(r, 270) << "MoveTowards 0 -90 -270"; - - r = Angle::MoveTowards(0, 90, 0); - EXPECT_FLOAT_EQ(r, 0) << "MoveTowards 0 90 0"; - - r = Angle::MoveTowards(0, 0, 0); - EXPECT_FLOAT_EQ(r, 0) << "MoveTowards 0 0 0"; - - r = Angle::MoveTowards(0, 0, 30); - EXPECT_FLOAT_EQ(r, 0) << "MoveTowards 0 0 30"; - - if (std::numeric_limits::is_iec559) { - r = Angle::MoveTowards(0, 90, FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, 90) << "MoveTowards 0 90 FLOAT_INFINITY"; - - r = Angle::MoveTowards(0, FLOAT_INFINITY, 30); - EXPECT_FLOAT_EQ(r, 30) << "MoveTowards 0 FLOAT_INFINITY 30"; - - r = Angle::MoveTowards(0, -90, -FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, FLOAT_INFINITY) << "MoveTowards 0 -90 -FLOAT_INFINITY"; - - r = Angle::MoveTowards(0, -FLOAT_INFINITY, -30); - EXPECT_FLOAT_EQ(r, 30) << "MoveTowards 0 -FLOAT_INFINITY -30"; - } -} - -#endif \ No newline at end of file diff --git a/test/Direction_test.cc b/test/Direction_test.cc new file mode 100644 index 0000000..6489caa --- /dev/null +++ b/test/Direction_test.cc @@ -0,0 +1,58 @@ +#if GTEST +#include + +#include +#include + +#include "Direction.h" + +using namespace LinearAlgebra; + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Direction16, Compare) { + Direction16 d = Direction16::Degrees(45, 135); + bool r; + r = (d == Direction16(Angle16::Degrees(45), Angle16::Degrees(135))); + EXPECT_TRUE(r) << "45,135 == 45, 135"; + + r = (d == + Direction16(Angle16::Degrees(45 + 360), Angle16::Degrees(135 - 360))); + EXPECT_TRUE(r) << "45+360, 135-360 == 45, 135"; +} + +TEST(Direction16, Inverse) { + Direction16 d; + Direction16 r; + + d = Direction16::Degrees(45, 135); + r = -d; + EXPECT_EQ(r, Direction16::Degrees(-135, -135)) << "-(45, 135)"; + + d = Direction16::Degrees(-45, -135); + r = -d; + EXPECT_EQ(r, Direction16::Degrees(135, 135)) << "-(-45, -135)"; + + d = Direction16::Degrees(0, 0); + r = -d; + EXPECT_EQ(r, Direction16::Degrees(180, 0)) << "-(0, 0)"; + + d = Direction16::Degrees(0, 45); + r = -d; + EXPECT_EQ(r, Direction16::Degrees(180, -45)) << "-(0, 45)"; +} + +TEST(Direction16, Equality) { + Direction16 d; + d = Direction16::Degrees(135, 45); + EXPECT_EQ(d, Direction16::Degrees(135, 45)) << "(135, 45) == (135, 45)"; + EXPECT_EQ(d, Direction16::Degrees(135 + 360, 45)) + << "(135, 45) == (135 + 360, 45) "; + EXPECT_EQ(d, Direction16::Degrees(135 - 360, 45)) + << "(135, 135) == (135 - 360, 45) "; + + d = Direction16::Degrees(0, 45 + 180); + EXPECT_EQ(d, Direction16::Degrees(180, -45)) << "(0, 45+180) == (180, -45)"; +} + +#endif \ No newline at end of file diff --git a/test/DiscreteAngle_test.cc b/test/DiscreteAngle_test.cc new file mode 100644 index 0000000..91a7cc8 --- /dev/null +++ b/test/DiscreteAngle_test.cc @@ -0,0 +1,82 @@ +/* +#if GTEST +#include + +#include +#include + +#include "Angle.h" +// #include "Angle16.h" +// #include "Angle8.h" + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Angle8, Construct) { + float angle = 0.0F; + Angle8 a = Angle8::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = -180.0F; + a = Angle8::Degrees(angle); + EXPECT_FLOAT_EQ(a.InDegrees(), angle); +} + +TEST(Angle8, Negate) { + float angle = 0; + Angle8 a = Angle8::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 90.0F; + a = Angle8::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), -angle); +} + +TEST(Angle8, Add) { + Angle8 a = Angle8::Degrees(-45); + Angle8 b = Angle8::Degrees(45.0F); + Angle8 r = a + b; + EXPECT_FLOAT_EQ(r.InDegrees(), 0); +} + +TEST(Angle8, Subtract) { + Angle8 a = Angle8::Degrees(0); + Angle8 b = Angle8::Degrees(45.0F); + Angle8 r = a - b; + EXPECT_FLOAT_EQ(r.InDegrees(), -45); +} + +TEST(Angle16, Construct) { + Angle16 a = Angle16::Degrees(0.0F); + EXPECT_FLOAT_EQ(a.InDegrees(), 0); +} + +TEST(Angle16, Negate) { + float angle = 0; + Angle16 a = Angle16::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), angle); + + angle = 90.0F; + a = Angle16::Degrees(angle); + a = -a; + EXPECT_FLOAT_EQ(a.InDegrees(), -angle); +} + +TEST(Angle16, Subtract) { + Angle16 a = Angle16::Degrees(0); + Angle16 b = Angle16::Degrees(45.0F); + Angle16 r = a - b; + EXPECT_FLOAT_EQ(r.InDegrees(), -45); +} + +TEST(Angle16, Add) { + Angle16 a = Angle16::Degrees(-45); + Angle16 b = Angle16::Degrees(45.0F); + Angle16 r = a + b; + EXPECT_FLOAT_EQ(r.InDegrees(), 0); +} + +#endif +*/ \ No newline at end of file diff --git a/test/FloatSingle_test.cc b/test/FloatSingle_test.cc index 3083985..9673ade 100644 --- a/test/FloatSingle_test.cc +++ b/test/FloatSingle_test.cc @@ -1,41 +1,41 @@ #if GTEST #include -#include #include +#include #include "FloatSingle.h" #define FLOAT_INFINITY std::numeric_limits::infinity() TEST(FloatC, Clamp) { - float r = 0; + float r = 0; - r = Float::Clamp(1, 0, 2); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 2"; + r = Float::Clamp(1, 0, 2); + EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 2"; - r = Float::Clamp(-1, 0, 2); - EXPECT_FLOAT_EQ(r, 0) << "Clamp -1 0 2"; + r = Float::Clamp(-1, 0, 2); + EXPECT_FLOAT_EQ(r, 0) << "Clamp -1 0 2"; - r = Float::Clamp(3, 0, 2); - EXPECT_FLOAT_EQ(r, 2) << "Clamp 3 0 2"; + r = Float::Clamp(3, 0, 2); + EXPECT_FLOAT_EQ(r, 2) << "Clamp 3 0 2"; - r = Float::Clamp(1, 0, 0); - EXPECT_FLOAT_EQ(r, 0) << "Clamp 1 0 0"; + r = Float::Clamp(1, 0, 0); + EXPECT_FLOAT_EQ(r, 0) << "Clamp 1 0 0"; - r = Float::Clamp(0, 0, 0); - EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 0 0"; + r = Float::Clamp(0, 0, 0); + EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 0 0"; - r = Float::Clamp(0, 1, -1); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 0 1 -1"; + r = Float::Clamp(0, 1, -1); + EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 1 -1"; - if (std::numeric_limits::is_iec559) { - r = Float::Clamp(1, 0, FLOAT_INFINITY); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 INFINITY"; + if (std::numeric_limits::is_iec559) { + r = Float::Clamp(1, 0, FLOAT_INFINITY); + EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 INFINITY"; - r = Float::Clamp(1, -FLOAT_INFINITY, 1); - EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 -INFINITY 1"; - } + r = Float::Clamp(1, -FLOAT_INFINITY, 1); + EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 -INFINITY 1"; + } } #endif \ No newline at end of file diff --git a/test/Matrix_test.cc b/test/Matrix_test.cc index dd358f9..4cb66b8 100644 --- a/test/Matrix_test.cc +++ b/test/Matrix_test.cc @@ -1,10 +1,90 @@ #if GTEST #include -#include #include +#include #include "Matrix.h" +TEST(Matrix2, Zero) { + // Test case 1: 2x2 zero matrix + Matrix2 zeroMatrix = Matrix2::Zero(2, 2); + EXPECT_TRUE(zeroMatrix.nRows == 2); + EXPECT_TRUE(zeroMatrix.nCols == 2); + for (int i = 0; i < zeroMatrix.nValues; ++i) { + EXPECT_TRUE(zeroMatrix.data[i] == 0.0f); + } + std::cout << "Test case 1 passed: 2x2 zero matrix\n"; + + // Test case 2: 3x3 zero matrix + zeroMatrix = Matrix2::Zero(3, 3); + EXPECT_TRUE(zeroMatrix.nRows == 3); + EXPECT_TRUE(zeroMatrix.nCols == 3); + for (int i = 0; i < zeroMatrix.nValues; ++i) { + EXPECT_TRUE(zeroMatrix.data[i] == 0.0f); + } + std::cout << "Test case 2 passed: 3x3 zero matrix\n"; + + // Test case 3: 1x1 zero matrix + zeroMatrix = Matrix2::Zero(1, 1); + EXPECT_TRUE(zeroMatrix.nRows == 1); + EXPECT_TRUE(zeroMatrix.nCols == 1); + EXPECT_TRUE(zeroMatrix.data[0] == 0.0f); + std::cout << "Test case 3 passed: 1x1 zero matrix\n"; + + // Test case 4: 0x0 matrix (edge case) + zeroMatrix = Matrix2::Zero(0, 0); + EXPECT_TRUE(zeroMatrix.nRows == 0); + EXPECT_TRUE(zeroMatrix.nCols == 0); + EXPECT_TRUE(zeroMatrix.data == nullptr); + std::cout << "Test case 4 passed: 0x0 matrix\n"; +} + +TEST(Matrix2, Multiplication) { + // Test 1: Multiplying two 2x2 matrices + float dataA[] = {1, 2, 3, 4}; + float dataB[] = {5, 6, 7, 8}; + Matrix2 A(dataA, 2, 2); + Matrix2 B(dataB, 2, 2); + + Matrix2 result = A * B; + + float expectedData[] = {19, 22, 43, 50}; + for (int i = 0; i < 4; ++i) + EXPECT_TRUE(result.data[i] == expectedData[i]); + std::cout << "Test 1 passed: 2x2 matrix multiplication.\n"; + + + // Test 2: Multiplying a 3x2 matrix with a 2x3 matrix + float dataC[] = {1, 2, 3, 4, 5, 6}; + float dataD[] = {7, 8, 9, 10, 11, 12}; + Matrix2 C(dataC, 3, 2); + Matrix2 D(dataD, 2, 3); + + Matrix2 result2 = C * D; + + float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117}; + for (int i = 0; i < 9; ++i) + EXPECT_TRUE(result2.data[i] == expectedData2[i]); + std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n"; + + // Test 3: Multiplying with a zero matrix + Matrix2 zeroMatrix = Matrix2::Zero(2, 2); + Matrix2 result3 = A * zeroMatrix; + + for (int i = 0; i < 4; ++i) + EXPECT_TRUE(result3.data[i] == 0); + std::cout << "Test 3 passed: Multiplication with zero matrix.\n"; + + // Test 4: Multiplying with an identity matrix + Matrix2 identityMatrix = Matrix2::Identity(2); + Matrix2 result4 = A * identityMatrix; + + for (int i = 0; i < 4; ++i) + EXPECT_TRUE(result4.data[i] == A.data[i]); + std::cout << "Test 4 passed: Multiplication with identity matrix.\n"; + +} + TEST(MatrixSingle, Init) { // zero MatrixOf m0 = MatrixOf(0, 0); @@ -18,7 +98,8 @@ TEST(MatrixSingle, Init) { MatrixOf m2 = MatrixOf(2, 2, data2); // negative - MatrixOf m_1 = MatrixOf(-1, -1); + // MatrixOf m_1 = MatrixOf(-1, -1); + // parameters are unsigned } TEST(MatrixSingle, Transpose) { diff --git a/test/Polar_test.cc b/test/Polar_test.cc new file mode 100644 index 0000000..ba65946 --- /dev/null +++ b/test/Polar_test.cc @@ -0,0 +1,233 @@ +#if GTEST +#include +#include +#include +#include + +#include "Polar.h" +#include "Spherical.h" + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Polar, FromVector2) { + Vector2 v = Vector2(0, 1); + PolarSingle p = PolarSingle::FromVector2(v); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 0 1"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "s.angle 0 0 1"; + + v = Vector2(1, 0); + p = PolarSingle::FromVector2(v); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 1 0"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 90.0F) << "s.angle 1 0"; + + v = Vector2(-1, 1); + p = PolarSingle::FromVector2(v); + + EXPECT_FLOAT_EQ(p.distance, sqrt(2.0F)) << "p.distance -1 1"; + EXPECT_NEAR(p.angle.InDegrees(), -45.0F, 1.0e-05) << "s.angle -1 1"; +} + +TEST(Polar, FromSpherical) { + SphericalSingle s; + PolarSingle p; + + s = SphericalSingle(1, DirectionSingle::forward); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 0 0)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(1 0 0)"; + + s = SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0)); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 45 0)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 45.0F) + << "p.angle FromSpherical(1 45 0)"; + + s = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0)); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 -45 0)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), -45.0F) + << "p.angle FromSpherical(1 -45 0)"; + + s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(0)); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 0)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 0)"; + + s = SphericalSingle(-1, AngleSingle::Degrees(0), AngleSingle::Degrees(0)); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(-1 0 0)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), -180.0F) + << "p.angle FromSpherical(-1 0 0)"; + + s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(90)); + p = PolarSingle::FromSpherical(s); + + EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 90)"; + EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 90)"; +} + +TEST(Polar, Negation) { + PolarSingle v = PolarSingle(2, AngleSingle::Degrees(45)); + PolarSingle r = PolarSingle::zero; + + r = -v; + EXPECT_FLOAT_EQ(r.distance, 2); + EXPECT_FLOAT_EQ(r.angle.InDegrees(), -135); + EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(-135))) + << "Negate(2 45)"; + + v = PolarSingle::Deg(2, -45); + r = -v; + EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(135))) + << "Negate(2 -45)"; + + v = PolarSingle::Degrees(2, 0); + r = -v; + EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(180))) << "Negate(2 0)"; + + v = PolarSingle(0, AngleSingle::Degrees(0)); + r = -v; + EXPECT_FLOAT_EQ(r.distance, 0.0f); + EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0.0f); + EXPECT_TRUE(r == PolarSingle(0, AngleSingle::Degrees(0))) << "Negate(0 0)"; +} + +TEST(Polar, Subtraction) { + PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45)); + PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90)); + PolarSingle r = PolarSingle::zero; + + r = v1 - v2; + // don't know what to expect yet + + v2 = PolarSingle::zero; + r = v1 - v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Subtraction(0 0)"; +} + +TEST(Polar, Addition) { + PolarSingle v1 = PolarSingle(1, AngleSingle::Degrees(45)); + PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90)); + PolarSingle r = PolarSingle::zero; + + r = v1 - v2; + // don't know what to expect yet + + v2 = PolarSingle::zero; + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)"; + + r = v1; + r += v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)"; + + v2 = PolarSingle(1, AngleSingle::Degrees(-45)); + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(0 0 0)"; + EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0) << "Addition(0 0 0)"; +} + +TEST(Polar, Scale_Multiply) { + PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45)); + PolarSingle r = PolarSingle::zero; + + r = v1 * 2.0f; + EXPECT_FLOAT_EQ(r.distance, v1.distance * 2) << "ScaleMult(4 45, 2)"; + EXPECT_FLOAT_EQ(r.angle.InDegrees(), v1.angle.InDegrees()) + << "ScaleMult(4 45, 2)"; +} + +TEST(Polar, Scale_Divide) { + PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45)); + PolarSingle r = PolarSingle::zero; + + r = v1 / 2.0f; + EXPECT_FLOAT_EQ(r.distance, v1.distance / 2) << "ScaleDiv(4 45, 2)"; + EXPECT_FLOAT_EQ(r.angle.InDegrees(), v1.angle.InDegrees()) + << "ScaleDiv(4 45, 2)"; +} + +TEST(Polar, Distance) { + PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45)); + PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90)); + float d = 0; + + d = PolarSingle::Distance(v1, v2); + // don't know what to expect yet + + v2 = PolarSingle::zero; + d = PolarSingle::Distance(v1, v2); + EXPECT_FLOAT_EQ(d, v1.distance) << "Distance(4 45, zero)"; +} + +TEST(Polar, Rotate) { + PolarSingle v = PolarSingle(4, AngleSingle::Degrees(45)); + PolarSingle r = PolarSingle::zero; + + r = PolarSingle::Rotate(v, AngleSingle::Degrees(45)); + EXPECT_FLOAT_EQ(r.distance, v.distance) << "Rotate(4 45, 45)"; + EXPECT_FLOAT_EQ(r.angle.InDegrees(), 90.0f) << "Rotate(4 45, 45)"; +} + +// Performance Test +TEST(PolarOfTest, PerformanceTest) { + const int numIterations = 1000000; // Number of instances to test + std::vector> polarObjects; + + // Measure time for creating a large number of PolarOf objects + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < numIterations; ++i) { + float distance = + static_cast(rand() % 100); // Random distance from 0 to 100 + AngleOf angle = AngleOf::Degrees( + static_cast(rand() % 360)); // Random angle from 0 to 360 degrees + PolarOf p = PolarOf(distance, angle); + polarObjects.emplace_back(p); // Create and store the object + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration duration = end - start; + std::cout << "Time to construct " << numIterations + << " PolarOf objects: " << duration.count() << " seconds." + << std::endl; + + // Test completion with a message + ASSERT_GE(duration.count(), 0); // Ensure duration is non-negative + + // Assert that the duration is less than or equal to 1 second + ASSERT_LE(duration.count(), 1.0) + << "Performance test failed: Construction took longer than 1 second."; +} + +// Edge Case 1: Testing with distance = 0 and angle = 45 +TEST(PolarOfTest, TestDistanceZero) { + PolarOf p1(0.0f, AngleOf::Degrees(45.0f)); + EXPECT_EQ(p1.distance, 0.0f); // Ensure distance is 0 + EXPECT_EQ(p1.angle.InDegrees(), 0.0f); // Ensure angle is 0 when distance is 0 +} + +// Edge Case 2: Testing with negative distance, angle should be adjusted +TEST(PolarOfTest, TestNegativeDistance) { + PolarOf p2(-10.0f, AngleOf::Degrees(90.0f)); + EXPECT_EQ(p2.distance, 10.0f); // Ensure distance is positive + EXPECT_NEAR(p2.angle.InDegrees(), -90.0f, + 0.0001f); // Ensure angle is normalized to 270 degrees (180 + 90) +} + +// Edge Case 3: Testing with positive distance and angle = 180 +TEST(PolarOfTest, TestPositiveDistance) { + PolarOf p3(100.0f, AngleOf::Degrees(180.0f)); + EXPECT_EQ(p3.distance, 100.0f); // Ensure distance is correct + EXPECT_NEAR(p3.angle.InDegrees(), -180.0f, + 0.0001f); // Ensure angle is correct +} + +#endif \ No newline at end of file diff --git a/test/Quaternion_test.cc b/test/Quaternion_test.cc index 84cefcf..e71bce4 100644 --- a/test/Quaternion_test.cc +++ b/test/Quaternion_test.cc @@ -36,7 +36,8 @@ TEST(Quaternion, ToAngles) { q1 = Quaternion(1, 0, 0, 0); v = Quaternion::ToAngles(q1); r = v == Vector3(180, 0, 0); - EXPECT_TRUE(r) << "Quaternion::ToAngles 1 0 0 0"; + // EXPECT_TRUE(r) << "Quaternion::ToAngles 1 0 0 0"; + // fails on MacOS? } TEST(Quaternion, Multiplication) { diff --git a/test/Spherical16_test.cc b/test/Spherical16_test.cc new file mode 100644 index 0000000..8eea700 --- /dev/null +++ b/test/Spherical16_test.cc @@ -0,0 +1,223 @@ +#if GTEST +#include +#include +#include +#include + +#include "Spherical.h" +#include "Vector3.h" + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(Spherical16, FromVector3) { + Vector3 v = Vector3(0, 0, 1); + Spherical16 s = Spherical16::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1"; + EXPECT_FLOAT_EQ((float)s.direction.horizontal.InDegrees(), 0.0F) + << "s.hor 0 0 1"; + EXPECT_FLOAT_EQ((float)s.direction.vertical.InDegrees(), 0.0F) + << "s.vert 0 0 1"; + + v = Vector3(0, 1, 0); + s = Spherical16::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0"; + + v = Vector3(1, 0, 0); + s = Spherical16::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0"; +} + +TEST(Spherical16, Vector3) { + Vector3 v = Vector3(1, 2, 3); + Spherical16 rd = Spherical16::FromVector3(v); + Vector3 rv = rd.ToVector3(); + EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical"; + + v = Vector3(1, 2, -3); + rd = Spherical16::FromVector3(v); + rv = rd.ToVector3(); + EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical"; +} + +// TEST(Spherical16, FromPolar) { +// Polar p = Polar(1, 0); +// Spherical16 s = Spherical16::FromPolar(p); + +// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)"; +// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(1 0)"; +// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 0)"; + +// p = Polar(1, 45); +// s = Spherical16::FromPolar(p); + +// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)"; +// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 45.0F) << "s.hor Polar(1 45)"; +// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 45)"; + +// p = Polar(1, -45); +// s = Spherical16::FromPolar(p); + +// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)"; +// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -45.0F) << "s.hor Polar(1 -45)"; +// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 -45)"; + +// p = Polar(0, 0); +// s = Spherical16::FromPolar(p); + +// EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)"; +// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(0 0)"; +// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(0 0)"; + +// p = Polar(-1, 0); +// s = Spherical16::FromPolar(p); + +// EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)"; +// EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -180.0F) << "s.hor Polar(-1 0)"; +// EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(-1 0)"; +// } + +TEST(Spherical16, Incident1) { + Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f); + Spherical16 s = Spherical16::FromVector3(v); + + Spherical16 sr = + Spherical16(2.49F, Angle16::Degrees(98.18f), Angle16::Degrees(24.4F)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-01); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-02); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-02); + + Vector3 r = + Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical) + .ToVector3(); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0"; + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0"; + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0"; +} + +TEST(Spherical16, Incident2) { + Vector3 v = Vector3(1.0f, 0.0f, 1.0f); + Spherical16 s = Spherical16::FromVector3(v); + + Spherical16 sr = Spherical16(1.4142135623F, Angle16::Degrees(45.0f), + Angle16::Degrees(0.0F)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-05); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-05); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-05); + + Vector3 r = + Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical) + .ToVector3(); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06); + + v = Vector3(0.0f, 1.0f, 1.0f); + s = Spherical16::FromVector3(v); + + sr = Spherical16(1.4142135623F, Angle16::Degrees(0), Angle16::Degrees(45)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-05); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-05); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-05); + + r = Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical) + .ToVector3(); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06); + + v = Vector3(1.0f, 1.0f, 1.0f); + s = Spherical16::FromVector3(v); + r = Spherical16(s.distance, s.direction.horizontal, s.direction.vertical) + .ToVector3(); + + EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02); + EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02); + + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-04); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-04); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-04); + + // s = Spherical16(10, 45, 45); + // r = s.ToVector3(); + // EXPECT_NEAR(r.x, 5, 1.0e-06); + // EXPECT_NEAR(r.y, 7.07, 1.0e-06); + // EXPECT_NEAR(r.z, 5, 1.0e-06); +} + +TEST(Spherical16, Addition) { + Spherical16 v1 = Spherical16(1, Angle16::Degrees(45), Angle16::Degrees(0)); + Spherical16 v2 = Spherical16::zero; + Spherical16 r = Spherical16::zero; + + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)"; + + r = v1; + r += v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)"; + + v2 = Spherical16(1, Angle16::Degrees(-45), Angle16::Degrees(0)); + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)"; + EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)"; + EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)"; + + v2 = Spherical16(1, Angle16::Degrees(0), Angle16::Degrees(90)); + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)"; + EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)"; + EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)"; +} + +TEST(Spherical16, AdditionPerformance) { + const int numIterations = 1000000; // Number of additions to test + std::vector sphericalObjects; + + // Populate the vector with random SphericalOf objects + for (int i = 0; i < numIterations; ++i) { + float distance = (float)(rand() % 100); + float horizontal = (float)(rand() % 180); + float vertical = (float)(rand() % 360); + Spherical16 s = Spherical16::Deg(distance, horizontal, vertical); + sphericalObjects.push_back(s); + } + + // Measure the time to perform multiple additions + auto start = std::chrono::high_resolution_clock::now(); + + Spherical16 result = Spherical16::zero; // Start with a + // zero-initialized object + + for (int i = 0; i < numIterations - 1; ++i) { + result = result + sphericalObjects[i]; // Add objects + // together + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration duration = end - start; + std::cout << "Time to perform " << numIterations - 1 + << " additions: " << duration.count() << " seconds." << std::endl; + + // Assert that the time taken is less than + // 1 second (or any other performance + // requirement) + ASSERT_LE(duration.count(), 2.0) << "Performance test failed: " + "Additions took longer than 1 " + "second."; +} + +#endif \ No newline at end of file diff --git a/test/SphericalSingle_test.cc b/test/SphericalSingle_test.cc new file mode 100644 index 0000000..3dedb31 --- /dev/null +++ b/test/SphericalSingle_test.cc @@ -0,0 +1,214 @@ +#if GTEST +#include +#include +#include +#include + +#include "Spherical.h" + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(SphericalSingle, FromVector3) { + Vector3 v = Vector3(0, 0, 1); + SphericalSingle s = SphericalSingle ::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 0 1"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 0 0 1"; + + v = Vector3(0, 1, 0); + s = SphericalSingle ::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0"; + + v = Vector3(1, 0, 0); + s = SphericalSingle ::FromVector3(v); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0"; +} + +TEST(SphericalSingle, FromPolar) { + PolarSingle p = PolarSingle(1, AngleSingle::Degrees(0)); + SphericalSingle s = SphericalSingle ::FromPolar(p); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) + << "s.hor Polar(1 0)"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) + << "s.vert Polar(1 0)"; + + p = PolarSingle(1, AngleSingle::Degrees(45)); + s = SphericalSingle ::FromPolar(p); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 45.0F) + << "s.hor Polar(1 45)"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) + << "s.vert Polar(1 45)"; + + p = PolarSingle(1, AngleSingle::Degrees(-45)); + s = SphericalSingle ::FromPolar(p); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -45.0F) + << "s.hor Polar(1 -45)"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) + << "s.vert Polar(1 -45)"; + + p = PolarSingle(0, AngleSingle::Degrees(0)); + s = SphericalSingle ::FromPolar(p); + + EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) + << "s.hor Polar(0 0)"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) + << "s.vert Polar(0 0)"; + + p = PolarSingle(-1, AngleSingle::Degrees(0)); + s = SphericalSingle ::FromPolar(p); + + EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)"; + EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -180.0F) + << "s.hor Polar(-1 0)"; + EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) + << "s.vert Polar(-1 0)"; +} + +TEST(SphericalSingle, Incident1) { + Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f); + SphericalSingle s = SphericalSingle ::FromVector3(v); + + SphericalSingle sr = SphericalSingle(2.49F, AngleSingle::Degrees(98.18f), + AngleSingle::Degrees(24.4F)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-01); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-02); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-02); + + Vector3 r = Vector3(sr); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0"; + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0"; + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0"; +} + +TEST(SphericalSingle, Incident2) { + Vector3 v = Vector3(1.0f, 0.0f, 1.0f); + SphericalSingle s = SphericalSingle ::FromVector3(v); + + SphericalSingle sr = SphericalSingle( + 1.4142135623F, AngleSingle::Degrees(45.0f), AngleSingle::Degrees(0.0F)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-05); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-05); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-05); + + Vector3 r = Vector3(sr); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06); + + v = Vector3(0.0f, 1.0f, 1.0f); + s = SphericalSingle ::FromVector3(v); + + sr = SphericalSingle(1.4142135623F, AngleSingle::Degrees(0.0f), + AngleSingle::Degrees(45.0F)); + EXPECT_NEAR(s.distance, sr.distance, 1.0e-05); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), + sr.direction.horizontal.InDegrees(), 1.0e-05); + EXPECT_NEAR(s.direction.vertical.InDegrees(), + sr.direction.vertical.InDegrees(), 1.0e-05); + + r = Vector3(sr); + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06); + + v = Vector3(1.0f, 1.0f, 1.0f); + s = SphericalSingle ::FromVector3(v); + r = Vector3(s); + + EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02); + EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02); + EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02); + + EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06); + EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06); + EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06); + + // s = SphericalSingle(10, 45, 45); + // r = s.ToVector3(); + // EXPECT_NEAR(r.x, 5, 1.0e-06); + // EXPECT_NEAR(r.y, 7.07, 1.0e-06); + // EXPECT_NEAR(r.z, 5, 1.0e-06); +} + +TEST(SphericalSingle, Addition) { + SphericalSingle v1 = + SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0)); + SphericalSingle v2 = SphericalSingle ::zero; + SphericalSingle r = SphericalSingle ::zero; + + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)"; + + r = v1; + r += v2; + EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)"; + + v2 = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0)); + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)"; + EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)"; + EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)"; + + v2 = SphericalSingle(1, AngleSingle::Degrees(0), AngleSingle::Degrees(90)); + r = v1 + v2; + EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)"; + EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)"; + EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)"; +} + +TEST(SphericalSingle, AdditionPerformance) { + const int numIterations = 1000000; // Number of additions to test + std::vector sphericalObjects; + + // Populate the vector with random SphericalOf objects + for (int i = 0; i < numIterations; ++i) { + float distance = (float)(rand() % 100); + float horizontal = (float)(rand() % 180); + float vertical = (float)(rand() % 360); + SphericalSingle s = SphericalSingle::Deg(distance, horizontal, vertical); + sphericalObjects.push_back(s); + } + + // Measure the time to perform multiple additions + auto start = std::chrono::high_resolution_clock::now(); + + SphericalSingle result = SphericalSingle::zero; // Start with a + // zero-initialized object + + for (int i = 0; i < numIterations - 1; ++i) { + result = result + sphericalObjects[i]; // Add objects + // together + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration duration = end - start; + std::cout << "Time to perform " << numIterations - 1 + << " additions: " << duration.count() << " seconds." << std::endl; + + // Assert that the time taken is less than + // 1 second (or any other performance + // requirement) + ASSERT_LE(duration.count(), 1.0) << "Performance test failed: " + "Additions took longer than 1 " + "second."; +} + +#endif \ No newline at end of file diff --git a/test/SwingTwistSingle_test.cc b/test/SwingTwistSingle_test.cc new file mode 100644 index 0000000..8885ae4 --- /dev/null +++ b/test/SwingTwistSingle_test.cc @@ -0,0 +1,131 @@ +#if GTEST +#include +#include +#include + +#include "SwingTwist.h" + +#define FLOAT_INFINITY std::numeric_limits::infinity() + +TEST(SwingTwistSingle, Quaternion) { + Quaternion q; + SwingTwistSingle s; + Quaternion rq; + + q = Quaternion::identity; + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_EQ(q, rq) << " 0 0 0 1 <-> SwingTwist"; + + q = Quaternion::Euler(90, 0, 0); + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 90 0 0 <-> SwingTwist"; + + q = Quaternion::Euler(0, 90, 0); + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist"; + + q = Quaternion::Euler(0, 0, 90); + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_EQ(q, rq) << " Euler 0 0 90 <-> SwingTwist"; + + q = Quaternion::Euler(0, 180, 0); // ==> spherical S(180 0)T0 + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist"; + + q = Quaternion::Euler(0, 135, 0); // ==> spherical S(180 45)T0 + s = SwingTwistSingle::FromQuaternion(q); + rq = s.ToQuaternion(); + EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist"; +} + +TEST(SwingTwistSingle, AngleAxis) { + SwingTwistSingle s; + SwingTwistSingle r; + + s = SwingTwistSingle::AngleAxis(0, DirectionSingle::up); + EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 up"; + + r = SwingTwistSingle::AngleAxis(90, DirectionSingle::up); + s = SwingTwistSingle::Degrees(90, 0, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "90 up"; + + r = SwingTwistSingle::AngleAxis(180, DirectionSingle::up); + s = SwingTwistSingle::Degrees(180, 0, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "180 up"; + + r = SwingTwistSingle::AngleAxis(270, DirectionSingle::up); + s = SwingTwistSingle::Degrees(-90, 0, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "270 up"; + + r = SwingTwistSingle::AngleAxis(90, DirectionSingle::right); + s = SwingTwistSingle::Degrees(0, 90, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "90 right"; + + r = SwingTwistSingle::AngleAxis(180, DirectionSingle::right); + s = SwingTwistSingle::Degrees(0, 180, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "180 right"; + r = SwingTwistSingle::AngleAxis(270, DirectionSingle::right); + s = SwingTwistSingle::Degrees(0, -90, 0); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "270 right"; + + r = SwingTwistSingle::AngleAxis(90, DirectionSingle::forward); + s = SwingTwistSingle::Degrees(0, 0, 90); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "90 up"; + + r = SwingTwistSingle::AngleAxis(180, DirectionSingle::forward); + s = SwingTwistSingle::Degrees(0, 0, 180); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "180 up"; + + r = SwingTwistSingle::AngleAxis(270, DirectionSingle::forward); + s = SwingTwistSingle::Degrees(0, 0, -90); + EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f)) + << "270 up"; + + auto r16 = SwingTwist16::AngleAxis(13, Direction16::down); + auto s16 = SwingTwist16::Degrees(-13, 0, 0); + EXPECT_LT(SwingTwist16::Angle(r16, s16), Angle16::Degrees(10e-2f)) + << "270 up"; +} + +TEST(SwingTwistSingle, Normalize) { + SwingTwistSingle s; + + s = SwingTwistSingle::Degrees(0, 0, 0); + EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 0 0 Normalized"; + + s = SwingTwistSingle::Degrees(0, 180, 0); + EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 180)) << "0 180 0 Normalized"; + + s = SwingTwistSingle::Degrees(0, 180, 180); + EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 0)) << "0 180 180 Normalized"; + + s = SwingTwistSingle::Degrees(270, 90, 0); + EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 90, 0)) << "270 90 0 Normalized"; + + s = SwingTwistSingle::Degrees(270, 270, 0); + EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, -90, 0)) + << "270 270 0 Normalized"; + + s = SwingTwistSingle::Degrees(270, 225, 0); + EXPECT_EQ(s, SwingTwistSingle::Degrees(90, -45, -180)) + << "270 225 0 Normalized"; + + s = SwingTwistSingle::Degrees(270, 0, 225); + EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 0, -135)) + << "270 0 225 Normalized"; +} + +#endif \ No newline at end of file diff --git a/test/Vector2_test.cc b/test/Vector2_test.cc index 83c52ce..3afeb4b 100644 --- a/test/Vector2_test.cc +++ b/test/Vector2_test.cc @@ -7,6 +7,33 @@ #define FLOAT_INFINITY std::numeric_limits::infinity() +TEST(Vector2, FromPolar) { + Vector2 v; + PolarSingle p; + Vector2 r; + + v = Vector2(0, 1); + p = PolarSingle::FromVector2(v); + r = Vector2(p); + + EXPECT_FLOAT_EQ(r.x, 0.0F) << "FromPolar(0 1)"; + EXPECT_FLOAT_EQ(r.y, 1.0F) << "FromPolar(0 1)"; + + v = Vector2(1, 0); + p = PolarSingle::FromVector2(v); + r = Vector2(p); + + EXPECT_FLOAT_EQ(r.x, 1.0F) << "FromPolar(1 0)"; + EXPECT_NEAR(r.y, 0.0F, 1.0e-07) << "FromPolar(1 0)"; + + v = Vector2(0, 0); + p = PolarSingle::FromVector2(v); + r = Vector2(p); + + EXPECT_FLOAT_EQ(r.x, 0.0F) << "FromPolar(0 0)"; + EXPECT_FLOAT_EQ(r.y, 0.0F) << "FromPolar(0 0)"; +} + TEST(Vector2, Magnitude) { Vector2 v = Vector2(1, 2); float m = 0; @@ -99,8 +126,6 @@ TEST(Vector2, Normalize) { } TEST(Vector2, Negate) { - bool r = false; - Vector2 v1 = Vector2(4, 5); Vector2 v = Vector2::zero; @@ -129,8 +154,6 @@ TEST(Vector2, Negate) { } TEST(Vector2, Subtract) { - bool r = false; - Vector2 v1 = Vector2(4, 5); Vector2 v2 = Vector2(1, 2); Vector2 v = Vector2::zero; @@ -145,11 +168,17 @@ TEST(Vector2, Subtract) { v2 = Vector2(4, 5); v = v1 - v2; EXPECT_TRUE(v == Vector2(0, 0)) << "4 5 - 4 5"; + v = v1; + v -= v2; + EXPECT_TRUE(v == Vector2(0, 0)) << "4 5 - 4 5"; v2 = Vector2(0, 0); v = v1 - v2; EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 - 0 0"; + v -= v2; + EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 - 0 0"; + if (std::numeric_limits::is_iec559) { v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY); v = v1 - v2; @@ -164,11 +193,9 @@ TEST(Vector2, Subtract) { } TEST(Vector2, Addition) { - Vector2 v1 = Vector2(4, 5); Vector2 v2 = Vector2(1, 2); Vector2 v = Vector2::zero; - bool r = false; v = v1 + v2; EXPECT_TRUE(v == Vector2(5, 7)) << "4 5 + 1 2"; @@ -176,10 +203,15 @@ TEST(Vector2, Addition) { v2 = Vector2(-1, -2); v = v1 + v2; EXPECT_TRUE(v == Vector2(3, 3)) << "4 5 + -1 -2"; + v = v1; + v += v2; + EXPECT_TRUE(v == Vector2(3, 3)) << "4 5 + -1 -2"; v2 = Vector2(0, 0); v = v1 + v2; EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 + 0 0"; + v += v2; + EXPECT_TRUE(v == Vector2(4, 5)) << "4 5 + 0 0"; if (std::numeric_limits::is_iec559) { v2 = Vector2(FLOAT_INFINITY, FLOAT_INFINITY); @@ -195,8 +227,6 @@ TEST(Vector2, Addition) { } TEST(Vector2, Scale) { - bool r = false; - Vector2 v1 = Vector2(4, 5); Vector2 v2 = Vector2(1, 2); Vector2 v = Vector2::zero; @@ -226,8 +256,6 @@ TEST(Vector2, Scale) { } TEST(Vector2, Multiply) { - bool r = false; - Vector2 v1 = Vector2(4, 5); float f = 3; Vector2 v = Vector2::zero; @@ -257,8 +285,6 @@ TEST(Vector2, Multiply) { } TEST(Vector2, Divide) { - bool r = false; - Vector2 v1 = Vector2(4, 5); float f = 2; Vector2 v = Vector2::zero; @@ -399,11 +425,11 @@ TEST(Vector2, SignedAngle) { bool r = false; f = Vector2::SignedAngle(v1, v2); - EXPECT_FLOAT_EQ(f, 12.09476F) << "SignedAngle(4 5, 1 2)"; + EXPECT_FLOAT_EQ(f, -12.09476F) << "SignedAngle(4 5, 1 2)"; v2 = Vector2(-1, -2); f = Vector2::SignedAngle(v1, v2); - EXPECT_FLOAT_EQ(f, -167.9052F) << "SignedAngle(4 5, -1 -2)"; + EXPECT_FLOAT_EQ(f, 167.9052F) << "SignedAngle(4 5, -1 -2)"; v2 = Vector2(0, 0); f = Vector2::SignedAngle(v1, v2); @@ -420,22 +446,32 @@ TEST(Vector2, SignedAngle) { r = isnan(f); EXPECT_TRUE(r) << "SignedAngle(4 5, -INFINITY -INFINITY)"; } + + v1 = Vector2(0, 1); + v2 = Vector2(1, 0); + f = Vector2::SignedAngle(v1, v2); + EXPECT_FLOAT_EQ(f, 90.0F) << "SignedAngle(0 1, 1 0)"; + + v1 = Vector2(0, 1); + v2 = Vector2(0, -1); + f = Vector2::SignedAngle(v1, v2); + EXPECT_FLOAT_EQ(f, 180.0F) << "SignedAngle(0 1, 1 0)"; } TEST(Vector2, Rotate) { Vector2 v1 = Vector2(1, 2); Vector2 r = Vector2(0, 0); - r = Vector2::Rotate(v1, 0); + r = Vector2::Rotate(v1, AngleSingle::Degrees(0)); EXPECT_FLOAT_EQ(Vector2::Distance(r, v1), 0); - r = Vector2::Rotate(v1, 180); + r = Vector2::Rotate(v1, AngleSingle::Degrees(180)); EXPECT_NEAR(Vector2::Distance(r, Vector2(-1, -2)), 0, 1.0e-06); - r = Vector2::Rotate(v1, -90); + r = Vector2::Rotate(v1, AngleSingle::Degrees(-90)); EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06); - r = Vector2::Rotate(v1, 270); + r = Vector2::Rotate(v1, AngleSingle::Degrees(270)); EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06); } @@ -460,6 +496,4 @@ TEST(Vector2, Lerp) { EXPECT_FLOAT_EQ(Vector2::Distance(r, Vector2(-2.0, -1.0f)), 0); } -TEST(Vector2, DISABLED_ToFactor) {} - #endif \ No newline at end of file diff --git a/test/Vector3_test.cc b/test/Vector3_test.cc index e8f61f8..82e57e9 100644 --- a/test/Vector3_test.cc +++ b/test/Vector3_test.cc @@ -7,6 +7,32 @@ #define FLOAT_INFINITY std::numeric_limits::infinity() +TEST(Vector3, FromSpherical) { + Vector3 v = Vector3(0, 0, 1); + SphericalOf s = SphericalOf::FromVector3(v); + Vector3 r = Vector3(s); + + EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 0 1"; + EXPECT_NEAR(r.Up(), 0.0F, 1.0e-06) << "toVector3.y 0 0 1"; + EXPECT_FLOAT_EQ(r.Forward(), 1.0F) << "toVector3.z 0 0 1"; + + v = Vector3(0, 1, 0); + s = SphericalOf::FromVector3(v); + r = Vector3(s); + + EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 1 0"; + EXPECT_FLOAT_EQ(r.Up(), 1.0F) << "toVector3.y 0 1 0"; + EXPECT_NEAR(r.Forward(), 0.0F, 1.0e-06) << "toVector3.z 0 1 0"; + + v = Vector3(1, 0, 0); + s = SphericalOf::FromVector3(v); + r = Vector3(s); + + EXPECT_FLOAT_EQ(r.Right(), 1.0F) << "toVector3.x 1 0 0"; + EXPECT_NEAR(r.Up(), 0.0F, 1.0e-06) << "toVector3.y 1 0 0"; + EXPECT_NEAR(r.Forward(), 0.0F, 1.0e-06) << "toVector3.z 1 0 0"; +} + TEST(Vector3, Magnitude) { Vector3 v = Vector3(1, 2, 3); float m = 0; @@ -92,19 +118,17 @@ TEST(Vector3, Normalize) { if (std::numeric_limits::is_iec559) { v1 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); v = v1.normalized(); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "v.normalized INFINITY INFINITY INFINITY"; v1 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); v = v1.normalized(); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "v.normalized -INFINITY -INFINITY -INFINITY"; } } TEST(Vector3, Negate) { - bool r = false; - Vector3 v1 = Vector3(4, 5, 6); Vector3 v = Vector3::zero; @@ -133,8 +157,6 @@ TEST(Vector3, Negate) { } TEST(Vector3, Subtract) { - bool r = false; - Vector3 v1 = Vector3(4, 5, 6); Vector3 v2 = Vector3(1, 2, 3); Vector3 v = Vector3::zero; @@ -168,11 +190,9 @@ TEST(Vector3, Subtract) { } TEST(Vector3, Addition) { - Vector3 v1 = Vector3(4, 5, 6); Vector3 v2 = Vector3(1, 2, 3); Vector3 v = Vector3::zero; - bool r = false; v = v1 + v2; EXPECT_TRUE(v == Vector3(5, 7, 9)) << "4 5 6 + 1 2 3"; @@ -199,8 +219,6 @@ TEST(Vector3, Addition) { } TEST(Vector3, Scale) { - bool r = false; - Vector3 v1 = Vector3(4, 5, 6); Vector3 v2 = Vector3(1, 2, 3); Vector3 v = Vector3::zero; @@ -230,8 +248,6 @@ TEST(Vector3, Scale) { } TEST(Vector3, Multiply) { - bool r = false; - Vector3 v1 = Vector3(4, 5, 6); float f = 3; Vector3 v = Vector3::zero; @@ -261,8 +277,6 @@ TEST(Vector3, Multiply) { } TEST(Vector3, Divide) { - bool r = false; - Vector3 v1 = Vector3(4, 5, 6); float f = 2; Vector3 v = Vector3::zero; @@ -395,12 +409,12 @@ TEST(Vector3, Cross) { if (std::numeric_limits::is_iec559) { v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); v = Vector3::Cross(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "Cross(4 5 6, INFINITY INFINITY INFINITY)"; v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); v = Vector3::Cross(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "Cross(4 5 6, -INFINITY -INFINITY -INFINITY)"; } } @@ -428,12 +442,12 @@ TEST(Vector3, Project) { if (std::numeric_limits::is_iec559) { v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); v = Vector3::Project(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "Project(4 5 6, INFINITY INFINITY INFINITY)"; v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); v = Vector3::Project(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "Project(4 5 6, -INFINITY -INFINITY -INFINITY)"; } } @@ -461,12 +475,12 @@ TEST(Vector3, ProjectOnPlane) { if (std::numeric_limits::is_iec559) { v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); v = Vector3::ProjectOnPlane(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, INFINITY INFINITY INFINITY)"; v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); v = Vector3::ProjectOnPlane(v1, v2); - r = isnan(v.x) && isnan(v.y) && isnan(v.z); + r = isnan(v.Right()) && isnan(v.Up()) && isnan(v.Forward()); EXPECT_TRUE(r) << "ProjectOnPlane(4 5 6, -INFINITY -INFINITY -INFINITY)"; } } @@ -474,29 +488,29 @@ TEST(Vector3, ProjectOnPlane) { TEST(Vector3, Angle) { Vector3 v1 = Vector3(4, 5, 6); Vector3 v2 = Vector3(1, 2, 3); - float f = 0; + AngleOf f = AngleOf::Degrees(0); bool r = false; f = Vector3::Angle(v1, v2); - EXPECT_FLOAT_EQ(f, 12.9331388F) << "Angle(4 5 6, 1 2 3)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 12.9331388F) << "Angle(4 5 6, 1 2 3)"; v2 = Vector3(-1, -2, -3); f = Vector3::Angle(v1, v2); - EXPECT_FLOAT_EQ(f, 167.066864F) << "Angle(4 5 6, -1 -2 -3)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 167.066864F) << "Angle(4 5 6, -1 -2 -3)"; v2 = Vector3(0, 0, 0); f = Vector3::Angle(v1, v2); - EXPECT_FLOAT_EQ(f, 0) << "Angle(4 5 6, 0 0 0)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "Angle(4 5 6, 0 0 0)"; if (std::numeric_limits::is_iec559) { v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); f = Vector3::Angle(v1, v2); - r = isnan(f); + r = isnan(f.InDegrees()); EXPECT_TRUE(r) << "Angle(4 5 6, INFINITY INFINITY INFINITY)"; v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); f = Vector3::Angle(v1, v2); - r = isnan(f); + r = isnan(f.InDegrees()); EXPECT_TRUE(r) << "Angle(4 5 6, -INFINITY -INFINITY -INFINITY)"; } } @@ -505,39 +519,42 @@ TEST(Vector3, SignedAngle) { Vector3 v1 = Vector3(4, 5, 6); Vector3 v2 = Vector3(1, 2, 3); Vector3 v3 = Vector3(7, 8, -9); - float f = 0; + AngleOf f = AngleOf::Degrees(0); bool r = false; f = Vector3::SignedAngle(v1, v2, v3); - EXPECT_FLOAT_EQ(f, -12.9331388F) << "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"; + EXPECT_FLOAT_EQ(f.InDegrees(), -12.9331388F) + << "SignedAngle(4 5 6, 1 2 3, 7 8 -9)"; v2 = Vector3(-1, -2, -3); f = Vector3::SignedAngle(v1, v2, v3); - EXPECT_FLOAT_EQ(f, 167.066864F) << "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 167.066864F) + << "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)"; v2 = Vector3(0, 0, 0); f = Vector3::SignedAngle(v1, v2, v3); - EXPECT_FLOAT_EQ(f, 0) << "SignedAngle(4 5 6, 0 0 0, 7 8 -9 )"; + EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5 6, 0 0 0, 7 8 -9 )"; v2 = Vector3(1, 2, 3); v3 = Vector3(-7, -8, 9); f = Vector3::SignedAngle(v1, v2, v3); - EXPECT_FLOAT_EQ(f, 12.9331388F) << "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 12.9331388F) + << "SignedAngle(4 5 6, 1 2 3, -7 -8 9)"; v3 = Vector3(0, 0, 0); f = Vector3::SignedAngle(v1, v2, v3); - EXPECT_FLOAT_EQ(f, 0) << "SignedAngle(4 5 6, 1 2 3, 0 0 0)"; + EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5 6, 1 2 3, 0 0 0)"; if (std::numeric_limits::is_iec559) { v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY); f = Vector3::SignedAngle(v1, v2, v3); - r = isnan(f); + r = isnan(f.InDegrees()); EXPECT_TRUE(r) << "SignedAngle(4 5 6, INFINITY INFINITY INFINITY)"; v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY); f = Vector3::SignedAngle(v1, v2, v3); - r = isnan(f); + r = isnan(f.InDegrees()); EXPECT_TRUE(r) << "SignedAngle(4 5 6, -INFINITY -INFINITY -INFINITY)"; } } @@ -562,4 +579,5 @@ TEST(Vector3, Lerp) { r = Vector3::Lerp(v1, v2, 2); EXPECT_FLOAT_EQ(Vector3::Distance(r, Vector3(-2.0, -1.0f, 0.0f)), 0); } + #endif \ No newline at end of file