migrate to new JTest API
This commit is contained in:
@@ -34,7 +34,7 @@ set_target_properties(J3ML PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jtest
|
||||
URL https://git.redacted.cc/josh/jtest/archive/Prerelease-5.zip
|
||||
URL https://git.redacted.cc/josh/jtest/archive/Release-1.1.zip
|
||||
)
|
||||
|
||||
target_include_directories(J3ML PUBLIC ${jtest_SOURCE_DIR}/include)
|
||||
|
@@ -1,142 +1,149 @@
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
#include <jtest/jtest.hpp>
|
||||
using J3ML::Algorithm::RNG;
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
void Float01InclTest()
|
||||
jtest::Unit RNGUnit{"RNG"};
|
||||
|
||||
|
||||
namespace RNGTests
|
||||
{
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
inline void Define()
|
||||
{
|
||||
float f = rng.Float01Incl();
|
||||
float f2 = rng.Float01Incl();
|
||||
using namespace jtest;
|
||||
using J3ML::Algorithm::RNG;
|
||||
|
||||
RNGUnit += Test("IntFast", []{
|
||||
RNG rng;
|
||||
u32 prev = rng.IntFast();
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
u32 next = rng.IntFast();
|
||||
jtest::check(next != prev);
|
||||
prev = next;
|
||||
}
|
||||
});
|
||||
|
||||
RNGUnit += Test("Int", []{
|
||||
RNG rng;
|
||||
assert(rng.lastNumber != 0 || rng.increment != 0);
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int prev = rng.Int();
|
||||
int next = rng.Int();
|
||||
jtest::check(prev != 0 || next != 0);
|
||||
if (prev != next)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
|
||||
});
|
||||
|
||||
RNGUnit += Test("Int_A_B", []{
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int a = rng.Int();
|
||||
int b = rng.Int();
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
int val = rng.Int(a, b);
|
||||
jtest::check( a <= val);
|
||||
jtest::check(val <= b);
|
||||
}
|
||||
});
|
||||
|
||||
RNGUnit += Test("Float", []{
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float f = rng.Float();
|
||||
float f2 = rng.Float();
|
||||
jtest::check(f < 1.f);
|
||||
jtest::check(f >= 0.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
});
|
||||
|
||||
|
||||
|
||||
RNGUnit += Test("Float01Incl", [] {
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float f = rng.Float01Incl();
|
||||
float f2 = rng.Float01Incl();
|
||||
|
||||
jtest::check(f <= 1.f);
|
||||
jtest::check(f >= 0.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
});
|
||||
|
||||
RNGUnit += Test("FloatNeg1_1", []{
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float f = rng.FloatNeg1_1();
|
||||
float f2 = rng.FloatNeg1_1();
|
||||
jtest::check(f < 1.f);
|
||||
jtest::check(f > -1.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
});
|
||||
|
||||
RNGUnit += Test("Float_A_B", []{
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float a = rng.Float();
|
||||
float b = rng.Float();
|
||||
if (a == b)
|
||||
continue;
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
|
||||
float f = rng.Float(a, b);
|
||||
jtest::check(a <= f);
|
||||
jtest::check(f < b);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
RNGUnit += Test("Float_A_B_Incl", [] {
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float a = rng.Float();
|
||||
float b = rng.Float();
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
|
||||
float f = rng.FloatIncl(a, b);
|
||||
jtest::check(a <= f);
|
||||
jtest::check(f <= b);
|
||||
}
|
||||
});
|
||||
|
||||
jtest::check(f <= 1.f);
|
||||
jtest::check(f >= 0.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
}
|
||||
|
||||
void FloatABInclTest()
|
||||
{
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
inline void Run()
|
||||
{
|
||||
float a = rng.Float();
|
||||
float b = rng.Float();
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
|
||||
float f = rng.FloatIncl(a, b);
|
||||
jtest::check(a <= f);
|
||||
jtest::check(f <= b);
|
||||
RNGUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
int RNGTests()
|
||||
{
|
||||
TEST("RNG::IntFast", []{
|
||||
RNG rng;
|
||||
u32 prev = rng.IntFast();
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
u32 next = rng.IntFast();
|
||||
jtest::check(next != prev);
|
||||
prev = next;
|
||||
}
|
||||
});
|
||||
|
||||
TEST("RNG::Int", []{
|
||||
RNG rng;
|
||||
assert(rng.lastNumber != 0 || rng.increment != 0);
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int prev = rng.Int();
|
||||
int next = rng.Int();
|
||||
jtest::check(prev != 0 || next != 0);
|
||||
if (prev != next)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
|
||||
});
|
||||
|
||||
TEST("Rng::Int_A_B", []{
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int a = rng.Int();
|
||||
int b = rng.Int();
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
int val = rng.Int(a, b);
|
||||
jtest::check( a <= val);
|
||||
jtest::check(val <= b);
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Rng::Float", []{
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float f = rng.Float();
|
||||
float f2 = rng.Float();
|
||||
jtest::check(f < 1.f);
|
||||
jtest::check(f >= 0.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
});
|
||||
|
||||
|
||||
|
||||
TEST("Rng::Float01Incl", Float01InclTest);
|
||||
|
||||
TEST("Rng::FloatNeg1_1", []{
|
||||
RNG rng;
|
||||
bool allEqual = true;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float f = rng.FloatNeg1_1();
|
||||
float f2 = rng.FloatNeg1_1();
|
||||
jtest::check(f < 1.f);
|
||||
jtest::check(f > -1.f);
|
||||
jtest::check(f != 0.f || f2 != 0.f);
|
||||
if (f != f2)
|
||||
allEqual = false;
|
||||
}
|
||||
jtest::check(!allEqual);
|
||||
});
|
||||
|
||||
TEST("Rng, Float_A_B", []{
|
||||
RNG rng;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
float a = rng.Float();
|
||||
float b = rng.Float();
|
||||
if (a == b)
|
||||
continue;
|
||||
if (b < a)
|
||||
Swap(a, b);
|
||||
|
||||
float f = rng.Float(a, b);
|
||||
jtest::check(a <= f);
|
||||
jtest::check(f < b);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
TEST("Rng::Float_A_B_Incl", FloatABInclTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -11,83 +11,88 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/LineSegment.hpp>
|
||||
#include <J3ML/Geometry/Sphere.hpp>
|
||||
|
||||
jtest::Unit AABBUnit {"AABB"};
|
||||
namespace AABBTests {
|
||||
inline void Define()
|
||||
{
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Geometry;
|
||||
|
||||
void AABBTests()
|
||||
{
|
||||
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Geometry;
|
||||
|
||||
TEST("AABB::Contains", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
AABBUnit += Test("Contains", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
|
||||
|
||||
check(a.Contains({0,0,0}));
|
||||
check(a.Contains({10,10,10}));
|
||||
check(a.Contains({1,2,3}));
|
||||
check(!a.Contains({-1, 2, 3}));
|
||||
check(!a.Contains({1, -2, 3}));
|
||||
check(!a.Contains({1, 2, -3}));
|
||||
check(!a.Contains({11, 2, 3}));
|
||||
});
|
||||
check(a.Contains({0,0,0}));
|
||||
check(a.Contains({10,10,10}));
|
||||
check(a.Contains({1,2,3}));
|
||||
check(!a.Contains({-1, 2, 3}));
|
||||
check(!a.Contains({1, -2, 3}));
|
||||
check(!a.Contains({1, 2, -3}));
|
||||
check(!a.Contains({11, 2, 3}));
|
||||
});
|
||||
|
||||
TEST("AABB::ContainsAABB", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
check(a.Contains(a));
|
||||
check(a.Contains(AABB({5, 5, 5}, {6, 6, 6})));
|
||||
check(a.Contains(AABB({5, 5, 5}, {10, 6, 6})));
|
||||
check(!a.Contains(AABB({5,5,5}, {15, 15, 15})));
|
||||
check(!a.Contains(AABB({5,5,5}, {5, 15, 5})));
|
||||
check(!a.Contains(AABB({-5,-5,-5}, {5, 5, 5})));
|
||||
check(!a.Contains(AABB({-5,-5,-5}, {0, 0, 0})));
|
||||
});
|
||||
AABBUnit += Test("ContainsAABB", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
check(a.Contains(a));
|
||||
check(a.Contains(AABB({5, 5, 5}, {6, 6, 6})));
|
||||
check(a.Contains(AABB({5, 5, 5}, {10, 6, 6})));
|
||||
check(!a.Contains(AABB({5,5,5}, {15, 15, 15})));
|
||||
check(!a.Contains(AABB({5,5,5}, {5, 15, 5})));
|
||||
check(!a.Contains(AABB({-5,-5,-5}, {5, 5, 5})));
|
||||
check(!a.Contains(AABB({-5,-5,-5}, {0, 0, 0})));
|
||||
});
|
||||
|
||||
|
||||
TEST("AABB::ContainsLineSegment", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
AABBUnit += Test("ContainsLineSegment", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
|
||||
check(a.Contains(LineSegment({0,0,0}, {10,10,10})));
|
||||
check(a.Contains(LineSegment({10,10,10}, {0,0,0})));
|
||||
check(a.Contains(LineSegment({5,5,5}, {6,6,6})));
|
||||
check(a.Contains(LineSegment({5,5,5}, {10,6,6})));
|
||||
check(!a.Contains(LineSegment({5,5,5}, {15, 15, 15})));
|
||||
check(!a.Contains(LineSegment({5,5,5}, {5, 15,5})));
|
||||
check(!a.Contains(LineSegment({-5, -5, -5}, {5,5,5})));
|
||||
check(!a.Contains(LineSegment({-5, -5, -5}, {0,0,0})));
|
||||
check(!a.Contains(LineSegment({15, 15, 15}, {0,0,0})));
|
||||
});
|
||||
check(a.Contains(LineSegment({0,0,0}, {10,10,10})));
|
||||
check(a.Contains(LineSegment({10,10,10}, {0,0,0})));
|
||||
check(a.Contains(LineSegment({5,5,5}, {6,6,6})));
|
||||
check(a.Contains(LineSegment({5,5,5}, {10,6,6})));
|
||||
check(!a.Contains(LineSegment({5,5,5}, {15, 15, 15})));
|
||||
check(!a.Contains(LineSegment({5,5,5}, {5, 15,5})));
|
||||
check(!a.Contains(LineSegment({-5, -5, -5}, {5,5,5})));
|
||||
check(!a.Contains(LineSegment({-5, -5, -5}, {0,0,0})));
|
||||
check(!a.Contains(LineSegment({15, 15, 15}, {0,0,0})));
|
||||
});
|
||||
|
||||
TEST("AABB::ContainsSphere", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
check(a.Contains(Sphere({0,0,0}, 0.f)));
|
||||
check(a.Contains(Sphere({5,5,5}, 1.f)));
|
||||
check(!a.Contains(Sphere({5,5,5}, 15.f)));
|
||||
check(!a.Contains(Sphere({9,5,5}, 2.f)));
|
||||
check(!a.Contains(Sphere({1,5,5}, 2.f)));
|
||||
check(!a.Contains(Sphere({-10, -10, -10}, 1000.f)));
|
||||
});
|
||||
AABBUnit += Test("ContainsSphere", [] {
|
||||
AABB a ({0,0,0}, {10,10,10});
|
||||
check(a.Contains(Sphere({0,0,0}, 0.f)));
|
||||
check(a.Contains(Sphere({5,5,5}, 1.f)));
|
||||
check(!a.Contains(Sphere({5,5,5}, 15.f)));
|
||||
check(!a.Contains(Sphere({9,5,5}, 2.f)));
|
||||
check(!a.Contains(Sphere({1,5,5}, 2.f)));
|
||||
check(!a.Contains(Sphere({-10, -10, -10}, 1000.f)));
|
||||
});
|
||||
|
||||
TEST("AABB::IntersectsAABB", [] {
|
||||
AABB a({0,0,0}, {10,10,10});
|
||||
AABB b({5,0,0}, {15,10,10});
|
||||
AABB c({-5,-5,-5}, {0,10,0});
|
||||
AABB d({20,20,20}, {30,30,30});
|
||||
AABB e({1,1,1}, {9,9,9});
|
||||
check(a.Intersects(a));
|
||||
check(a.Intersects(b));
|
||||
check(!a.Intersects(c));
|
||||
check(!a.Intersects(d));
|
||||
check(a.Intersects(e));
|
||||
});
|
||||
AABBUnit += Test("IntersectsAABB", [] {
|
||||
AABB a({0,0,0}, {10,10,10});
|
||||
AABB b({5,0,0}, {15,10,10});
|
||||
AABB c({-5,-5,-5}, {0,10,0});
|
||||
AABB d({20,20,20}, {30,30,30});
|
||||
AABB e({1,1,1}, {9,9,9});
|
||||
check(a.Intersects(a));
|
||||
check(a.Intersects(b));
|
||||
check(!a.Intersects(c));
|
||||
check(!a.Intersects(d));
|
||||
check(a.Intersects(e));
|
||||
});
|
||||
|
||||
|
||||
TEST("AABB::TransformAsAABB", []{ /* TODO: Implement Test Stub */ });
|
||||
TEST("AABB::IsDegenerate", []{ /* TODO: Implement Test Stub */ });
|
||||
TEST("AABB::Volume", []{ /* TODO: Implement Test Stub */ });
|
||||
AABBUnit += Test("TransformAsAABB", []{ /* TODO: Implement Test Stub */ });
|
||||
AABBUnit += Test("IsDegenerate", []{ /* TODO: Implement Test Stub */ });
|
||||
AABBUnit += Test("Volume", []{ /* TODO: Implement Test Stub */ });
|
||||
}
|
||||
|
||||
inline void Run() {
|
||||
AABBUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
67
tests/Geometry/CommonGeometryTests.hpp
Normal file
67
tests/Geometry/CommonGeometryTests.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/Geometry/Forward.hpp>
|
||||
#include <jtest/jtest.hpp>
|
||||
|
||||
jtest::Unit CommonGeometryUnit {"CommonGeometry"};
|
||||
namespace CommonGeometryTests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
using J3ML::Geometry::Interval;
|
||||
|
||||
CommonGeometryUnit += Test("Interval_Intersect", [] {
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{0, 1}.Intersects({2, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({0, 1})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 4}.Intersects({3, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 4}.Intersects({1, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({3, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{3, 5}.Intersects({2, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({2, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({2, 3})));
|
||||
|
||||
// . a
|
||||
// . b
|
||||
jtest::check(!(Interval{2, 2}.Intersects({2, 2})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 5}.Intersects({3, 4})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{3, 4}.Intersects({2, 5})));
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run() {
|
||||
CommonGeometryUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
#include <J3ML/Geometry/Frustum.hpp>
|
||||
#include <J3ML/Geometry/PBVolume.hpp>
|
||||
@@ -44,285 +45,295 @@ Frustum GenIdFrustum(FrustumType t, FrustumHandedness h, FrustumProjectiveSpace
|
||||
case 7 : f = GenIdFrustum(FrustumType::Orthographic, FrustumHandedness::Right, FrustumProjectiveSpace::D3D); break; \
|
||||
} \
|
||||
|
||||
jtest::Unit FrustumUnit {"Frustum"};
|
||||
namespace FrustumTests
|
||||
{
|
||||
inline void Define()
|
||||
{
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Geometry;
|
||||
using namespace J3ML::Math;
|
||||
|
||||
void FrustumTests() {
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Geometry;
|
||||
using namespace J3ML::Math;
|
||||
RNG rng;
|
||||
|
||||
RNG rng;
|
||||
|
||||
TEST("Frustum::AspectRatio", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(EqualAbs(f.AspectRatio(), 1.f));
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
TEST("Frustum::WorldRight", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.WorldRight().Equals({1, 0, 0}));
|
||||
} else { // In the test func, all cameras lock down to -Z, so left-handed cameras need to point their right towards -X then.
|
||||
check(f.WorldRight().Equals({-1, 0, 0}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Frustum::Chirality", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(f.WorldMatrix().Determinant() > 0.f);
|
||||
check(f.ViewMatrix().Determinant() > 0.f);
|
||||
if (f.Handedness() == FrustumHandedness::Left)
|
||||
check(f.ProjectionMatrix().Determinant4() > 0.f); // left-handed view -> projection space transform does not change handedness.
|
||||
else
|
||||
check(f.ProjectionMatrix().Determinant4() < 0.f); // but right-handed transform should.
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Frustum::Planes", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(f.NearPlane().Normal.Equals({0,0,1}));
|
||||
check(Math::EqualAbs(f.NearPlane().distance, -1.f));
|
||||
|
||||
check(f.FarPlane().Normal.Equals({0,0,-1}));
|
||||
check(Math::EqualAbs(f.FarPlane().distance, 100.f));
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
Vector3 pt;
|
||||
if (i == 8)
|
||||
pt = f.CenterPoint();
|
||||
else
|
||||
pt = f.CornerPoint(i);
|
||||
check(f.NearPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.FarPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.LeftPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.RightPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.TopPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.BottomPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.Contains(pt));
|
||||
FrustumUnit += Test("Frustum::AspectRatio", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(EqualAbs(f.AspectRatio(), 1.f));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
TEST("Frustum::Corners", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
|
||||
// Corner points are returned in XYZ order: 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++
|
||||
if (f.Type() == FrustumType::Perspective && f.Handedness() == FrustumHandedness::Left) {
|
||||
check(f.CornerPoint(0).Equals({1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({1.f, 1, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({100.f, 100.f, 100.f}));
|
||||
check(f.CornerPoint(4).Equals({-1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({-100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({-1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({-100.f, 100.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Perspective && f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.CornerPoint(0).Equals({-1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({-100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({-1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({-100.f, 100.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({100.f, 100.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Orthographic && f.Handedness() == FrustumHandedness::Left) {
|
||||
check(f.CornerPoint(0).Equals({50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({50.f, 50.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({-50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({-50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({-50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({-50.f, 50.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Orthographic && f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.CornerPoint(0).Equals({-50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({-50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({-50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({-50.f, 50.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({50.f, 50.f, -100.f}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Frustum::ProjectUnprojectSymmetry", [&rng] {
|
||||
|
||||
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// Orient and locate the Frustum randomly
|
||||
Matrix3x3 rot = Matrix3x3::RandomRotation(rng);
|
||||
f.Transform(rot);
|
||||
f.SetPos(f.Pos() + Vector3::RandomDir(rng, rng.Float(1.f, 100.f)));
|
||||
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
Vector2 pt = Vector2::RandomBox(rng, -1.f, 1.f);
|
||||
Vector3 pos = f.NearPlanePos(pt);
|
||||
Vector3 pt2 = f.Project(pos);
|
||||
check(pt.Equals(pt2.XY()));
|
||||
|
||||
pos = f.FarPlanePos(pt);
|
||||
pt2 = f.Project(pos);
|
||||
check(pt.Equals(pt2.XY()));
|
||||
|
||||
pos = f.PointInside(pt.x, pt.y, rng.Float());
|
||||
pt2 = f.Project(pos);
|
||||
FrustumUnit += Test("Frustum::WorldRight", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.WorldRight().Equals({1, 0, 0}));
|
||||
} else { // In the test func, all cameras lock down to -Z, so left-handed cameras need to point their right towards -X then.
|
||||
check(f.WorldRight().Equals({-1, 0, 0}));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Frustum::PlaneNormalsAreCorrect", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
auto pb = f.ToPBVolume();
|
||||
Vector3 corners[8];
|
||||
Plane planes[6];
|
||||
f.GetCornerPoints(corners);
|
||||
f.GetPlanes(planes);
|
||||
FrustumUnit += Test("Frustum::Chirality", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(f.WorldMatrix().Determinant() > 0.f);
|
||||
check(f.ViewMatrix().Determinant() > 0.f);
|
||||
if (f.Handedness() == FrustumHandedness::Left)
|
||||
check(f.ProjectionMatrix().Determinant4() > 0.f); // left-handed view -> projection space transform does not change handedness.
|
||||
else
|
||||
check(f.ProjectionMatrix().Determinant4() < 0.f); // but right-handed transform should.
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
check(pb.Contains(corners[i]));
|
||||
FrustumUnit += Test("Frustum::Planes", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
check(f.NearPlane().Normal.Equals({0,0,1}));
|
||||
check(Math::EqualAbs(f.NearPlane().distance, -1.f));
|
||||
|
||||
for(int i = 0; i < 6; ++i)
|
||||
for(int j = 0; j < 8; ++j)
|
||||
check(planes[i].SignedDistance(corners[j]) <= 0.f);
|
||||
}
|
||||
});
|
||||
check(f.FarPlane().Normal.Equals({0,0,-1}));
|
||||
check(Math::EqualAbs(f.FarPlane().distance, 100.f));
|
||||
|
||||
TEST("Frustum::IsConvex", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
Polyhedron p = f.ToPolyhedron();
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
Vector3 pt;
|
||||
if (i == 8)
|
||||
pt = f.CenterPoint();
|
||||
else
|
||||
pt = f.CornerPoint(i);
|
||||
check(f.NearPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.FarPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.LeftPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.RightPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.TopPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.BottomPlane().SignedDistance(pt) < 1e-3f);
|
||||
check(f.Contains(pt));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for(int i = 0; i < 6; ++i)
|
||||
|
||||
FrustumUnit += Test("Frustum::Corners", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
|
||||
// Corner points are returned in XYZ order: 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++
|
||||
if (f.Type() == FrustumType::Perspective && f.Handedness() == FrustumHandedness::Left) {
|
||||
check(f.CornerPoint(0).Equals({1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({1.f, 1, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({100.f, 100.f, 100.f}));
|
||||
check(f.CornerPoint(4).Equals({-1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({-100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({-1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({-100.f, 100.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Perspective && f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.CornerPoint(0).Equals({-1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({-100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({-1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({-100.f, 100.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({1.f, -1.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({100.f, -100.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({1.f, 1.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({100.f, 100.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Orthographic && f.Handedness() == FrustumHandedness::Left) {
|
||||
check(f.CornerPoint(0).Equals({50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({50.f, 50.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({-50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({-50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({-50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({-50.f, 50.f, -100.f}));
|
||||
} else if (f.Type() == FrustumType::Orthographic && f.Handedness() == FrustumHandedness::Right) {
|
||||
check(f.CornerPoint(0).Equals({-50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(1).Equals({-50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(2).Equals({-50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(3).Equals({-50.f, 50.f, -100.f}));
|
||||
check(f.CornerPoint(4).Equals({50.f, -50.f, -1.f}));
|
||||
check(f.CornerPoint(5).Equals({50.f, -50.f, -100.f}));
|
||||
check(f.CornerPoint(6).Equals({50.f, 50.f, -1.f}));
|
||||
check(f.CornerPoint(7).Equals({50.f, 50.f, -100.f}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::ProjectUnprojectSymmetry", [&rng] {
|
||||
|
||||
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// Orient and locate the Frustum randomly
|
||||
Matrix3x3 rot = Matrix3x3::RandomRotation(rng);
|
||||
f.Transform(rot);
|
||||
f.SetPos(f.Pos() + Vector3::RandomDir(rng, rng.Float(1.f, 100.f)));
|
||||
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
Vector2 pt = Vector2::RandomBox(rng, -1.f, 1.f);
|
||||
Vector3 pos = f.NearPlanePos(pt);
|
||||
Vector3 pt2 = f.Project(pos);
|
||||
check(pt.Equals(pt2.XY()));
|
||||
|
||||
pos = f.FarPlanePos(pt);
|
||||
pt2 = f.Project(pos);
|
||||
check(pt.Equals(pt2.XY()));
|
||||
|
||||
pos = f.PointInside(pt.x, pt.y, rng.Float());
|
||||
pt2 = f.Project(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::PlaneNormalsAreCorrect", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
auto pb = f.ToPBVolume();
|
||||
Vector3 corners[8];
|
||||
Plane planes[6];
|
||||
f.GetCornerPoints(corners);
|
||||
f.GetPlanes(planes);
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
check(pb.Contains(corners[i]));
|
||||
|
||||
for(int i = 0; i < 6; ++i)
|
||||
for(int j = 0; j < 8; ++j)
|
||||
check(planes[i].SignedDistance(corners[j]) <= 0.f);
|
||||
}
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::IsConvex", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
Polyhedron p = f.ToPolyhedron();
|
||||
|
||||
for(int i = 0; i < 6; ++i)
|
||||
{
|
||||
Plane p1 = f.GetPlane(i);
|
||||
Plane p2 = p.FacePlane(i);
|
||||
check(p1.Equals(p2));
|
||||
}
|
||||
check(p.EulerFormulaHolds());
|
||||
check(p.IsClosed());
|
||||
check(p.IsConvex());
|
||||
check(!p.IsNull());
|
||||
}
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Plane::ProjectToNegativeHalf", [] {
|
||||
Plane p(Vector3(0,1,0), 50.f);
|
||||
|
||||
Vector3 neg = Vector3(0,-100.f, 0);
|
||||
Vector3 pos = Vector3(0, 100.f, 0);
|
||||
check(neg.Equals(p.ProjectToNegativeHalf(neg)));
|
||||
check(!neg.Equals(p.ProjectToPositiveHalf(neg)));
|
||||
|
||||
check(pos.Equals(p.ProjectToPositiveHalf(pos)));
|
||||
check(!pos.Equals(p.ProjectToNegativeHalf(pos)));
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::Contains", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
for(int i = 0; i < 8; ++i)
|
||||
{
|
||||
Vector3 corner = f.CornerPoint(i);
|
||||
Vector3 closestPoint = f.ClosestPoint(corner);
|
||||
float distance = f.Distance(corner);
|
||||
if (!f.Contains(corner) || distance > 1e-4f)
|
||||
//LOGE("Closest point to %s: %s", corner.ToString().c_str(), closestPoint.ToString().c_str());
|
||||
check(f.Contains(corner));
|
||||
check(distance < 10.f);
|
||||
}
|
||||
check(f.Contains(f.CenterPoint()));
|
||||
}
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::ContainsCorners", [&rng] {
|
||||
constexpr float SCALE = 1e2f;
|
||||
|
||||
Vector3 pt = Vector3::RandomBox(rng, Vector3::FromScalar(-SCALE), Vector3::FromScalar(SCALE));
|
||||
Frustum b;// = RandomFrustumContainingPoint(rng, pt);
|
||||
|
||||
for(int i = 0; i < 9; ++i)
|
||||
{
|
||||
Plane p1 = f.GetPlane(i);
|
||||
Plane p2 = p.FacePlane(i);
|
||||
check(p1.Equals(p2));
|
||||
Vector3 point = (i == 8) ? b.CenterPoint() : b.CornerPoint(i);
|
||||
|
||||
check(b.NearPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.FarPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.LeftPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.RightPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.TopPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.BottomPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.Contains(point));
|
||||
}
|
||||
check(p.EulerFormulaHolds());
|
||||
check(p.IsClosed());
|
||||
check(p.IsConvex());
|
||||
check(!p.IsNull());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Plane::ProjectToNegativeHalf", [] {
|
||||
Plane p(Vector3(0,1,0), 50.f);
|
||||
FrustumUnit += Test("Frustum::Matrices", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Handedness() == FrustumHandedness::Right) {
|
||||
Matrix4x4 wm = f.WorldMatrix();
|
||||
check(wm.IsIdentity());
|
||||
|
||||
Vector3 neg = Vector3(0,-100.f, 0);
|
||||
Vector3 pos = Vector3(0, 100.f, 0);
|
||||
check(neg.Equals(p.ProjectToNegativeHalf(neg)));
|
||||
check(!neg.Equals(p.ProjectToPositiveHalf(neg)));
|
||||
Matrix4x4 vm = f.ViewMatrix();
|
||||
check(vm.IsIdentity());
|
||||
} else {
|
||||
Matrix4x4 wm = f.WorldMatrix() * Matrix4x4::RotateY(Math::Pi);
|
||||
check(wm.IsIdentity());
|
||||
|
||||
check(pos.Equals(p.ProjectToPositiveHalf(pos)));
|
||||
check(!pos.Equals(p.ProjectToNegativeHalf(pos)));
|
||||
});
|
||||
|
||||
TEST("Frustum::Contains", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
for(int i = 0; i < 8; ++i)
|
||||
{
|
||||
Vector3 corner = f.CornerPoint(i);
|
||||
Vector3 closestPoint = f.ClosestPoint(corner);
|
||||
float distance = f.Distance(corner);
|
||||
if (!f.Contains(corner) || distance > 1e-4f)
|
||||
//LOGE("Closest point to %s: %s", corner.ToString().c_str(), closestPoint.ToString().c_str());
|
||||
check(f.Contains(corner));
|
||||
check(distance < 10.f);
|
||||
Matrix4x4 vm = f.ViewMatrix() * Matrix4x4::RotateY(Math::Pi);
|
||||
check(vm.IsIdentity());
|
||||
}
|
||||
}
|
||||
check(f.Contains(f.CenterPoint()));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Frustum::ContainsCorners", [&rng] {
|
||||
constexpr float SCALE = 1e2f;
|
||||
FrustumUnit += Test("Frustum::Projection", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
const float nearD = (f.ProjectiveSpace() == FrustumProjectiveSpace::D3D) ? 0.f : -1.f;
|
||||
|
||||
Vector3 pt = Vector3::RandomBox(rng, Vector3::FromScalar(-SCALE), Vector3::FromScalar(SCALE));
|
||||
Frustum b;// = RandomFrustumContainingPoint(rng, pt);
|
||||
|
||||
for(int i = 0; i < 9; ++i)
|
||||
{
|
||||
Vector3 point = (i == 8) ? b.CenterPoint() : b.CornerPoint(i);
|
||||
|
||||
check(b.NearPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.FarPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.LeftPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.RightPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.TopPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.BottomPlane().SignedDistance(point) < 1e-3f);
|
||||
check(b.Contains(point));
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Frustum::Matrices", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Handedness() == FrustumHandedness::Right) {
|
||||
Matrix4x4 wm = f.WorldMatrix();
|
||||
check(wm.IsIdentity());
|
||||
|
||||
Matrix4x4 vm = f.ViewMatrix();
|
||||
check(vm.IsIdentity());
|
||||
} else {
|
||||
Matrix4x4 wm = f.WorldMatrix() * Matrix4x4::RotateY(Math::Pi);
|
||||
check(wm.IsIdentity());
|
||||
|
||||
Matrix4x4 vm = f.ViewMatrix() * Matrix4x4::RotateY(Math::Pi);
|
||||
check(vm.IsIdentity());
|
||||
// Corner points are returned in XYZ order: 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++
|
||||
check(f.Project(f.CornerPoint(0)).Equals({-1,-1, nearD}));
|
||||
check(f.Project(f.CornerPoint(1)).Equals({-1,-1, 1}));
|
||||
check(f.Project(f.CornerPoint(2)).Equals({-1,1, nearD}));
|
||||
check(f.Project(f.CornerPoint(3)).Equals({-1,1, 1}));
|
||||
check(f.Project(f.CornerPoint(4)).Equals({1,-1, nearD}));
|
||||
check(f.Project(f.CornerPoint(5)).Equals({1,-1, 1}));
|
||||
check(f.Project(f.CornerPoint(6)).Equals({1,1, nearD}));
|
||||
check(f.Project(f.CornerPoint(7)).Equals({1,1, 1}));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Frustum::Projection", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
const float nearD = (f.ProjectiveSpace() == FrustumProjectiveSpace::D3D) ? 0.f : -1.f;
|
||||
|
||||
// Corner points are returned in XYZ order: 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++
|
||||
check(f.Project(f.CornerPoint(0)).Equals({-1,-1, nearD}));
|
||||
check(f.Project(f.CornerPoint(1)).Equals({-1,-1, 1}));
|
||||
check(f.Project(f.CornerPoint(2)).Equals({-1,1, nearD}));
|
||||
check(f.Project(f.CornerPoint(3)).Equals({-1,1, 1}));
|
||||
check(f.Project(f.CornerPoint(4)).Equals({1,-1, nearD}));
|
||||
check(f.Project(f.CornerPoint(5)).Equals({1,-1, 1}));
|
||||
check(f.Project(f.CornerPoint(6)).Equals({1,1, nearD}));
|
||||
check(f.Project(f.CornerPoint(7)).Equals({1,1, 1}));
|
||||
}
|
||||
});
|
||||
|
||||
TEST("Frustum::UnProject", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Type() == FrustumType::Perspective) {
|
||||
Ray r = f.UnProject(0, 0);
|
||||
check(r.Origin.Equals(f.Pos()));
|
||||
check(r.Origin.Equals({0,0,0}));
|
||||
check(r.Direction.Equals({0,0,-1}));
|
||||
FrustumUnit += Test("Frustum::UnProject", [] {
|
||||
Frustum f;
|
||||
FOR_EACH_FRUSTUM_CONVENTION(f)
|
||||
if (f.Type() == FrustumType::Perspective) {
|
||||
Ray r = f.UnProject(0, 0);
|
||||
check(r.Origin.Equals(f.Pos()));
|
||||
check(r.Origin.Equals({0,0,0}));
|
||||
check(r.Direction.Equals({0,0,-1}));
|
||||
|
||||
|
||||
r = f.UnProject(-1, -1);
|
||||
check(r.Origin.Equals(f.Pos()));
|
||||
check(r.Origin.Equals({0,0,0}));
|
||||
r = f.UnProject(-1, -1);
|
||||
check(r.Origin.Equals(f.Pos()));
|
||||
check(r.Origin.Equals({0,0,0}));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
FrustumUnit += Test("Frustum::UnProjectFromNearPlane", []{});
|
||||
|
||||
FrustumUnit += Test("Frustum::UnProjectFromNearPlane", []{});
|
||||
}
|
||||
|
||||
});
|
||||
inline void Run()
|
||||
{
|
||||
//FrustumUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
TEST("Frustum::UnProjectFromNearPlane", []{});
|
||||
|
||||
TEST("Frustum::UnProjectFromNearPlane", []{});
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/Geometry/Forward.hpp>
|
||||
#include <jtest/jtest.hpp>
|
||||
using J3ML::Geometry::Interval;
|
||||
|
||||
int CommonGeometryTests() {
|
||||
|
||||
TEST("Geometry::Interval_Intersect", [] {
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{0, 1}.Intersects({2, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({0, 1})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 4}.Intersects({3, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 4}.Intersects({1, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({3, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{3, 5}.Intersects({2, 3})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({2, 5})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 3}.Intersects({2, 3})));
|
||||
|
||||
// . a
|
||||
// . b
|
||||
jtest::check(!(Interval{2, 2}.Intersects({2, 2})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{2, 5}.Intersects({3, 4})));
|
||||
|
||||
// <- a ->
|
||||
// <- b ->
|
||||
jtest::check(!(Interval{3, 4}.Intersects({2, 5})));
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -7,4 +7,5 @@
|
||||
|
||||
/// @file OBBTests.hpp
|
||||
/// @desc Unit tests for the Oriented Bounding Box class.
|
||||
/// @edit 2024-07-23
|
||||
/// @edit 2024-07-23
|
||||
|
||||
|
@@ -1,94 +1,103 @@
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <J3ML/Geometry/Triangle.hpp>
|
||||
|
||||
using J3ML::Geometry::Interval;
|
||||
using J3ML::Geometry::Triangle;
|
||||
|
||||
int TriangleTests() {
|
||||
TEST("Triangle::FaceNormal", [] {
|
||||
Triangle t(
|
||||
{-1, -1, -1},
|
||||
{0, 1, 0},
|
||||
{1, -1, 1}
|
||||
);
|
||||
|
||||
jtest::check(t.FaceNormal() == Vector3{4, 0, -4});
|
||||
});
|
||||
|
||||
TEST("Triangle::IntersectTriangle", []
|
||||
jtest::Unit TriangleUnit {"Triangle"};
|
||||
namespace TriangleTests {
|
||||
inline void Define()
|
||||
{
|
||||
Triangle xyTriangle(
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 1.0f, 0.0f},
|
||||
{2.0f, 0.0f, 0.0f}
|
||||
);
|
||||
using namespace jtest;
|
||||
using J3ML::Geometry::Interval;
|
||||
using J3ML::Geometry::Triangle;
|
||||
|
||||
// Triangle collides with itself
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle));
|
||||
// Translate 1 towards x -- should collide
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(1.0f, 0.0f, 0.0f))));
|
||||
// Translate 2 towards x -- should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(2.0f, 0.0f, 0.0f))));
|
||||
// Translate 2 towards negative x -- should collide exactly on V0
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(-2.0f, 0.0f, 0.0f))));
|
||||
// Translate 3 towards x -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(3.0f, 0.0f, 0.0f))));
|
||||
// Translate 3 towards negative x -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(-3.0f, 0.0f, 0.0f))));
|
||||
// Translate 1 towards z -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
||||
// Triangle collides with contained smaller triangle
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Scaled(Vector3(0.5f, 0.5f, 0.5f)).Translated(Vector3(0.25f, 0.25f, 0.0f))));
|
||||
TriangleUnit += Test("FaceNormal", [] {
|
||||
Triangle t(
|
||||
{-1, -1, -1},
|
||||
{0, 1, 0},
|
||||
{1, -1, 1}
|
||||
);
|
||||
|
||||
Triangle zxTriangle (
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 0.0f, 1.0f},
|
||||
{0.0f, 0.0f, 2.0f}
|
||||
);
|
||||
jtest::check(t.FaceNormal() == Vector3{4, 0, -4});
|
||||
});
|
||||
|
||||
// Should collide exactly on V0
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle));
|
||||
// Should collide across xyTriangle's edge and zxTriangle's face
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -1.0))));
|
||||
// Should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -2.0))));
|
||||
// xyTriangle's face should be poked by zxTriangle's V0
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 0.0f))));
|
||||
// xyTriangle's face should be cut by zxTriangle
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, -0.5f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 1.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -3.0f))));
|
||||
TriangleUnit += Test("IntersectTriangle", []
|
||||
{
|
||||
Triangle xyTriangle(
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 1.0f, 0.0f},
|
||||
{2.0f, 0.0f, 0.0f}
|
||||
);
|
||||
|
||||
Triangle yxTriangle(
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 1.0f, 0.0f},
|
||||
{0.0f, 2.0f, 0.0f}
|
||||
);
|
||||
// Triangle collides with itself
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle));
|
||||
// Translate 1 towards x -- should collide
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(1.0f, 0.0f, 0.0f))));
|
||||
// Translate 2 towards x -- should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(2.0f, 0.0f, 0.0f))));
|
||||
// Translate 2 towards negative x -- should collide exactly on V0
|
||||
jtest::check(Intersects(xyTriangle, xyTriangle.Translated(Vector3(-2.0f, 0.0f, 0.0f))));
|
||||
// Translate 3 towards x -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(3.0f, 0.0f, 0.0f))));
|
||||
// Translate 3 towards negative x -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(-3.0f, 0.0f, 0.0f))));
|
||||
// Translate 1 towards z -- should not collide
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
||||
// Triangle collides with contained smaller triangle
|
||||
jtest::check(!Intersects(xyTriangle, xyTriangle.Scaled(Vector3(0.5f, 0.5f, 0.5f)).Translated(Vector3(0.25f, 0.25f, 0.0f))));
|
||||
|
||||
// Should collide on V0-V1 edge
|
||||
jtest::check(Intersects(yxTriangle, yxTriangle));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, yxTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(yxTriangle, yxTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
||||
Triangle zxTriangle (
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 0.0f, 1.0f},
|
||||
{0.0f, 0.0f, 2.0f}
|
||||
);
|
||||
|
||||
Triangle zyInvertedTriangle(
|
||||
{0.0f, 1.0f, -1.0f},
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 1.0f, 1.0f}
|
||||
);
|
||||
// Should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.25f, 0.75f, 0.0f))));
|
||||
});
|
||||
// Should collide exactly on V0
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle));
|
||||
// Should collide across xyTriangle's edge and zxTriangle's face
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -1.0))));
|
||||
// Should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -2.0))));
|
||||
// xyTriangle's face should be poked by zxTriangle's V0
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 0.0f))));
|
||||
// xyTriangle's face should be cut by zxTriangle
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, -0.5f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 1.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -3.0f))));
|
||||
|
||||
Triangle yxTriangle(
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{1.0f, 1.0f, 0.0f},
|
||||
{0.0f, 2.0f, 0.0f}
|
||||
);
|
||||
|
||||
return 0;
|
||||
// Should collide on V0-V1 edge
|
||||
jtest::check(Intersects(yxTriangle, yxTriangle));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, yxTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(yxTriangle, yxTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
||||
|
||||
Triangle zyInvertedTriangle(
|
||||
{0.0f, 1.0f, -1.0f},
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 1.0f, 1.0f}
|
||||
);
|
||||
// Should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||
// Should not collide
|
||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.25f, 0.75f, 0.0f))));
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run()
|
||||
{
|
||||
TriangleUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -2,6 +2,20 @@
|
||||
// Created by josh on 12/26/2023.
|
||||
//
|
||||
|
||||
int EulerAngleTests() {
|
||||
return 0;
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
jtest::Unit EulerAngleUnit {"EulerAngle"};
|
||||
|
||||
namespace EulerAngleTests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
|
||||
EulerAngleUnit += Test("Not Implemented", [] {
|
||||
throw("Not Implemented");
|
||||
});
|
||||
}
|
||||
inline void Run() {
|
||||
EulerAngleUnit.RunAll();
|
||||
}
|
||||
}
|
@@ -1,8 +1,19 @@
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix2x2.hpp>
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
jtest::Unit Matrix2x2Unit {"Matrix2x2"};
|
||||
namespace Matrix2x2Tests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
int Matrix2x2Tests() {
|
||||
return 0;
|
||||
Matrix2x2Unit += Test("Not Implemented", [] {
|
||||
throw("Not Implemented");
|
||||
});
|
||||
}
|
||||
inline void Run() {
|
||||
Matrix2x2Unit.RunAll();
|
||||
}
|
||||
}
|
@@ -1,96 +1,103 @@
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
// TODO: create RNG instance
|
||||
|
||||
int Matrix3x3Tests() {
|
||||
|
||||
|
||||
TEST("Mat3x3::Add_Unary", []
|
||||
jtest::Unit Matrix3x3Unit {"Matrix3x3"};
|
||||
namespace Matrix3x3Tests
|
||||
{
|
||||
inline void Define()
|
||||
{
|
||||
Matrix3x3 m(1,2,3, 4,5,6, 7,8,9);
|
||||
Matrix3x3 m2 = +m;
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
using namespace jtest;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
TEST("Mat3x3::Solve_Axb", []{
|
||||
RNG rng;
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
Vector3 b = Vector3::RandomBox(rng, Vector3::FromScalar(-10.f), Vector3::FromScalar(10.f));
|
||||
|
||||
Vector3 x;
|
||||
bool success = A.SolveAxb(b, x);
|
||||
jtest::check(success || mayFail);
|
||||
if (success)
|
||||
Matrix3x3Unit += Test("Add_Unary", []
|
||||
{
|
||||
Vector3 b2 = A*x;
|
||||
jtest::check(b2.Equals(b, 1e-1f));
|
||||
}
|
||||
});
|
||||
Matrix3x3 m(1,2,3, 4,5,6, 7,8,9);
|
||||
Matrix3x3 m2 = +m;
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
|
||||
TEST("Mat3x3::Inverse_Case", []
|
||||
{
|
||||
Matrix3x3 m(-8.75243664f,6.71196938f,-5.95816374f,6.81996822f,-6.85106039f,2.38949537f,-0.856015682f,3.45762491f,3.311584f);
|
||||
Matrix3x3Unit += Test("Solve_Axb", []{
|
||||
RNG rng;
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
bool success = m.Inverse();
|
||||
jtest::check(success);
|
||||
});
|
||||
Vector3 b = Vector3::RandomBox(rng, Vector3::FromScalar(-10.f), Vector3::FromScalar(10.f));
|
||||
|
||||
TEST("Mat3x3::Inverse", []
|
||||
{
|
||||
RNG rng;
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
Vector3 x;
|
||||
bool success = A.SolveAxb(b, x);
|
||||
jtest::check(success || mayFail);
|
||||
if (success)
|
||||
{
|
||||
Vector3 b2 = A*x;
|
||||
jtest::check(b2.Equals(b, 1e-1f));
|
||||
}
|
||||
});
|
||||
|
||||
Matrix3x3 A2 = A;
|
||||
bool success = A2.Inverse();
|
||||
jtest::check(success || mayFail);
|
||||
if (success)
|
||||
Matrix3x3Unit += Test("Inverse_Case", []
|
||||
{
|
||||
Matrix3x3 id = A * A2;
|
||||
Matrix3x3 id2 = A2 * A;
|
||||
jtest::check(id.Equals(Matrix3x3::Identity, 0.3f));
|
||||
jtest::check(id2.Equals(Matrix3x3::Identity, 0.3f));
|
||||
}
|
||||
});
|
||||
Matrix3x3 m(-8.75243664f,6.71196938f,-5.95816374f,6.81996822f,-6.85106039f,2.38949537f,-0.856015682f,3.45762491f,3.311584f);
|
||||
|
||||
bool success = m.Inverse();
|
||||
jtest::check(success);
|
||||
});
|
||||
|
||||
TEST("Mat3x3::InverseFast", []
|
||||
{
|
||||
// TODO: Fix implementation of InverseFast
|
||||
/*
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
Matrix3x3 A2 = A;
|
||||
bool success = A2.InverseFast();
|
||||
assert(success || mayFail);
|
||||
|
||||
if (success)
|
||||
Matrix3x3Unit += Test("Inverse", []
|
||||
{
|
||||
Matrix3x3 id = A * A2;
|
||||
Matrix3x3 id2 = A2 * A;
|
||||
assert(id.Equals(Matrix3x3::Identity, 0.3f));
|
||||
assert(id2.Equals(Matrix3x3::Identity, 0.3f));
|
||||
}
|
||||
*/
|
||||
});
|
||||
RNG rng;
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
TEST("Mat3x3::MulMat4x4", []
|
||||
Matrix3x3 A2 = A;
|
||||
bool success = A2.Inverse();
|
||||
jtest::check(success || mayFail);
|
||||
if (success)
|
||||
{
|
||||
Matrix3x3 id = A * A2;
|
||||
Matrix3x3 id2 = A2 * A;
|
||||
jtest::check(id.Equals(Matrix3x3::Identity, 0.3f));
|
||||
jtest::check(id2.Equals(Matrix3x3::Identity, 0.3f));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Matrix3x3Unit += Test("InverseFast", []
|
||||
{
|
||||
// TODO: Fix implementation of InverseFast
|
||||
/*
|
||||
Matrix3x3 A = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
Matrix3x3 A2 = A;
|
||||
bool success = A2.InverseFast();
|
||||
assert(success || mayFail);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Matrix3x3 id = A * A2;
|
||||
Matrix3x3 id2 = A2 * A;
|
||||
assert(id.Equals(Matrix3x3::Identity, 0.3f));
|
||||
assert(id2.Equals(Matrix3x3::Identity, 0.3f));
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
Matrix3x3Unit += Test("MulMat4x4", []
|
||||
{
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
Matrix4x4 m_ = m;
|
||||
Matrix4x4 m2 = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||
|
||||
Matrix4x4 test = m * m2;
|
||||
Matrix4x4 correct = m_ * m2;
|
||||
jtest::check(test.Equals(correct));
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run()
|
||||
{
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
Matrix4x4 m_ = m;
|
||||
Matrix4x4 m2 = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||
|
||||
Matrix4x4 test = m * m2;
|
||||
Matrix4x4 correct = m_ * m2;
|
||||
jtest::check(test.Equals(correct));
|
||||
});
|
||||
|
||||
return 0;
|
||||
Matrix3x3Unit.RunAll();
|
||||
}
|
||||
}
|
||||
|
@@ -1,129 +1,135 @@
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/Math.hpp>
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
jtest::Unit Matrix4x4Unit {"Matrix4x4"};
|
||||
namespace Matrix4x4Tests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using namespace J3ML::Math;
|
||||
|
||||
void Matrix4x4_AngleTypeRoundtripConversion()
|
||||
{
|
||||
Matrix4x4 matrix;
|
||||
EulerAngle a(Math::Radians(45), Math::Radians(45), Math::Radians(45));
|
||||
Quaternion q(a);
|
||||
matrix.SetRotatePart(q);
|
||||
//matrix.SetRotatePartX(a.pitch);
|
||||
//matrix.SetRotatePartY(a.yaw);
|
||||
//matrix.SetRotatePartZ(a.roll);
|
||||
EulerAngle fromMatrix = matrix.GetRotatePart().ToQuat().ToEulerAngle();
|
||||
jtest::check(a == fromMatrix);
|
||||
}
|
||||
|
||||
int Matrix4x4Tests() {
|
||||
|
||||
TEST("Mat4x4::Add_Unary", []
|
||||
{
|
||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2 = +m;
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
|
||||
TEST("Mat4x4::Inverse", [] {
|
||||
RNG rng;
|
||||
Matrix4x4 A = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
Matrix4x4 A2 = A;
|
||||
bool success = A2.Inverse();
|
||||
|
||||
jtest::check(success || mayFail);
|
||||
|
||||
if (success)
|
||||
Matrix4x4Unit += Test("Add_Unary", []
|
||||
{
|
||||
Matrix4x4 id = A * A2;
|
||||
Matrix4x4 id2 = A2 * A;
|
||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2 = +m;
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
|
||||
jtest::check(id.Equals(Matrix4x4::Identity, 0.3f));
|
||||
jtest::check(id2.Equals(Matrix4x4::Identity, 0.3f));
|
||||
}
|
||||
});
|
||||
Matrix4x4Unit += Test("Inverse", [] {
|
||||
RNG rng;
|
||||
Matrix4x4 A = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||
bool mayFail = Math::EqualAbs(A.Determinant(), 0.f, 1e-2f);
|
||||
|
||||
TEST("Mat4x4::Ctor", []{
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
Matrix4x4 A2 = A;
|
||||
bool success = A2.Inverse();
|
||||
|
||||
Matrix4x4 m2(m);
|
||||
jtest::check(success || mayFail);
|
||||
|
||||
for (int y = 0; y < 3; ++y)
|
||||
for (int x = 0; x < 3; ++x)
|
||||
assert(Math::EqualAbs(m.At(y, x), m2.At(y, x)));
|
||||
if (success)
|
||||
{
|
||||
Matrix4x4 id = A * A2;
|
||||
Matrix4x4 id2 = A2 * A;
|
||||
|
||||
jtest::check(Math::EqualAbs(m2[0][3], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[1][3], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[2][3], 0.f));
|
||||
jtest::check(id.Equals(Matrix4x4::Identity, 0.3f));
|
||||
jtest::check(id2.Equals(Matrix4x4::Identity, 0.3f));
|
||||
}
|
||||
});
|
||||
|
||||
jtest::check(Math::EqualAbs(m2[3][0], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][1], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][2], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][3], 0.f));
|
||||
});
|
||||
Matrix4x4Unit += Test("Ctor", []{
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
|
||||
TEST("Mat4x4::SetRow", []
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m.SetRow(0, 1,2,3,4);
|
||||
m.SetRow(1, Vector4(5,6,7,8));
|
||||
m.SetRow(2, 9,10,11,12);
|
||||
m.SetRow(3, 13, 14, 15, 16);
|
||||
Matrix4x4 m2(m);
|
||||
|
||||
for (int y = 0; y < 3; ++y)
|
||||
for (int x = 0; x < 3; ++x)
|
||||
assert(Math::EqualAbs(m.At(y, x), m2.At(y, x)));
|
||||
|
||||
jtest::check(Math::EqualAbs(m2[0][3], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[1][3], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[2][3], 0.f));
|
||||
|
||||
jtest::check(Math::EqualAbs(m2[3][0], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][1], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][2], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][3], 0.f));
|
||||
});
|
||||
|
||||
Matrix4x4Unit += Test("SetRow", []
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m.SetRow(0, 1,2,3,4);
|
||||
m.SetRow(1, Vector4(5,6,7,8));
|
||||
m.SetRow(2, 9,10,11,12);
|
||||
m.SetRow(3, 13, 14, 15, 16);
|
||||
|
||||
|
||||
Matrix4x4 m3(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2;
|
||||
m2.Set(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
jtest::check(m.Equals(m2));
|
||||
jtest::check(m.Equals(m3));
|
||||
});
|
||||
Matrix4x4 m3(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2;
|
||||
m2.Set(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
jtest::check(m.Equals(m2));
|
||||
jtest::check(m.Equals(m3));
|
||||
});
|
||||
|
||||
TEST("Mat4x4::SwapRows", []
|
||||
{
|
||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2(13,14,15,16, 9,10,11,12, 5,6,7,8, 1,2,3,4);
|
||||
m.SwapRows(0,3);
|
||||
m.SwapRows(1,2);
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
Matrix4x4Unit += Test("SwapRows", []
|
||||
{
|
||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||
Matrix4x4 m2(13,14,15,16, 9,10,11,12, 5,6,7,8, 1,2,3,4);
|
||||
m.SwapRows(0,3);
|
||||
m.SwapRows(1,2);
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
|
||||
TEST("Mat4x4::CtorCols", []
|
||||
{
|
||||
Matrix4x4 m(Vector4(1,2,3,4), Vector4(5,6,7,8), Vector4(9,10,11,12), Vector4(13,14,15,16));
|
||||
Matrix4x4 m2(1,5,9,13, 2,6,10,14, 3,7,11,15, 4,8,12,16);
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
Matrix4x4Unit += Test("CtorCols", []
|
||||
{
|
||||
Matrix4x4 m(Vector4(1,2,3,4), Vector4(5,6,7,8), Vector4(9,10,11,12), Vector4(13,14,15,16));
|
||||
Matrix4x4 m2(1,5,9,13, 2,6,10,14, 3,7,11,15, 4,8,12,16);
|
||||
jtest::check(m.Equals(m2));
|
||||
});
|
||||
|
||||
TEST("Mat4x4::CtorFromQuat", []
|
||||
{
|
||||
RNG rng;
|
||||
// TODO: Multiple random passes
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
Matrix4x4 m(q);
|
||||
Matrix4x4Unit += Test("CtorFromQuat", []
|
||||
{
|
||||
RNG rng;
|
||||
// TODO: Multiple random passes
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
Matrix4x4 m(q);
|
||||
|
||||
Vector3 v = Vector3(-1, 5, 20.f);
|
||||
Vector3 v1 = q * v;
|
||||
Vector3 v2 = m.Transform(v); //m.TransformPos(v);
|
||||
jtest::check(v1.Equals(v2));
|
||||
});
|
||||
Vector3 v = Vector3(-1, 5, 20.f);
|
||||
Vector3 v1 = q * v;
|
||||
Vector3 v2 = m.Transform(v); //m.TransformPos(v);
|
||||
jtest::check(v1.Equals(v2));
|
||||
});
|
||||
|
||||
|
||||
TEST("Mat4x4::CtorFromQuatTrans", [] {});
|
||||
TEST("Mat4x4::Translate", [] {});
|
||||
TEST("Mat4x4::Scale", [] {});
|
||||
TEST("Mat4x4::InverseOrthogonalUniformScale", [] {});
|
||||
TEST("Mat4x4::InverseOrthonormal", [] {});
|
||||
TEST("Mat4x4::DeterminantCorrectness", [] { });
|
||||
TEST("Mat4x4::MulMat3x3", [] {});
|
||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {});
|
||||
Matrix4x4Unit += Test("Translate", [] {});
|
||||
Matrix4x4Unit += Test("Scale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthogonalUniformScale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthonormal", [] {});
|
||||
Matrix4x4Unit += Test("DeterminantCorrectness", [] { });
|
||||
Matrix4x4Unit += Test("MulMat3x3", [] {});
|
||||
|
||||
|
||||
TEST("Mat4x4::AngleTypeRoundtripConversion", Matrix4x4_AngleTypeRoundtripConversion);
|
||||
Matrix4x4Unit += Test("AngleTypeRoundtripConversion", [] {
|
||||
Matrix4x4 matrix;
|
||||
EulerAngle a(Math::Radians(45), Math::Radians(45), Math::Radians(45));
|
||||
Quaternion q(a);
|
||||
matrix.SetRotatePart(q);
|
||||
//matrix.SetRotatePartX(a.pitch);
|
||||
//matrix.SetRotatePartY(a.yaw);
|
||||
//matrix.SetRotatePartZ(a.roll);
|
||||
EulerAngle fromMatrix = matrix.GetRotatePart().ToQuat().ToEulerAngle();
|
||||
jtest::check(a == fromMatrix);
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Run() {
|
||||
Matrix4x4Unit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,3 +149,4 @@ int Matrix4x4Tests() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,77 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
Quaternion PreciseSlerp(const Quaternion &a, const Quaternion& b, float t)
|
||||
{
|
||||
double angle = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
|
||||
double sign = 1.0;
|
||||
|
||||
if (angle > 0) {
|
||||
angle = -angle;
|
||||
sign = -1.0;
|
||||
}
|
||||
double A;
|
||||
double B;
|
||||
|
||||
if (angle <= 1.0) // perform spherical linear interpolation
|
||||
jtest::Unit QuaternionUnit {"Quaternion"};
|
||||
namespace QuaternionTests {
|
||||
Quaternion PreciseSlerp(const Quaternion &a, const Quaternion& b, float t)
|
||||
{
|
||||
angle = std::acos(angle); // After this, angle is in the range pi / 2 -> 0 as the original angle variable ranged from 0 -> 1.
|
||||
double angle = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
|
||||
double angleT = t * angle;
|
||||
double sign = 1.0;
|
||||
|
||||
double s[3] = { std::sin(angle), std::sin(angle - angleT), std::sin(angleT)};
|
||||
double c = 1.0 / s[0];
|
||||
if (angle > 0) {
|
||||
angle = -angle;
|
||||
sign = -1.0;
|
||||
}
|
||||
double A;
|
||||
double B;
|
||||
|
||||
A = s[1] * c;
|
||||
B = s[2] * c;
|
||||
} else { // If angle is close to taking the denominator to zero, resort to linear interpolation (and normalization).
|
||||
A = 1.0 - t;
|
||||
B = t;
|
||||
if (angle <= 1.0) // perform spherical linear interpolation
|
||||
{
|
||||
angle = std::acos(angle); // After this, angle is in the range pi / 2 -> 0 as the original angle variable ranged from 0 -> 1.
|
||||
|
||||
double angleT = t * angle;
|
||||
|
||||
double s[3] = { std::sin(angle), std::sin(angle - angleT), std::sin(angleT)};
|
||||
double c = 1.0 / s[0];
|
||||
|
||||
A = s[1] * c;
|
||||
B = s[2] * c;
|
||||
} else { // If angle is close to taking the denominator to zero, resort to linear interpolation (and normalization).
|
||||
A = 1.0 - t;
|
||||
B = t;
|
||||
}
|
||||
|
||||
Quaternion C;
|
||||
C.x = (float)(a.x*A*sign + b.x*B);
|
||||
C.y = (float)(a.y*A*sign + b.y*B);
|
||||
C.z = (float)(a.z*A*sign + b.z*B);
|
||||
C.w = (float)(a.w*A*sign + b.w*B);
|
||||
return C.Normalized();
|
||||
}
|
||||
|
||||
Quaternion C;
|
||||
C.x = (float)(a.x*A*sign + b.x*B);
|
||||
C.y = (float)(a.y*A*sign + b.y*B);
|
||||
C.z = (float)(a.z*A*sign + b.z*B);
|
||||
C.w = (float)(a.w*A*sign + b.w*B);
|
||||
return C.Normalized();
|
||||
}
|
||||
inline void Define()
|
||||
{
|
||||
using namespace jtest;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using J3ML::Algorithm::RNG;
|
||||
|
||||
QuaternionUnit += Test("SlerpPrecision", [] {
|
||||
RNG rng;
|
||||
float maxError = 0;
|
||||
float maxLerpError = 0;
|
||||
float magnitudeError = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
Quaternion q2 = Quaternion::RandomRotation(rng);
|
||||
float t = rng.Float01Incl();
|
||||
|
||||
int QuaternionTests()
|
||||
{
|
||||
Quaternion correct = PreciseSlerp(q, q2, t);
|
||||
Quaternion fast = q.Slerp(q2, t);
|
||||
|
||||
TEST("Quat::SlerpPrecision", [] {
|
||||
RNG rng;
|
||||
float maxError = 0;
|
||||
float maxLerpError = 0;
|
||||
float magnitudeError = 0;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
Quaternion q2 = Quaternion::RandomRotation(rng);
|
||||
float t = rng.Float01Incl();
|
||||
magnitudeError = std::max(magnitudeError, std::abs(1.f - fast.LengthSquared()));
|
||||
Quaternion lerp = q.Lerp(q2, t);
|
||||
}
|
||||
});
|
||||
QuaternionUnit += Test("Mat4x4Conversion", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("MulOpQuat", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("DivOpQuat", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("Lerp", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("RotateFromTo", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("Transform", [] { throw("Not Implemented"); });
|
||||
|
||||
Quaternion correct = PreciseSlerp(q, q2, t);
|
||||
Quaternion fast = q.Slerp(q2, t);
|
||||
}
|
||||
|
||||
magnitudeError = std::max(magnitudeError, std::abs(1.f - fast.LengthSquared()));
|
||||
Quaternion lerp = q.Lerp(q2, t);
|
||||
}
|
||||
});
|
||||
TEST("Quat::Mat4x4Conversion", [] {});
|
||||
TEST("Quat::MulOpQuat", [] {});
|
||||
TEST("Quat::DivOpQuat", [] {});
|
||||
TEST("Quat::Lerp", [] {});
|
||||
TEST("Quat::RotateFromTo", [] {});
|
||||
TEST("Quat::Transform", [] {});
|
||||
|
||||
return 0;
|
||||
inline void Run()
|
||||
{
|
||||
QuaternionUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,191 +1,201 @@
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
|
||||
int Vector2Tests()
|
||||
jtest::Unit Vector2Unit {"Vector2"};
|
||||
namespace Vector2Tests
|
||||
{
|
||||
TEST("Vector2::Ctor_Default", []
|
||||
inline void Define()
|
||||
{
|
||||
// TODO: implement check_eq
|
||||
jtest::check(Vector2() == Vector2::Zero);
|
||||
});
|
||||
using namespace jtest;
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
|
||||
TEST("Vector2::Ctor_XY", []
|
||||
Vector2Unit += Test("Ctor_Default", []
|
||||
{
|
||||
// TODO: implement check_eq
|
||||
jtest::check(Vector2() == Vector2::Zero);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Ctor_XY", []
|
||||
{
|
||||
Vector2 vec (1, 0);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(vec == Vector2::Right);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Addition_Op", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (3, 3);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(A+B == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Addition_Method", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (4, 4);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(A.Add(B) == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Addition_Static", []
|
||||
{
|
||||
Vector2 A (3, 3);
|
||||
Vector2 B (2, 2);
|
||||
|
||||
Vector2 C (5, 5);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(Vector2::Add(A, B) == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Subtract_Op", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(A-B == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Subtract_Method", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(A.Sub(B) == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Subtract_Static", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(Vector2::Sub(A, B) == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Scalar_Multiplication", []
|
||||
{
|
||||
Vector2 A (5, 1);
|
||||
float B = 0.5f;
|
||||
Vector2 C (2.5f, .5f);
|
||||
jtest::check(A*B == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Size", []
|
||||
{
|
||||
jtest::check(sizeof(Vector2) == 8);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("NaN", []
|
||||
{
|
||||
|
||||
jtest::check(Vector2::Zero != Vector2::NaN);
|
||||
jtest::check(Vector2::Up != Vector2::NaN);
|
||||
jtest::check(Vector2::Left != Vector2::NaN);
|
||||
jtest::check(Vector2::Down != Vector2::NaN);
|
||||
jtest::check(Vector2::Right != Vector2::NaN);
|
||||
jtest::check(Vector2::NaN != Vector2::NaN);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("MarginOfError", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check(A.IsWithinMarginOfError(B, 0.5f));
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Min", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check( Vector2::Min(A, B) == B);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Max", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check( Vector2::Max(A, B) == A);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Clamp", []
|
||||
{
|
||||
Vector2 Input (0, 20);
|
||||
|
||||
Vector2 Minimum ( 2, 2);
|
||||
Vector2 Maximum (16, 16);
|
||||
|
||||
Vector2 ExpectedResult (2, 16);
|
||||
|
||||
jtest::check(Input.Clamp(Minimum, Maximum) == ExpectedResult);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("DotProduct", []
|
||||
{
|
||||
|
||||
Vector2 A (2, 2);
|
||||
Vector2 B (1, 1);
|
||||
jtest::check(A.Dot(B) == 4.f);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Project", []
|
||||
{
|
||||
Vector2 Base (4, 4);
|
||||
Vector2 Projected (1, 0);
|
||||
|
||||
Vector2 ExpectedResult (4, 0);
|
||||
|
||||
jtest::check(Base.Project(Projected) == ExpectedResult);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Normalized", []
|
||||
{
|
||||
Vector2 A(2, 0);
|
||||
Vector2 B(1, 0);
|
||||
jtest::check(A.Normalized() == B);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("Lerp", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (10, 10);
|
||||
Vector2 C (6, 6);
|
||||
|
||||
jtest::check(A.Lerp(B, 0.f) == A);
|
||||
jtest::check(A.Lerp(B, 1.f) == B);
|
||||
jtest::check(A.Lerp(B, 0.5f) == C);
|
||||
});
|
||||
|
||||
Vector2Unit += Test("AngleBetween", []
|
||||
{
|
||||
Vector2 A (0.5f, 0.5);
|
||||
Vector2 B (0.5f, 0.1f);
|
||||
|
||||
A = A.Normalized();
|
||||
B = B.Normalized();
|
||||
|
||||
jtest::check_float_eq(A.AngleBetween(B), 0.58800244);
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run()
|
||||
{
|
||||
Vector2 vec (1, 0);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(vec == Vector2::Right);
|
||||
});
|
||||
|
||||
TEST("Vector2::Addition_Op", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (3, 3);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(A+B == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Addition_Method", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (4, 4);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(A.Add(B) == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Addition_Static", []
|
||||
{
|
||||
Vector2 A (3, 3);
|
||||
Vector2 B (2, 2);
|
||||
|
||||
Vector2 C (5, 5);
|
||||
// TODO: implement check_eq
|
||||
jtest::check(Vector2::Add(A, B) == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Subtract_Op", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(A-B == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Subtract_Method", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(A.Sub(B) == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Subtract_Static", []
|
||||
{
|
||||
Vector2 A (1,1);
|
||||
Vector2 B (2,2);
|
||||
|
||||
Vector2 C (-1, -1);
|
||||
|
||||
jtest::check(Vector2::Sub(A, B) == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Scalar_Multiplication", []
|
||||
{
|
||||
Vector2 A (5, 1);
|
||||
float B = 0.5f;
|
||||
Vector2 C (2.5f, .5f);
|
||||
jtest::check(A*B == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::Size", []
|
||||
{
|
||||
jtest::check(sizeof(Vector2) == 8);
|
||||
});
|
||||
|
||||
TEST("Vector2::NaN", []
|
||||
{
|
||||
|
||||
jtest::check(Vector2::Zero != Vector2::NaN);
|
||||
jtest::check(Vector2::Up != Vector2::NaN);
|
||||
jtest::check(Vector2::Left != Vector2::NaN);
|
||||
jtest::check(Vector2::Down != Vector2::NaN);
|
||||
jtest::check(Vector2::Right != Vector2::NaN);
|
||||
jtest::check(Vector2::NaN != Vector2::NaN);
|
||||
});
|
||||
|
||||
TEST("Vector2::MarginOfError", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check(A.IsWithinMarginOfError(B, 0.5f));
|
||||
});
|
||||
|
||||
TEST("Vector2::Min", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check( Vector2::Min(A, B) == B);
|
||||
});
|
||||
|
||||
TEST("Vector2::Max", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (1.85, 1.85);
|
||||
|
||||
jtest::check( Vector2::Max(A, B) == A);
|
||||
});
|
||||
|
||||
TEST("Vector2::Clamp", []
|
||||
{
|
||||
Vector2 Input (0, 20);
|
||||
|
||||
Vector2 Minimum ( 2, 2);
|
||||
Vector2 Maximum (16, 16);
|
||||
|
||||
Vector2 ExpectedResult (2, 16);
|
||||
|
||||
jtest::check(Input.Clamp(Minimum, Maximum) == ExpectedResult);
|
||||
});
|
||||
|
||||
TEST("Vector2::DotProduct", []
|
||||
{
|
||||
|
||||
Vector2 A (2, 2);
|
||||
Vector2 B (1, 1);
|
||||
jtest::check(A.Dot(B) == 4.f);
|
||||
});
|
||||
|
||||
TEST("Vector2::Project", []
|
||||
{
|
||||
Vector2 Base (4, 4);
|
||||
Vector2 Projected (1, 0);
|
||||
|
||||
Vector2 ExpectedResult (4, 0);
|
||||
|
||||
jtest::check(Base.Project(Projected) == ExpectedResult);
|
||||
});
|
||||
|
||||
TEST("Vector2::Normalized", []
|
||||
{
|
||||
Vector2 A(2, 0);
|
||||
Vector2 B(1, 0);
|
||||
jtest::check(A.Normalized() == B);
|
||||
});
|
||||
|
||||
TEST("Vector2::Lerp", []
|
||||
{
|
||||
Vector2 A (2,2);
|
||||
Vector2 B (10, 10);
|
||||
Vector2 C (6, 6);
|
||||
|
||||
jtest::check(A.Lerp(B, 0.f) == A);
|
||||
jtest::check(A.Lerp(B, 1.f) == B);
|
||||
jtest::check(A.Lerp(B, 0.5f) == C);
|
||||
});
|
||||
|
||||
TEST("Vector2::AngleBetween", []
|
||||
{
|
||||
Vector2 A (0.5f, 0.5);
|
||||
Vector2 B (0.5f, 0.1f);
|
||||
|
||||
A = A.Normalized();
|
||||
B = B.Normalized();
|
||||
|
||||
// TODO: AngleBetween returns not a number
|
||||
// TODO: implement jtest::check_float_eq
|
||||
jtest::check(A.AngleBetween(B) == 0.58800244);
|
||||
});
|
||||
|
||||
return 0;
|
||||
Vector2Unit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,206 +1,215 @@
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector3;
|
||||
|
||||
inline void EXPECT_V3_EQ(const Vector3& lhs, const Vector3& rhs)
|
||||
{
|
||||
jtest::check(lhs.x == rhs.x);
|
||||
jtest::check(lhs.y == rhs.y);
|
||||
jtest::check(lhs.z == rhs.z);
|
||||
}
|
||||
|
||||
int Vector3Tests() {
|
||||
TEST("Vector3::Ctor_Default", []
|
||||
jtest::Unit Vector3Unit {"Vector3"};
|
||||
namespace Vector3Tests {
|
||||
inline void EXPECT_V3_EQ(const Vector3& lhs, const Vector3& rhs)
|
||||
{
|
||||
EXPECT_V3_EQ(Vector3(), Vector3::Zero);
|
||||
});
|
||||
jtest::check(lhs.x == rhs.x);
|
||||
jtest::check(lhs.y == rhs.y);
|
||||
jtest::check(lhs.z == rhs.z);
|
||||
}
|
||||
|
||||
TEST("Vector3::Ctor_XYZ", []
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
using J3ML::LinearAlgebra::Vector3;
|
||||
|
||||
Vector3Unit += Test("Ctor_Default", []
|
||||
{
|
||||
EXPECT_V3_EQ(Vector3(), Vector3::Zero);
|
||||
});
|
||||
|
||||
Vector3Unit += Test("Ctor_XYZ", []
|
||||
{
|
||||
Vector3 Input (0, 1, 0);
|
||||
|
||||
EXPECT_V3_EQ(Input, Vector3::Down);
|
||||
});
|
||||
|
||||
Vector3Unit += Test("Addition_Op", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A + B, ExpectedResult);
|
||||
});
|
||||
|
||||
Vector3Unit += Test("Addition_Method", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A.Add(B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Addition_Static", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (3,3,3);
|
||||
|
||||
Vector3 ExpectedResult (4,4,4);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Add(A, B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Subtract_Op", [] {
|
||||
Vector3 A (2,2,2);
|
||||
Vector3 B (.5f, .5f, .5f);
|
||||
|
||||
Vector3 ExpectedResult (1.5f, 1.5f, 1.5f);
|
||||
|
||||
EXPECT_V3_EQ(A - B, ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Subtract_Method", [] {
|
||||
Vector3 A (3,3,3);
|
||||
Vector3 B (1,1,1);
|
||||
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
|
||||
EXPECT_V3_EQ(A.Sub(B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("V3_Subtract_Static", [] {
|
||||
Vector3 A (4,4,4);
|
||||
Vector3 B (1,1,1);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Sub(A, B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Mult_Op", [] {
|
||||
Vector3 A ( 1,1,1);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (1.5f, 1.5f, 1.5f);
|
||||
|
||||
EXPECT_V3_EQ(A * B, ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Mult_Method", [] {
|
||||
Vector3 A (3,3,3);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (4.5f, 4.5f, 4.5f);
|
||||
|
||||
EXPECT_V3_EQ(A.Mul(B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Mult_Static", [] {
|
||||
Vector3 A (2,2,2);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (3.f, 3.f, 3.f);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Mul(A, B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Div_Op", [] {
|
||||
Vector3 A (4,4,4);
|
||||
float B = 2.f;
|
||||
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
EXPECT_V3_EQ(A / B, ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Div_Method", [] {
|
||||
Vector3 A (6,6,6);
|
||||
float B = 2.f;
|
||||
Vector3 ExpectedResult ( 3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A.Div(B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Scalar_Div_Static", [] {
|
||||
Vector3 A (3,3,3);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult ( 2.f, 2.f, 2.f);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Div(A, B), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Sizeof", [] {
|
||||
jtest::check(sizeof(Vector3) == 12);
|
||||
});
|
||||
Vector3Unit += Test("NaN", [] {
|
||||
jtest::check(Vector3(0, 0, 0) != Vector3::NaN);
|
||||
|
||||
});
|
||||
Vector3Unit += Test("Min", [] {
|
||||
Vector3 Input (2,2,2);
|
||||
Vector3 Minimum (3,3,3);
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
|
||||
EXPECT_V3_EQ(Input.Min(Minimum), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Max", [] {
|
||||
Vector3 Input (2,2,2);
|
||||
Vector3 Maximum (3,3,3);
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(Input.Max(Maximum), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Clamp", [] {
|
||||
Vector3 Input (5,-1,8);
|
||||
Vector3 Minimum (1,1,1);
|
||||
Vector3 Maximum (5,5,5);
|
||||
|
||||
Vector3 ExpectedResult (5,1,5);
|
||||
|
||||
EXPECT_V3_EQ(Input.Clamp(Minimum, Maximum), ExpectedResult);
|
||||
|
||||
});
|
||||
Vector3Unit += Test("DotProduct", [] {
|
||||
Vector3 A(6,6,6);
|
||||
Vector3 B(1,1,1);
|
||||
|
||||
|
||||
float ExpectedResult = 18;
|
||||
|
||||
// TODO: Add check_float_eq
|
||||
jtest::check(A.Dot(B) == ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("CrossProduct", [] {
|
||||
Vector3 A(1,1,1);
|
||||
Vector3 B(2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (0,0,0);
|
||||
|
||||
EXPECT_V3_EQ(A.Cross(B), ExpectedResult);
|
||||
|
||||
});
|
||||
Vector3Unit += Test("Project", [] {
|
||||
Vector3 Base;
|
||||
Vector3 Projection;
|
||||
Vector3 ExpectedResult;
|
||||
});
|
||||
Vector3Unit += Test("Normalized", [] {
|
||||
Vector3 Input (2, 0, 0);
|
||||
Vector3 ExpectedResult (1, 0, 0);
|
||||
|
||||
EXPECT_V3_EQ(Input.Normalized(), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("Lerp", []
|
||||
{
|
||||
Vector3 Start;
|
||||
Vector3 Finish;
|
||||
float Percent = 50;
|
||||
Vector3 ExpectedResult;
|
||||
EXPECT_V3_EQ(Start.Lerp(Finish, Percent), ExpectedResult);
|
||||
});
|
||||
Vector3Unit += Test("AngleBetween", [] {
|
||||
using J3ML::LinearAlgebra::Angle2D;
|
||||
Vector3 A ( .5f, .5f, .5f);
|
||||
Vector3 B (.25f, .75f, .25f);
|
||||
A = A.Normalized();
|
||||
B = B.Normalized();
|
||||
Angle2D ExpectedResult (-0.69791365, -2.3561945);
|
||||
//std::cout << A.AngleBetween(B).x << ", " << A.AngleBetween(B).y << "";
|
||||
auto angle = A.AngleBetween(B);
|
||||
|
||||
jtest::check(angle.x == ExpectedResult.x);
|
||||
jtest::check(angle.y == ExpectedResult.y);
|
||||
});
|
||||
}
|
||||
|
||||
inline void Run()
|
||||
{
|
||||
Vector3 Input (0, 1, 0);
|
||||
|
||||
EXPECT_V3_EQ(Input, Vector3::Down);
|
||||
});
|
||||
|
||||
TEST("Vector3::Addition_Op", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A + B, ExpectedResult);
|
||||
});
|
||||
|
||||
TEST("Vector3::Addition_Method", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A.Add(B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Addition_Static", [] {
|
||||
Vector3 A (1,1,1);
|
||||
Vector3 B (3,3,3);
|
||||
|
||||
Vector3 ExpectedResult (4,4,4);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Add(A, B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Subtract_Op", [] {
|
||||
Vector3 A (2,2,2);
|
||||
Vector3 B (.5f, .5f, .5f);
|
||||
|
||||
Vector3 ExpectedResult (1.5f, 1.5f, 1.5f);
|
||||
|
||||
EXPECT_V3_EQ(A - B, ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Subtract_Method", [] {
|
||||
Vector3 A (3,3,3);
|
||||
Vector3 B (1,1,1);
|
||||
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
|
||||
EXPECT_V3_EQ(A.Sub(B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3Test, V3_Subtract_Static", [] {
|
||||
Vector3 A (4,4,4);
|
||||
Vector3 B (1,1,1);
|
||||
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Sub(A, B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Mult_Op", [] {
|
||||
Vector3 A ( 1,1,1);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (1.5f, 1.5f, 1.5f);
|
||||
|
||||
EXPECT_V3_EQ(A * B, ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Mult_Method", [] {
|
||||
Vector3 A (3,3,3);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (4.5f, 4.5f, 4.5f);
|
||||
|
||||
EXPECT_V3_EQ(A.Mul(B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Mult_Static", [] {
|
||||
Vector3 A (2,2,2);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult (3.f, 3.f, 3.f);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Mul(A, B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Div_Op", [] {
|
||||
Vector3 A (4,4,4);
|
||||
float B = 2.f;
|
||||
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
EXPECT_V3_EQ(A / B, ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Div_Method", [] {
|
||||
Vector3 A (6,6,6);
|
||||
float B = 2.f;
|
||||
Vector3 ExpectedResult ( 3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(A.Div(B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Scalar_Div_Static", [] {
|
||||
Vector3 A (3,3,3);
|
||||
float B = 1.5f;
|
||||
|
||||
Vector3 ExpectedResult ( 2.f, 2.f, 2.f);
|
||||
|
||||
EXPECT_V3_EQ(Vector3::Div(A, B), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Sizeof", [] {
|
||||
jtest::check(sizeof(Vector3) == 12);
|
||||
});
|
||||
TEST("Vector3::NaN", [] {
|
||||
jtest::check(Vector3(0, 0, 0) != Vector3::NaN);
|
||||
|
||||
});
|
||||
TEST("Vector3::Min", [] {
|
||||
Vector3 Input (2,2,2);
|
||||
Vector3 Minimum (3,3,3);
|
||||
Vector3 ExpectedResult (2,2,2);
|
||||
|
||||
EXPECT_V3_EQ(Input.Min(Minimum), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Max", [] {
|
||||
Vector3 Input (2,2,2);
|
||||
Vector3 Maximum (3,3,3);
|
||||
Vector3 ExpectedResult (3,3,3);
|
||||
|
||||
EXPECT_V3_EQ(Input.Max(Maximum), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Clamp", [] {
|
||||
Vector3 Input (5,-1,8);
|
||||
Vector3 Minimum (1,1,1);
|
||||
Vector3 Maximum (5,5,5);
|
||||
|
||||
Vector3 ExpectedResult (5,1,5);
|
||||
|
||||
EXPECT_V3_EQ(Input.Clamp(Minimum, Maximum), ExpectedResult);
|
||||
|
||||
});
|
||||
TEST("Vector3::DotProduct", [] {
|
||||
Vector3 A(6,6,6);
|
||||
Vector3 B(1,1,1);
|
||||
|
||||
|
||||
float ExpectedResult = 18;
|
||||
|
||||
// TODO: Add check_float_eq
|
||||
jtest::check(A.Dot(B) == ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::CrossProduct", [] {
|
||||
Vector3 A(1,1,1);
|
||||
Vector3 B(2,2,2);
|
||||
|
||||
Vector3 ExpectedResult (0,0,0);
|
||||
|
||||
EXPECT_V3_EQ(A.Cross(B), ExpectedResult);
|
||||
|
||||
});
|
||||
TEST("Vector3::Project", [] {
|
||||
Vector3 Base;
|
||||
Vector3 Projection;
|
||||
Vector3 ExpectedResult;
|
||||
});
|
||||
TEST("Vector3::Normalized", [] {
|
||||
Vector3 Input (2, 0, 0);
|
||||
Vector3 ExpectedResult (1, 0, 0);
|
||||
|
||||
EXPECT_V3_EQ(Input.Normalized(), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::Lerp", []
|
||||
{
|
||||
Vector3 Start;
|
||||
Vector3 Finish;
|
||||
float Percent = 50;
|
||||
Vector3 ExpectedResult;
|
||||
EXPECT_V3_EQ(Start.Lerp(Finish, Percent), ExpectedResult);
|
||||
});
|
||||
TEST("Vector3::AngleBetween", [] {
|
||||
using J3ML::LinearAlgebra::Angle2D;
|
||||
Vector3 A ( .5f, .5f, .5f);
|
||||
Vector3 B (.25f, .75f, .25f);
|
||||
A = A.Normalized();
|
||||
B = B.Normalized();
|
||||
Angle2D ExpectedResult (-0.69791365, -2.3561945);
|
||||
//std::cout << A.AngleBetween(B).x << ", " << A.AngleBetween(B).y << "";
|
||||
auto angle = A.AngleBetween(B);
|
||||
|
||||
jtest::check(angle.x == ExpectedResult.x);
|
||||
jtest::check(angle.y == ExpectedResult.y);
|
||||
});
|
||||
return 0;
|
||||
Vector3Unit.RunAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -13,71 +13,80 @@
|
||||
#pragma once
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include "J3ML/J3ML.hpp"
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/J3ML.hpp>
|
||||
|
||||
inline void MathFuncTests()
|
||||
jtest::Unit MathUnit {"Math"};
|
||||
namespace MathTests
|
||||
{
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Math;
|
||||
inline void Define()
|
||||
{
|
||||
using namespace jtest;
|
||||
using namespace J3ML::Math;
|
||||
using namespace J3ML;
|
||||
|
||||
TEST("Math::IsFinite", [] {
|
||||
check(IsFinite<u32>(420));
|
||||
check(IsFinite<u64>(25));
|
||||
check(IsFinite(5.f));
|
||||
check(IsFinite(5.0));
|
||||
check(!IsFinite(Infinity));
|
||||
check(!IsFinite(NotANumber));
|
||||
});
|
||||
MathUnit += Test("IsFinite", [] {
|
||||
check(IsFinite<u32>(420));
|
||||
check(IsFinite<u64>(25));
|
||||
check(IsFinite(5.f));
|
||||
check(IsFinite(5.0));
|
||||
check(!IsFinite(Infinity));
|
||||
check(!IsFinite(NotANumber));
|
||||
});
|
||||
|
||||
TEST("Math::IsNotANumber", [] {
|
||||
check(!IsNotANumber(5.f));
|
||||
check(!IsNotANumber(5.0));
|
||||
check(IsNotANumber(NotANumber));
|
||||
check(!IsNotANumber(Infinity));
|
||||
});
|
||||
MathUnit += Test("IsNotANumber", [] {
|
||||
check(!IsNotANumber(5.f));
|
||||
check(!IsNotANumber(5.0));
|
||||
check(IsNotANumber(NotANumber));
|
||||
check(!IsNotANumber(Infinity));
|
||||
});
|
||||
|
||||
TEST("Math::IsInfinite", [] {
|
||||
check(!IsInfinite(5.f));
|
||||
check(!IsInfinite(5.0));
|
||||
check(IsInfinite(Infinity));
|
||||
});
|
||||
MathUnit += Test("IsInfinite", [] {
|
||||
check(!IsInfinite(5.f));
|
||||
check(!IsInfinite(5.0));
|
||||
check(IsInfinite(Infinity));
|
||||
});
|
||||
|
||||
TEST("Math::ReinterpretAsU32", [] {
|
||||
check(ReinterpretAs<u32>(0.f) == 0x00000000);
|
||||
check(ReinterpretAs<u32>(1.f) == 0x3F800000);
|
||||
check(ReinterpretAs<u32>(2.f) == 0x40000000);
|
||||
check(ReinterpretAs<u32>(-1.f) == 0xBF800000);
|
||||
check(ReinterpretAs<u32>(Infinity) == 0x7F800000);
|
||||
});
|
||||
MathUnit += Test("ReinterpretAsU32", [] {
|
||||
check(ReinterpretAs<u32>(0.f) == 0x00000000);
|
||||
check(ReinterpretAs<u32>(1.f) == 0x3F800000);
|
||||
check(ReinterpretAs<u32>(2.f) == 0x40000000);
|
||||
check(ReinterpretAs<u32>(-1.f) == 0xBF800000);
|
||||
check(ReinterpretAs<u32>(Infinity) == 0x7F800000);
|
||||
});
|
||||
|
||||
TEST("Math::ReinterpretAsFloat", [] {
|
||||
check(ReinterpretAs<float, u32>(0x00000000) == 0.f);
|
||||
check(ReinterpretAs<float, u32>(0x3F800000) == 1.f);
|
||||
check(ReinterpretAs<float, u32>(0x40000000) == 2.f);
|
||||
check(ReinterpretAs<float, u32>(0xBF800000) == -1.f);
|
||||
check(ReinterpretAs<float>(0x7F800000) == Infinity);
|
||||
check(IsNotANumber(ReinterpretAs<float>(0x7F800001)));
|
||||
});
|
||||
MathUnit += Test("ReinterpretAsFloat", [] {
|
||||
check(ReinterpretAs<float, u32>(0x00000000) == 0.f);
|
||||
check(ReinterpretAs<float, u32>(0x3F800000) == 1.f);
|
||||
check(ReinterpretAs<float, u32>(0x40000000) == 2.f);
|
||||
check(ReinterpretAs<float, u32>(0xBF800000) == -1.f);
|
||||
check(ReinterpretAs<float>(0x7F800000) == Infinity);
|
||||
check(IsNotANumber(ReinterpretAs<float>(0x7F800001)));
|
||||
});
|
||||
|
||||
TEST("Math::SqrtVals", [] {
|
||||
MathUnit += Test("SqrtVals", [] {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Math::SqrtPrecision", [] {
|
||||
MathUnit += Test("SqrtPrecision", [] {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Math::SqrtRSqrtPrecision", [] {
|
||||
MathUnit += Test("SqrtRSqrtPrecision", [] {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Math::SqrtRecipPrecision", [] {
|
||||
MathUnit += Test("SqrtRecipPrecision", [] {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
TEST("Math::Min", [] {});
|
||||
TEST("Math::Max", [] {});
|
||||
TEST("Math::IsPow2", [] {});
|
||||
MathUnit += Test("Min", [] {});
|
||||
MathUnit += Test("Max", [] {});
|
||||
MathUnit += Test("IsPow2", [] {});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
inline void Run()
|
||||
{
|
||||
MathUnit.RunAll();
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
|
||||
#include "Algorithm/RNGTests.hpp"
|
||||
#include "Geometry/Geometry.hpp"
|
||||
#include "Geometry/CommonGeometryTests.hpp"
|
||||
#include "Geometry/TriangleTests.hpp"
|
||||
#include "Geometry/AABBTests.hpp"
|
||||
#include "Geometry/FrustumTests.hpp"
|
||||
|
Reference in New Issue
Block a user