Improved unit tests
All checks were successful
Build and Run C++ Unit Tests / build-and-test (push) Successful in 2m1s

This commit is contained in:
Pascal Serrarens 2025-12-22 10:23:27 +01:00
parent ce578791d5
commit 679471f748
9 changed files with 217 additions and 290 deletions

View File

@ -216,12 +216,6 @@ using AngleSingle = AngleOf<float>;
using Angle16 = AngleOf<signed short>; using Angle16 = AngleOf<signed short>;
using Angle8 = AngleOf<signed char>; using Angle8 = AngleOf<signed char>;
#if defined(ARDUINO)
using Angle = Angle16;
#else
using Angle = AngleSingle;
#endif
} // namespace LinearAlgebra } // namespace LinearAlgebra
#endif #endif

View File

@ -91,12 +91,6 @@ class DirectionOf {
using DirectionSingle = DirectionOf<float>; using DirectionSingle = DirectionOf<float>;
using Direction16 = DirectionOf<signed short>; using Direction16 = DirectionOf<signed short>;
#if defined(ARDUINO)
using Direction = Direction16;
#else
using Direction = DirectionSingle;
#endif
} // namespace LinearAlgebra } // namespace LinearAlgebra
#endif #endif

View File

@ -236,10 +236,10 @@ Vector3Of<T>::Vector3Of(Vector2Of<T> v) : horizontal(v.horizontal), vertical(v.v
template <typename T> template <typename T>
Vector3Of<T>::Vector3Of(SphericalOf<T> v) { Vector3Of<T>::Vector3Of(SphericalOf<T> v) {
float cosVertical = Angle::Cos(v.direction.vertical); float cosVertical = AngleOf<T>::Cos(v.direction.vertical);
float sinVertical = Angle::Sin(v.direction.vertical); float sinVertical = AngleOf<T>::Sin(v.direction.vertical);
float cosHorizontal = Angle::Cos(v.direction.horizontal); float cosHorizontal = AngleOf<T>::Cos(v.direction.horizontal);
float sinHorizontal = Angle::Sin(v.direction.horizontal); float sinHorizontal = AngleOf<T>::Sin(v.direction.horizontal);
horizontal = v.distance * sinVertical * sinHorizontal; horizontal = v.distance * sinVertical * sinHorizontal;
vertical = v.distance * cosVertical; vertical = v.distance * cosVertical;
@ -365,7 +365,7 @@ float Vector3Of<T>::Dot(const Vector3Of& v1, const Vector3Of& v2) {
} }
template <typename T> template <typename T>
AngleOf<float> Vector3Of<T>::Angle(const Vector3Of& v1, const Vector3Of& v2) { AngleOf<float> Vector3Of<T>::UnsignedAngle(const Vector3Of& v1, const Vector3Of& v2) {
float denominator = sqrtf(v1.SqrMagnitude() * v2.SqrMagnitude()); float denominator = sqrtf(v1.SqrMagnitude() * v2.SqrMagnitude());
if (denominator < epsilon) if (denominator < epsilon)
return AngleOf<float>(); return AngleOf<float>();

View File

@ -345,7 +345,7 @@ class Vector3Of {
/// @remark This reterns an unsigned angle which is the shortest distance /// @remark This reterns an unsigned angle which is the shortest distance
/// between the two vectors. Use Vector3::SignedAngle if a signed angle is /// between the two vectors. Use Vector3::SignedAngle if a signed angle is
/// needed. /// needed.
static AngleOf<float> Angle(const Vector3Of& v1, const Vector3Of& v2); static AngleOf<float> UnsignedAngle(const Vector3Of& v1, const Vector3Of& v2);
}; };
using Vector3Int = Vector3Of<int>; using Vector3Int = Vector3Of<int>;

View File

@ -10,14 +10,15 @@ using namespace LinearAlgebra;
#define FLOAT_INFINITY std::numeric_limits<float>::infinity() #define FLOAT_INFINITY std::numeric_limits<float>::infinity()
using AngleTypes = ::testing::Types<AngleOf<float>, AngleOf<signed short>, AngleOf<signed char>>; //using AngleTypes = ::testing::Types<AngleOf<float>, AngleOf<signed short>, AngleOf<signed char>>;
using BaseTypes = ::testing::Types<float, signed short, signed char>;
template <typename T> template <typename T>
class AngleTest : public ::testing::Test {}; class AngleTests : public ::testing::Test {};
TYPED_TEST_SUITE(AngleTest, AngleTypes); TYPED_TEST_SUITE(AngleTests, BaseTypes);
TYPED_TEST(AngleTest, Construct) { TYPED_TEST(AngleTests, Construct) {
using Angle = TypeParam; using Angle = AngleOf<TypeParam>;
float angle = 0.0F; float angle = 0.0F;
Angle a = Angle::Degrees(angle); Angle a = Angle::Degrees(angle);
EXPECT_FLOAT_EQ(a.InDegrees(), angle); EXPECT_FLOAT_EQ(a.InDegrees(), angle);
@ -31,8 +32,8 @@ TYPED_TEST(AngleTest, Construct) {
EXPECT_FLOAT_EQ(a.InDegrees(), -90); EXPECT_FLOAT_EQ(a.InDegrees(), -90);
} }
TYPED_TEST(AngleTest, Negate) { TYPED_TEST(AngleTests, Negate) {
using Angle = TypeParam; using Angle = AngleOf<TypeParam>;
float angle = 0; float angle = 0;
Angle a = Angle::Degrees(angle); Angle a = Angle::Degrees(angle);
a = -a; a = -a;
@ -44,205 +45,211 @@ TYPED_TEST(AngleTest, Negate) {
EXPECT_FLOAT_EQ(a.InDegrees(), -angle); EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
} }
TYPED_TEST(AngleTest, Add) { TYPED_TEST(AngleTests, Add) {
using Angle = TypeParam; using Angle = AngleOf<TypeParam>;
Angle a = Angle::Degrees(-45); Angle a = Angle::Degrees(-45);
Angle b = Angle::Degrees(45.0F); Angle b = Angle::Degrees(45.0F);
Angle r = a + b; Angle r = a + b;
EXPECT_FLOAT_EQ(r.InDegrees(), 0); EXPECT_FLOAT_EQ(r.InDegrees(), 0);
} }
TYPED_TEST(AngleTest, Subtract) { TYPED_TEST(AngleTests, Subtract) {
Angle8 a = Angle8::Degrees(0); using Angle = AngleOf<TypeParam>;
Angle8 b = Angle8::Degrees(45.0F); Angle a = Angle::Degrees(0);
Angle8 r = a - b; Angle b = Angle::Degrees(45.0F);
Angle r = a - b;
EXPECT_FLOAT_EQ(r.InDegrees(), -45); EXPECT_FLOAT_EQ(r.InDegrees(), -45);
} }
TYPED_TEST(AngleTest, Compare) { TYPED_TEST(AngleTests, Compare) {
Angle8 a = Angle8::Degrees(45); using Angle = AngleOf<TypeParam>;
Angle a = Angle::Degrees(45);
bool r = false; bool r = false;
r = a > Angle8::Degrees(0); r = a > Angle::Degrees(0);
EXPECT_TRUE(r) << "45 > 0"; EXPECT_TRUE(r) << "45 > 0";
r = a > Angle8::Degrees(90); r = a > Angle::Degrees(90);
EXPECT_FALSE(r) << "45 > 90"; EXPECT_FALSE(r) << "45 > 90";
r = a > Angle8::Degrees(-90); r = a > Angle::Degrees(-90);
EXPECT_TRUE(r) << "45 > -90"; EXPECT_TRUE(r) << "45 > -90";
} }
TYPED_TEST(AngleTest, Normalize) { TYPED_TEST(AngleTests, Normalize) {
Angle8 r = Angle8(); using Angle = AngleOf<TypeParam>;
Angle r = Angle();
r = Angle8::Normalize(Angle8::Degrees(90.0f)); r = Angle::Normalize(Angle::Degrees(90.0f));
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90";
r = Angle8::Normalize(Angle8::Degrees(-90)); r = Angle::Normalize(Angle::Degrees(-90));
EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90"; EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90";
r = Angle8::Normalize(Angle8::Degrees(270)); r = Angle::Normalize(Angle::Degrees(270));
EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270"; EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270";
r = Angle8::Normalize(Angle8::Degrees(270 + 360)); r = Angle::Normalize(Angle::Degrees(270 + 360));
EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360"; EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360";
r = Angle8::Normalize(Angle8::Degrees(-270)); r = Angle::Normalize(Angle::Degrees(-270));
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270";
r = Angle8::Normalize(Angle8::Degrees(-270 - 360)); r = Angle::Normalize(Angle::Degrees(-270 - 360));
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360";
r = Angle8::Normalize(Angle8::Degrees(0)); r = Angle::Normalize(Angle::Degrees(0));
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0";
if (false) { // std::numeric_limits<float>::is_iec559) { if (false) { // std::numeric_limits<float>::is_iec559) {
// Infinites are not supported // Infinites are not supported
r = Angle8::Normalize(Angle8::Degrees(FLOAT_INFINITY)); r = Angle::Normalize(Angle::Degrees(FLOAT_INFINITY));
EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY"; EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY";
r = Angle8::Normalize(Angle8::Degrees(-FLOAT_INFINITY)); r = Angle::Normalize(Angle::Degrees(-FLOAT_INFINITY));
EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY"; EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY";
} }
} }
TYPED_TEST(AngleTest, Clamp) { TYPED_TEST(AngleTests, Clamp) {
Angle8 r = Angle8(); using Angle = AngleOf<TypeParam>;
Angle r = Angle();
// Clamp(1, 0, 2) will fail because Angle8 does not have enough resolution for // Clamp(1, 0, 2) will fail because Angle does not have enough resolution for
// this. Instead we use Clamp(10, 0, 20) etc. // this. Instead we use Clamp(10, 0, 20) etc.
r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), r = Angle::Clamp(Angle::Degrees(10), Angle::Degrees(0),
Angle8::Degrees(20)); Angle::Degrees(20));
EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 10 0 20"; EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 10 0 20";
r = Angle8::Clamp(Angle8::Degrees(-10), Angle8::Degrees(0), r = Angle::Clamp(Angle::Degrees(-10), Angle::Degrees(0),
Angle8::Degrees(20)); Angle::Degrees(20));
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20";
r = Angle8::Clamp(Angle8::Degrees(30), Angle8::Degrees(0), r = Angle::Clamp(Angle::Degrees(30), Angle::Degrees(0),
Angle8::Degrees(20)); Angle::Degrees(20));
EXPECT_NEAR(r.InDegrees(), 20, 1.0e-0) << "Clamp 30 0 20"; EXPECT_NEAR(r.InDegrees(), 20, 1.0e-0) << "Clamp 30 0 20";
r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), r = Angle::Clamp(Angle::Degrees(10), Angle::Degrees(0),
Angle8::Degrees(0)); Angle::Degrees(0));
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0";
r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(0), Angle8::Degrees(0)); r = Angle::Clamp(Angle::Degrees(0), Angle::Degrees(0), Angle::Degrees(0));
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0";
r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(10), r = Angle::Clamp(Angle::Degrees(0), Angle::Degrees(10),
Angle8::Degrees(-10)); Angle::Degrees(-10));
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10";
if (false) { // std::numeric_limits<float>::is_iec559) { if (false) { // std::numeric_limits<float>::is_iec559) {
// Infinites are not supported // Infinites are not supported
r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0), r = Angle::Clamp(Angle::Degrees(10), Angle::Degrees(0),
Angle8::Degrees(FLOAT_INFINITY)); Angle::Degrees(FLOAT_INFINITY));
EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 0 INFINITY"; EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 0 INFINITY";
r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(-FLOAT_INFINITY), r = Angle::Clamp(Angle::Degrees(10), Angle::Degrees(-FLOAT_INFINITY),
Angle8::Degrees(10)); Angle::Degrees(10));
EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 -INFINITY 1"; EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 -INFINITY 1";
} }
} }
// TEST(Angle8, Difference) { // TEST(Angle, Difference) {
// Angle8 r = 0; // using Angle = AngleOf<TypeParam>;
// Angle r = 0;
// r = Angle8::Difference(0, 90); // r = Angle::Difference(0, 90);
// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90"; // EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90";
// r = Angle8::Difference(0, -90); // r = Angle::Difference(0, -90);
// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90"; // EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90";
// r = Angle8::Difference(0, 270); // r = Angle::Difference(0, 270);
// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270"; // EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270";
// r = Angle8::Difference(0, -270); // r = Angle::Difference(0, -270);
// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270"; // EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270";
// r = Angle8::Difference(90, 0); // r = Angle::Difference(90, 0);
// EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0"; // EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0";
// r = Angle8::Difference(-90, 0); // r = Angle::Difference(-90, 0);
// EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0"; // EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0";
// r = Angle8::Difference(0, 0); // r = Angle::Difference(0, 0);
// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0"; // EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0";
// r = Angle8::Difference(90, 90); // r = Angle::Difference(90, 90);
// EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90"; // EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90";
// if (std::numeric_limits<float>::is_iec559) { // if (std::numeric_limits<float>::is_iec559) {
// r = Angle8::Difference(0, INFINITY); // r = Angle::Difference(0, INFINITY);
// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY"; // EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY";
// r = Angle8::Difference(0, -INFINITY); // r = Angle::Difference(0, -INFINITY);
// EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY"; // EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY";
// r = Angle8::Difference(-INFINITY, INFINITY); // r = Angle::Difference(-INFINITY, INFINITY);
// EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY // EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY
// INFINITY"; // INFINITY";
// } // }
// } // }
TYPED_TEST(AngleTest, MoveTowards) { TYPED_TEST(AngleTests, MoveTowards) {
Angle8 r = Angle8(); using Angle = AngleOf<TypeParam>;
Angle r = Angle();
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 30); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90), 30);
EXPECT_NEAR(r.InDegrees(), 30, 1.0e-0) << "MoveTowards 0 90 30"; EXPECT_NEAR(r.InDegrees(), 30, 1.0e-0) << "MoveTowards 0 90 30";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 90); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90), 90);
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), 180); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90), 180);
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 270); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90), 270);
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), -30); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90), -30);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -30); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90), -30);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -90); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90), -90);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -180); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90), -180);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -270); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90), -270);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 0); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90), 0);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 0); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(0), 0);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 30); r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(0), 30);
EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30"; EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30";
if (false) { // std::numeric_limits<float>::is_iec559) { if (false) { // std::numeric_limits<float>::is_iec559) {
// infinites are not supported // infinites are not supported
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(90),
FLOAT_INFINITY); FLOAT_INFINITY);
EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY"; EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(FLOAT_INFINITY), r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(FLOAT_INFINITY),
30); 30);
EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30"; EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";
r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), r = Angle::MoveTowards(Angle::Degrees(0), Angle::Degrees(-90),
-FLOAT_INFINITY); -FLOAT_INFINITY);
EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY)
<< "MoveTowards 0 -90 -FLOAT_INFINITY"; << "MoveTowards 0 -90 -FLOAT_INFINITY";
r = Angle8::MoveTowards(Angle8::Degrees(0), r = Angle::MoveTowards(Angle::Degrees(0),
Angle8::Degrees(-FLOAT_INFINITY), -30); Angle::Degrees(-FLOAT_INFINITY), -30);
EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30"; EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30";
} }
} }

View File

@ -10,49 +10,58 @@ using namespace LinearAlgebra;
#define FLOAT_INFINITY std::numeric_limits<float>::infinity() #define FLOAT_INFINITY std::numeric_limits<float>::infinity()
TEST(Direction16, Compare) { using BaseTypes = ::testing::Types<float, signed short>;
Direction16 d = Direction16::Degrees(45, 135);
template <typename T>
class DirectionTests : public ::testing::Test {};
TYPED_TEST_SUITE(DirectionTests, BaseTypes);
TYPED_TEST(DirectionTests, Compare) {
using Direction = DirectionOf<TypeParam>;
using Angle = AngleOf<TypeParam>;
Direction d = Direction::Degrees(45, 135);
bool r; bool r;
r = (d == Direction16(Angle16::Degrees(45), Angle16::Degrees(135))); r = (d == Direction(Angle::Degrees(45), Angle::Degrees(135)));
EXPECT_TRUE(r) << "45,135 == 45, 135"; EXPECT_TRUE(r) << "45,135 == 45, 135";
r = (d == r = (d == Direction(Angle::Degrees(45 + 360), Angle::Degrees(135 - 360)));
Direction16(Angle16::Degrees(45 + 360), Angle16::Degrees(135 - 360)));
EXPECT_TRUE(r) << "45+360, 135-360 == 45, 135"; EXPECT_TRUE(r) << "45+360, 135-360 == 45, 135";
} }
TEST(Direction16, Inverse) { TYPED_TEST(DirectionTests, Inverse) {
Direction16 d; using Direction = DirectionOf<TypeParam>;
Direction16 r; Direction d;
Direction r;
d = Direction16::Degrees(45, 135); d = Direction::Degrees(45, 135);
r = -d; r = -d;
EXPECT_EQ(r, Direction16::Degrees(-135, -135)) << "-(45, 135)"; EXPECT_EQ(r, Direction::Degrees(-135, -135)) << "-(45, 135)";
d = Direction16::Degrees(-45, -135); d = Direction::Degrees(-45, -135);
r = -d; r = -d;
EXPECT_EQ(r, Direction16::Degrees(135, 135)) << "-(-45, -135)"; EXPECT_EQ(r, Direction::Degrees(135, 135)) << "-(-45, -135)";
d = Direction16::Degrees(0, 0); d = Direction::Degrees(0, 0);
r = -d; r = -d;
EXPECT_EQ(r, Direction16::Degrees(180, 0)) << "-(0, 0)"; EXPECT_EQ(r, Direction::Degrees(180, 0)) << "-(0, 0)";
d = Direction16::Degrees(0, 45); d = Direction::Degrees(0, 45);
r = -d; r = -d;
EXPECT_EQ(r, Direction16::Degrees(180, -45)) << "-(0, 45)"; EXPECT_EQ(r, Direction::Degrees(180, -45)) << "-(0, 45)";
} }
TEST(Direction16, Equality) { TYPED_TEST(DirectionTests, Equality) {
Direction16 d; using Direction = DirectionOf<TypeParam>;
d = Direction16::Degrees(135, 45); Direction d;
EXPECT_EQ(d, Direction16::Degrees(135, 45)) << "(135, 45) == (135, 45)"; d = Direction::Degrees(135, 45);
EXPECT_EQ(d, Direction16::Degrees(135 + 360, 45)) EXPECT_EQ(d, Direction::Degrees(135, 45)) << "(135, 45) == (135, 45)";
EXPECT_EQ(d, Direction::Degrees(135 + 360, 45))
<< "(135, 45) == (135 + 360, 45) "; << "(135, 45) == (135 + 360, 45) ";
EXPECT_EQ(d, Direction16::Degrees(135 - 360, 45)) EXPECT_EQ(d, Direction::Degrees(135 - 360, 45))
<< "(135, 135) == (135 - 360, 45) "; << "(135, 135) == (135 - 360, 45) ";
d = Direction16::Degrees(0, 45 + 180); d = Direction::Degrees(0, 45 + 180);
EXPECT_EQ(d, Direction16::Degrees(180, -45)) << "(0, 45+180) == (180, -45)"; EXPECT_EQ(d, Direction::Degrees(180, -45)) << "(0, 45+180) == (180, -45)";
} }
#endif #endif

View File

@ -1,82 +0,0 @@
/*
#if GTEST
#include <gtest/gtest.h>
#include <math.h>
#include <limits>
#include "Angle.h"
// #include "Angle16.h"
// #include "Angle8.h"
#define FLOAT_INFINITY std::numeric_limits<float>::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
*/

View File

@ -14,14 +14,15 @@ bool isDefaultValue(const T& value) {
// return false; // Improve this if you handle non-arithmetic types // return false; // Improve this if you handle non-arithmetic types
} }
using MatrixTypes = ::testing::Types<Matrix2Of<float>, Matrix2Of<int>>; // using MatrixTypes = ::testing::Types<Matrix2Of<float>, Matrix2Of<int>>;
using BaseTypes = ::testing::Types<float, int>;
template <typename T> template <typename T>
class Matrix2Test : public ::testing::Test {}; class Matrix2Tests : public ::testing::Test {};
TYPED_TEST_SUITE(Matrix2Test, MatrixTypes); TYPED_TEST_SUITE(Matrix2Tests, BaseTypes);
TYPED_TEST(Matrix2Test, Zero) { TYPED_TEST(Matrix2Tests, Zero) {
using Matrix2 = TypeParam; using Matrix2 = Matrix2Of<TypeParam>;
// Test case 1: 2x2 zero matrix // Test case 1: 2x2 zero matrix
Matrix2 zeroMatrix = Matrix2::Zero(2, 2); Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
EXPECT_TRUE(zeroMatrix.RowCount() == 2); EXPECT_TRUE(zeroMatrix.RowCount() == 2);
@ -56,60 +57,81 @@ TYPED_TEST(Matrix2Test, Zero) {
std::cout << "Test case 4 passed: 0x0 matrix\n"; std::cout << "Test case 4 passed: 0x0 matrix\n";
} }
// TYPED_TEST(Matrix2Test, Multiplication) { TYPED_TEST(Matrix2Tests, Multiplication) {
// using T = typename TestFixture::TypeParam; using T = TypeParam;
// using Matrix2 = TypeParam; using Matrix2 = Matrix2Of<TypeParam>;
// // Test 1: Multiplying two 2x2 matrices
// T dataA[] = {1, 2, 3, 4};
// T dataB[] = {5, 6, 7, 8};
// Matrix2 A(dataA, 2, 2);
// Matrix2 B(dataB, 2, 2);
// Matrix2 result = A * B; // Test 1: Multiplying two 2x2 matrices
T dataA[] = {1, 2, 3, 4};
T dataB[] = {5, 6, 7, 8};
Matrix2 A(2, 2, dataA);
Matrix2 B(2, 2, dataB);
// float expectedData[] = {19, 22, 43, 50}; Matrix2 result = A * B;
float expectedData[] = {19, 22, 43, 50};
// for (int i = 0; i < 4; ++i) // for (int i = 0; i < 4; ++i)
for (unsigned int rowIx = 0; rowIx < 2; ++rowIx) {
for (unsigned int colIx = 0; colIx < 2; ++colIx) {
EXPECT_TRUE(result(rowIx, colIx) == expectedData[rowIx * 2 + colIx]);
}
}
// EXPECT_TRUE(result.data[i] == expectedData[i]); // EXPECT_TRUE(result.data[i] == expectedData[i]);
// std::cout << "Test 1 passed: 2x2 matrix multiplication.\n"; std::cout << "Test 1 passed: 2x2 matrix multiplication.\n";
// // Test 2: Multiplying a 3x2 matrix with a 2x3 matrix // Test 2: Multiplying a 3x2 matrix with a 2x3 matrix
// float dataC[] = {1, 2, 3, 4, 5, 6}; T dataC[] = {1, 2, 3, 4, 5, 6};
// float dataD[] = {7, 8, 9, 10, 11, 12}; T dataD[] = {7, 8, 9, 10, 11, 12};
// Matrix2 C(dataC, 3, 2); Matrix2 C(3, 2, dataC);
// Matrix2 D(dataD, 2, 3); Matrix2 D(2, 3, dataD);
// Matrix2 result2 = C * D; Matrix2 result2 = C * D;
// float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117}; float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117};
for (unsigned int rowIx = 0; rowIx < 3; ++rowIx) {
for (unsigned int colIx = 0; colIx < 3; ++colIx) {
EXPECT_TRUE(result2(rowIx, colIx) == expectedData2[rowIx * 3 + colIx]);
}
}
// for (int i = 0; i < 9; ++i) // for (int i = 0; i < 9; ++i)
// EXPECT_TRUE(result2.data[i] == expectedData2[i]); // EXPECT_TRUE(result2.data[i] == expectedData2[i]);
// std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n"; std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n";
// // Test 3: Multiplying with a zero matrix // Test 3: Multiplying with a zero matrix
// Matrix2 zeroMatrix = Matrix2::Zero(2, 2); Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
// Matrix2 result3 = A * zeroMatrix; Matrix2 result3 = A * zeroMatrix;
for (unsigned int rowIx = 0; rowIx < 2; ++rowIx) {
for (unsigned int colIx = 0; colIx < 2; ++colIx) {
EXPECT_TRUE(result3(rowIx, colIx) == 0);
}
}
// for (int i = 0; i < 4; ++i) // for (int i = 0; i < 4; ++i)
// EXPECT_TRUE(result3.data[i] == 0); // EXPECT_TRUE(result3.data[i] == 0);
// std::cout << "Test 3 passed: Multiplication with zero matrix.\n"; std::cout << "Test 3 passed: Multiplication with zero matrix.\n";
// // Test 4: Multiplying with an identity matrix // Test 4: Multiplying with an identity matrix
// Matrix2 identityMatrix = Matrix2::Identity(2); Matrix2 identityMatrix = Matrix2::Identity(2);
// Matrix2 result4 = A * identityMatrix; Matrix2 result4 = A * identityMatrix;
for (unsigned int rowIx = 0; rowIx < 2; ++rowIx) {
for (unsigned int colIx = 0; colIx < 2; ++colIx) {
EXPECT_TRUE(result4(rowIx, colIx) == A(rowIx, colIx));
}
}
// for (int i = 0; i < 4; ++i) // for (int i = 0; i < 4; ++i)
// EXPECT_TRUE(result4.data[i] == A.data[i]); // EXPECT_TRUE(result4.data[i] == A.data[i]);
// std::cout << "Test 4 passed: Multiplication with identity matrix.\n"; std::cout << "Test 4 passed: Multiplication with identity matrix.\n";
// } }
template <typename T> template <typename T>
class Matrix1Test : public ::testing::Test { class Matrix1Test : public ::testing::Test {
protected: protected:
}; };
TYPED_TEST_SUITE(Matrix1Test, MatrixTypes); TYPED_TEST_SUITE(Matrix1Test, BaseTypes);
TYPED_TEST(Matrix2Test, Init) { TYPED_TEST(Matrix2Tests, Init) {
using Matrix2 = TypeParam; using Matrix2 = Matrix2Of<TypeParam>;
// zero // zero
Matrix2 m0 = Matrix2(0, 0); Matrix2 m0 = Matrix2(0, 0);
@ -129,8 +151,8 @@ TYPED_TEST(Matrix2Test, Init) {
// parameters are unsigned // parameters are unsigned
} }
TYPED_TEST(Matrix2Test, Transpose) { TYPED_TEST(Matrix2Tests, Transpose) {
using Matrix2 = TypeParam; using Matrix2 = Matrix2Of<TypeParam>;
Matrix2 m = Matrix2(1, 1); Matrix2 m = Matrix2(1, 1);
m(0, 0) = 1; m(0, 0) = 1;
@ -197,9 +219,9 @@ TYPED_TEST(Matrix2Test, Transpose) {
EXPECT_EQ(r12(0, 1), 2); EXPECT_EQ(r12(0, 1), 2);
} }
TYPED_TEST(Matrix2Test, Multiply) { TYPED_TEST(Matrix2Tests, Multiply) {
using Matrix1 = TypeParam; using Matrix2 = Matrix2Of<TypeParam>;
Matrix1 m12 = Matrix1(1, 2); Matrix2 m12 = Matrix2(1, 2);
m12(0, 0) = 1; m12(0, 0) = 1;
m12(0, 1) = 2; m12(0, 1) = 2;
@ -209,7 +231,7 @@ TYPED_TEST(Matrix2Test, Multiply) {
EXPECT_EQ(m12(0, 1), 2); EXPECT_EQ(m12(0, 1), 2);
// float m21data[] = {3.0F, 4.0F}; // float m21data[] = {3.0F, 4.0F};
Matrix1 m21 = Matrix1(2, 1); //, m21data); Matrix2 m21 = Matrix2(2, 1); //, m21data);
m21(0, 0) = 3; m21(0, 0) = 3;
m21(1, 0) = 4; m21(1, 0) = 4;
@ -219,7 +241,7 @@ TYPED_TEST(Matrix2Test, Multiply) {
EXPECT_EQ(m21(1, 0), 4); EXPECT_EQ(m21(1, 0), 4);
// float r11data[] = {0.0F}; // float r11data[] = {0.0F};
Matrix1 r11 = Matrix1::Zero(1, 1); //, r11data); Matrix2 r11 = Matrix2::Zero(1, 1); //, r11data);
EXPECT_EQ(r11.RowCount(), 1); EXPECT_EQ(r11.RowCount(), 1);
EXPECT_EQ(r11.ColCount(), 1); EXPECT_EQ(r11.ColCount(), 1);
@ -230,7 +252,7 @@ TYPED_TEST(Matrix2Test, Multiply) {
EXPECT_EQ(r11(0, 0), 11); EXPECT_EQ(r11(0, 0), 11);
// float r22data[] = {0.0F, 0.0F, 0.0F, 0.0F}; // float r22data[] = {0.0F, 0.0F, 0.0F, 0.0F};
Matrix1 r22 = Matrix1::Zero(2, 2); //, r22data); Matrix2 r22 = Matrix2::Zero(2, 2); //, r22data);
// Matrix1::Multiply(&m21, &m12, &r22); // Matrix1::Multiply(&m21, &m12, &r22);
r22 = m21 * m12; r22 = m21 * m12;
@ -242,21 +264,4 @@ TYPED_TEST(Matrix2Test, Multiply) {
EXPECT_EQ(r22(1, 1), 8); EXPECT_EQ(r22(1, 1), 8);
} }
// TYPED_TEST(Matrix2Test, Multiply_Vector3) {
// using Matrix2 = TypeParam;
// auto v = Vector3(1.0, 2.0, 3.0);
// Matrix1Of r = Matrix1Of<int>::zero;
// // float m13data[] = {3.0, 4.0, 5.0};
// // Matrix1 m13 = Matrix1(1, 3, m13data);
// // Vector3 r = Matrix1::Multiply(&m13, v);
// //float m33data[] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
// Matrix2 m33 = Matrix2::Identity(3, 3); //, m33data);
// //r = Matrix1::Multiply(&m33, v);
// r = m33 * v;
// EXPECT_FLOAT_EQ(Vector3::Distance(r, Vector3(1.0f, 2.0f, 3.0f)), 0);
// }
#endif #endif

View File

@ -394,7 +394,7 @@ TEST(Vector2, Distance) {
TEST(Vector2, Angle) { TEST(Vector2, Angle) {
Vector2 v1 = Vector2(4, 5); Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2); Vector2 v2 = Vector2(1, 2);
Angle f = Angle::zero; AngleSingle f = AngleSingle::zero;
bool r = false; bool r = false;
f = Vector2::UnsignedAngle(v1, v2); f = Vector2::UnsignedAngle(v1, v2);
@ -426,7 +426,7 @@ TEST(Vector2, Angle) {
TEST(Vector2, SignedAngle) { TEST(Vector2, SignedAngle) {
Vector2 v1 = Vector2(4, 5); Vector2 v1 = Vector2(4, 5);
Vector2 v2 = Vector2(1, 2); Vector2 v2 = Vector2(1, 2);
Angle f = Angle::zero; AngleSingle f = AngleSingle::zero;
bool r = false; bool r = false;
f = Vector2::SignedAngle(v1, v2); f = Vector2::SignedAngle(v1, v2);