LinearAlgebra-cpp/test/Spherical_test.cc
Pascal Serrarens b555fb5d6a
All checks were successful
Build and Run C++ Unit Tests / build-and-test (push) Successful in 2m2s
Converted all unit tests to template form
2025-12-22 15:01:11 +01:00

253 lines
8.9 KiB
C++

#if GTEST
#include <gtest/gtest.h>
#include <math.h>
#include <chrono>
#include <limits>
#include "Spherical.h"
#include "Vector3.h"
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
using BaseTypes = ::testing::Types<float, signed short>;
template <typename T>
class SphericalTests : public ::testing::Test {};
TYPED_TEST_SUITE(SphericalTests, BaseTypes);
TYPED_TEST(SphericalTests, FromVector3) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
Vector3Of<float> v = Vector3Of<float>(0, 0, 1);
Spherical s = Spherical::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 = Vector3Of<float>(0, 1, 0);
s = Spherical::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 = Vector3Of<float>(1, 0, 0);
s = Spherical::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";
}
TYPED_TEST(SphericalTests, Vector3) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
Vector3Of<float> v = Vector3Of<float>(1, 2, 3);
Spherical rd = Spherical::FromVector3(v);
Vector3Of<float> rv = rd.ToVector3();
EXPECT_LT(Vector3Of<float>::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
v = Vector3Of<float>(1, 2, -3);
rd = Spherical::FromVector3(v);
rv = rd.ToVector3();
EXPECT_LT(Vector3Of<float>::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
}
// TYPED_TEST(SphericalTests, FromPolar) {
// using T = TypeParam;
// using Spherical = SphericalOf<T>;
// Polar p = Polar(1, 0);
// Spherical s = Spherical::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 = Spherical::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 = Spherical::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 = Spherical::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 = Spherical::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)";
// }
TYPED_TEST(SphericalTests, Incident1) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Vector3Of<float> v = Vector3Of<float>(2.242557f, 1.027884f, -0.322347f);
Spherical s = Spherical::FromVector3(v);
Spherical sr =
Spherical(2.49F, Angle::Degrees(98.18f), Angle::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);
Vector3Of<float> r =
Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-02) << "toVector3.x 1 0 0";
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-02) << "toVector3.y 1 0 0";
EXPECT_NEAR(r.depth, v.depth, 1.0e-02) << "toVector3.z 1 0 0";
}
TYPED_TEST(SphericalTests, Incident2) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Vector3Of<float> v = Vector3Of<float>(1.0f, 0.0f, 1.0f);
Spherical s = Spherical::FromVector3(v);
Spherical sr =
Spherical(1.4142135623F, Angle::Degrees(45.0f), Angle::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);
Vector3Of<float> r =
Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-06);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-06);
EXPECT_NEAR(r.depth, v.depth, 1.0e-06);
v = Vector3Of<float>(0.0f, 1.0f, 1.0f);
s = Spherical::FromVector3(v);
sr = Spherical(1.4142135623F, Angle::Degrees(0), Angle::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 = Spherical(sr.distance, sr.direction.horizontal, sr.direction.vertical)
.ToVector3();
EXPECT_NEAR(r.horizontal, v.horizontal, 1.0e-06);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-06);
EXPECT_NEAR(r.depth, v.depth, 1.0e-06);
v = Vector3Of<float>(1.0f, 1.0f, 1.0f);
s = Spherical::FromVector3(v);
r = Spherical(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.horizontal, v.horizontal, 1.0e-04);
EXPECT_NEAR(r.vertical, v.vertical, 1.0e-04);
EXPECT_NEAR(r.depth, v.depth, 1.0e-04);
// s = Spherical(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);
}
TYPED_TEST(SphericalTests, Addition) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
using Angle = AngleOf<T>;
Spherical v1 = Spherical(1, Angle::Degrees(45), Angle::Degrees(0));
Spherical v2 = Spherical::zero;
Spherical r = Spherical::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 = Spherical(1, Angle::Degrees(-45), Angle::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 = Spherical(1, Angle::Degrees(0), Angle::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)";
}
TYPED_TEST(SphericalTests, AdditionPerformance) {
using T = TypeParam;
using Spherical = SphericalOf<T>;
const int numIterations = 1000000; // Number of additions to test
std::vector<Spherical> 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);
Spherical s = Spherical::Deg(distance, horizontal, vertical);
sphericalObjects.push_back(s);
}
// Measure the time to perform multiple additions
auto start = std::chrono::high_resolution_clock::now();
Spherical result = Spherical::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<double> 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