[WIP] tests transform it into BDD Style

This commit is contained in:
NADAL Jean-Baptiste
2024-02-13 18:41:42 +01:00
parent c3d3a85f08
commit bac26441c5
6 changed files with 1635 additions and 731 deletions

View File

@@ -35,318 +35,594 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] a tuple with w=1.0 is a point", "[Tuple]")
SCENARIO("A tuple with w=1.0 is a point", "[features/tuples.feature]")
{
Tuple a(4.3, -4.2, 3.1, 1.0);
REQUIRE(a.x() == 4.3);
REQUIRE(a.y() == -4.2);
REQUIRE(a.z() == 3.1);
REQUIRE(a.w() == 1.0);
REQUIRE(a.is_point() == true);
REQUIRE(a.is_vector() == false);
GIVEN("A tuple with w=1.0 is a point")
{
Tuple a(4.3, -4.2, 3.1, 1.0);
THEN("a.x = 4.3")
{
REQUIRE(a.x() == 4.3);
}
AND_THEN("a.y = -4.2")
{
REQUIRE(a.y() == -4.2);
}
AND_THEN("a.z = 3.1")
{
REQUIRE(a.z() == 3.1);
}
AND_THEN("a.w = 1.0")
{
REQUIRE(a.w() == 1.0);
}
AND_THEN("a is a point")
{
REQUIRE(a.is_point() == true);
}
AND_THEN("a is not a vector")
{
REQUIRE(a.is_vector() == false);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] a tuple with w=0 is a vector", "[Tuple]")
SCENARIO("A tuple with w=0 is a vector", "[features/tuples.feature]")
{
Tuple a(4.3, -4.2, 3.1, 0.0);
REQUIRE(a.x() == 4.3);
REQUIRE(a.y() == -4.2);
REQUIRE(a.z() == 3.1);
REQUIRE(a.w() == 0.0);
REQUIRE(a.is_point() == false);
GIVEN("a <-tuple(4.3, -4.2, 3.1, 0.0)")
{
Tuple a(4.3, -4.2, 3.1, 0.0);
THEN("a.x = 4.3")
{
REQUIRE(a.x() == 4.3);
}
AND_THEN("a.y = -4.2")
{
REQUIRE(a.y() == -4.2);
}
AND_THEN("a.z = 3.1")
{
REQUIRE(a.z() == 3.1);
}
AND_THEN("a.w = 0.0")
{
REQUIRE(a.w() == 0.0);
}
AND_THEN("a is not a point")
{
REQUIRE(a.is_point() == false);
}
AND_THEN("a is a vector")
{
REQUIRE(a.is_vector() == true);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] access of data with []", "[Tuple]")
SCENARIO("Access of data with []", "[features/tuples.feature]")
{
Tuple a(4.3, -4.2, 3.1, 0.0);
REQUIRE(a[0] == 4.3);
REQUIRE(a[1] == -4.2);
REQUIRE(a[2] == 3.1);
REQUIRE(a[3] == 0.0);
GIVEN(" a <- tuple(4.3, -4.2, 3.1, 0.0)")
{
Tuple a(4.3, -4.2, 3.1, 0.0);
THEN("a[0] = 4.3")
{
REQUIRE(a[0] == 4.3);
}
AND_THEN("a[1] = -4.2")
{
REQUIRE(a[1] == -4.2);
}
AND_THEN("a[2] = 3.1")
{
REQUIRE(a[2] == 3.1);
}
AND_THEN("a[3] = 0.0")
{
REQUIRE(a[3] == 0.0);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] constructor with std::vector", "[Tuple]")
SCENARIO("A constructor with std::vector", "[features/tuples.feature]")
{
std::vector<double> v = {4.3, -4.2, 3.1, 0.0};
Tuple a(v);
GIVEN(" a <- tuple with {4.3, -4.2, 3.1, 0.0}")
{
std::vector<double> v = {4.3, -4.2, 3.1, 0.0};
Tuple a(v);
REQUIRE(a[0] == 4.3);
REQUIRE(a[1] == -4.2);
REQUIRE(a[2] == 3.1);
REQUIRE(a[3] == 0.0);
THEN("a[0] = 4.3")
{
REQUIRE(a[0] == 4.3);
}
AND_THEN("a[1] = -4.2")
{
REQUIRE(a[1] == -4.2);
}
AND_THEN("a[2] = 3.1")
{
REQUIRE(a[2] == 3.1);
}
AND_THEN("a[3] = 0.0")
{
REQUIRE(a[3] == 0.0);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] test copy constructor", "[Tuple]")
SCENARIO("A test copy constructor", "[features/tuples.feature]")
{
Tuple a;
Tuple b(4.3, -4.2, 3.1, 0.0);
a = b;
REQUIRE(a[0] == 4.3);
REQUIRE(a[1] == -4.2);
REQUIRE(a[2] == 3.1);
REQUIRE(a[3] == 0.0);
GIVEN(" a <- tuple(4.3, -4.2, 3.1, 0.0)")
{
Tuple a(4.3, -4.2, 3.1, 0.0);
AND_GIVEN(" b <- tuple")
{
Tuple b;
WHEN("b = a")
{
b = a;
THEN("b[0] = 4.3")
{
REQUIRE(b[0] == 4.3);
}
AND_THEN("b[1] = -4.2")
{
REQUIRE(b[1] == -4.2);
}
AND_THEN("b[2] = 3.1")
{
REQUIRE(b[2] == 3.1);
}
AND_THEN("b[3] = 0.0")
{
REQUIRE(b[3] == 0.0);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Tuple could be copy", "[Tuple]")
SCENARIO("Tuple could be copy", "[features/tuples.feature]")
{
Tuple p = Tuple::Point(4, -4, 3);
Tuple n;
n = p;
REQUIRE(n == p);
GIVEN("p <-point(4, -4, 3)")
{
Tuple p = Tuple::Point(4, -4, 3);
Tuple n;
WHEN("n <- p")
{
n = p;
THEN(" n = p")
{
REQUIRE(n == p);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Point() creates tuples with w=1", "[Tuple][Point]")
SCENARIO("Point() creates tuples with w=1", "[features/tuples.feature]")
{
Tuple p = Tuple::Point(4, -4, 3);
REQUIRE(p == Tuple(4, -4, 3, 1));
GIVEN("p <-point(4, -4, 3)")
{
Tuple p = Tuple::Point(4, -4, 3);
THEN("p = tuple(4,-4, 3, 1)")
{
REQUIRE(p == Tuple(4, -4, 3, 1));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Vector() creates tuples with w=0", "[Tuple][Vector]")
SCENARIO("Vector() creates tuples with w=0", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(4, -4, 3);
REQUIRE(v == Tuple(4, -4, 3, 0));
GIVEN("v <-vector(4, -4, 3)")
{
Tuple v = Tuple::Vector(4, -4, 3);
THEN("v = tuple(4,-4, 3, 1)")
{
REQUIRE(v == Tuple(4, -4, 3, 0));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Adding two tuples", "[Tuple][Operations]")
SCENARIO("Adding two tuples", "[features/tuples.feature]")
{
Tuple a1(3, -2, 5, 1);
Tuple a2(-2, 3, 1, 0);
REQUIRE((a1 + a2) == Tuple(1, 1, 6, 1));
GIVEN("a1 <-tuple(3, -2, 5, 1)")
{
Tuple a1(3, -2, 5, 1);
AND_GIVEN("a2 <- tuple(-2, 3, 1, 0)")
{
Tuple a2(-2, 3, 1, 0);
THEN("a1 + a2 = tuple(1, 1, 6, 1)")
{
REQUIRE((a1 + a2) == Tuple(1, 1, 6, 1));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Adding two tuples without modify a1", "[Tuple][Operations]")
SCENARIO("Adding two tuples without modify a1", "[features/tuples.feature]")
{
Tuple a1(3, -2, 5, 1);
Tuple a2(-2, 3, 1, 0);
Tuple a3 = a1 + a2;
REQUIRE((a1 + a2) == Tuple(1, 1, 6, 1));
GIVEN("a1 <-tuple(3, -2, 5, 1)")
{
Tuple a1(3, -2, 5, 1);
AND_GIVEN("a2 <- tuple(-2, 3, 1, 0)")
{
Tuple a2(-2, 3, 1, 0);
WHEN("a3 = a1 + a2")
{
Tuple a3 = a1 + a2;
THEN("a1 + a2 = tuple(1, 1, 6, 1)")
{
REQUIRE((a1 + a2) == Tuple(1, 1, 6, 1));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Subtracting two points", "[Tuple][Operations]")
SCENARIO("Subtracting two points", "[features/tuples.feature]")
{
Tuple p1 = Tuple::Point(3, 2, 1);
Tuple p2 = Tuple::Point(5, 6, 7);
REQUIRE((p1 - p2) == Tuple::Vector(-2, -4, -6));
GIVEN("p1 <- point(3, 2, 1)")
{
Tuple p1 = Tuple::Point(3, 2, 1);
AND_GIVEN("p2 <- point(5, 6, 7)")
{
Tuple p2 = Tuple::Point(5, 6, 7);
THEN("p1 - p2 = vector(-2, -4, -6)")
{
REQUIRE((p1 - p2) == Tuple::Vector(-2, -4, -6));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Subtracting two points without modify p1", "[Tuple][Operations]")
SCENARIO("Subtracting two points without modify p1", "[features/tuples.feature]")
{
Tuple p1 = Tuple::Point(3, 2, 1);
Tuple p2 = Tuple::Point(5, 6, 7);
GIVEN("p1 <- point(3, 2, 1)")
{
Tuple p1 = Tuple::Point(3, 2, 1);
AND_GIVEN("p2 <- point(5, 6, 7)")
{
Tuple p2 = Tuple::Point(5, 6, 7);
Tuple p3 = p1 - p2;
REQUIRE((p1 - p2) == Tuple::Vector(-2, -4, -6));
WHEN("p3 = p1 - p2")
{
Tuple p3 = p1 - p2;
THEN("(p1 - p2) = vector(-2, -4, -6)")
{
REQUIRE((p1 - p2) == Tuple::Vector(-2, -4, -6));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Subtracting a vector from a point", "[Tuple][Operations]")
SCENARIO("Subtracting a vector from a point", "[features/tuples.feature]")
{
Tuple p = Tuple::Point(3, 2, 1);
Tuple v = Tuple::Vector(5, 6, 7);
GIVEN("p <- point(3, 2, 1)")
{
Tuple p = Tuple::Point(3, 2, 1);
REQUIRE((p - v) == Tuple::Point(-2, -4, -6));
AND_GIVEN("v <-vector(5, 6, 7)")
{
Tuple v = Tuple::Vector(5, 6, 7);
THEN("p - v = point(-2, -4, -6)")
{
REQUIRE((p - v) == Tuple::Point(-2, -4, -6));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Subtracting two vectors", "[Tuple][Operations]")
SCENARIO("Subtracting two vectors", "[features/tuples.feature]")
{
Tuple v1 = Tuple::Vector(3, 2, 1);
Tuple v2 = Tuple::Vector(5, 6, 7);
REQUIRE((v1 - v2) == Tuple::Vector(-2, -4, -6));
GIVEN("v1 <-vector(3, 2, 1)")
{
Tuple v1 = Tuple::Vector(3, 2, 1);
AND_GIVEN("v2 <-vector(5, 6, 7)")
{
Tuple v2 = Tuple::Vector(5, 6, 7);
THEN("v1 - v2 = vector(-2, -4, -6)")
{
REQUIRE((v1 - v2) == Tuple::Vector(-2, -4, -6));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Subtracting a vector from the zero vector", "[Tuple][Operations]")
SCENARIO("Subtracting a vector from the zero vector", "[features/tuples.feature]")
{
Tuple zero = Tuple::Vector(0, 0, 0);
Tuple v = Tuple::Vector(1, -2, 3);
REQUIRE((zero - v) == Tuple::Vector(-1, 2, -3));
GIVEN("zero <-vector(0, 0, 0)")
{
Tuple zero = Tuple::Vector(0, 0, 0);
AND_GIVEN("v <-vector(1, -2, 3)")
{
Tuple v = Tuple::Vector(1, -2, 3);
THEN("zero - v = vector(-1, 2, -3)")
{
REQUIRE((zero - v) == Tuple::Vector(-1, 2, -3));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Negative a tuple", "[Tuple][Operations]")
SCENARIO("Negative a tuple", "[features/tuples.feature]")
{
Tuple a(1, -2, 3, -4);
REQUIRE(-a == Tuple(-1, 2, -3, 4));
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
THEN("-a = tuple(-1, 2, -3, 4)")
{
REQUIRE(-a == Tuple(-1, 2, -3, 4));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Multiplying a tuple by a scalar", "[Tuple][Multiplication]")
SCENARIO("Multiplying a tuple by a scalar", "[features/tuples.feature]")
{
Tuple a(1, -2, 3, -4);
REQUIRE(a * 3.5 == Tuple(3.5, -7, 10.5, -14));
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
THEN("a * 3.5 = tuple(3.5, -7, 10.5, -14)")
{
REQUIRE(a * 3.5 == Tuple(3.5, -7, 10.5, -14));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Multiplying a tuple by a scalar without modify a", "[Tuple][Multiplication]")
SCENARIO("Multiplying a tuple by a scalar without modify a", "[features/tuples.feature]")
{
Tuple a(1, -2, 3, -4);
Tuple b = a * 3.5;
REQUIRE(a * 3.5 == Tuple(3.5, -7, 10.5, -14));
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
WHEN("b = a * 3.5;")
{
Tuple b = a * 3.5;
THEN("a * 3.5 = tuple(3.5, -7, 10.5, -14)")
{
REQUIRE(a * 3.5 == Tuple(3.5, -7, 10.5, -14));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Dividing a tuple by a scalar", "[Tuple][Multiplication]")
SCENARIO("Multiplying a tuple by a fraction", "[features/tuples.feature]")
{
Tuple a(1, -2, 3, -4);
REQUIRE(a / 2 == Tuple(0.5, -1, 1.5, -2));
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
THEN("a * 0.5 = tuple(0.5, -1, 1.5, -2)")
{
REQUIRE(a * 0.5 == Tuple(0.5, -1, 1.5, -2));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Dividing a tuple by a scalar without modify a", "[Tuple][Multiplication]")
SCENARIO("Dividing a tuple by a scalar", "[features/tuples.feature]")
{
Tuple a(1, -2, 3, -4);
Tuple b = a / 2;
REQUIRE(a / 2 == Tuple(0.5, -1, 1.5, -2));
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
THEN("a / 2 = tuple(0.5, -1, 1.5, -2)")
{
REQUIRE(a / 2 == Tuple(0.5, -1, 1.5, -2));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Computing the magnitude of vector(1,0,0)", "[Tuple][Magnitude]")
SCENARIO("Dividing a tuple by a scalar without modify a", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(1, 0, 0);
REQUIRE(v.magnitude() == 1);
GIVEN("a <-tuple(1, -2, 3, -4)")
{
Tuple a(1, -2, 3, -4);
WHEN("b = a / 2")
{
Tuple b = a / 2;
THEN("a / 2 = tuple(0.5, -1, 1.5, -2)")
{
REQUIRE(a / 2 == Tuple(0.5, -1, 1.5, -2));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Computing the magnitude of vector(0,1,0)", "[Tuple][Magnitude]")
SCENARIO("Computing the magnitude of vector(1,0,0)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(0, 1, 0);
REQUIRE(v.magnitude() == 1);
GIVEN("v <-vector(1, 0, 0)")
{
Tuple v = Tuple::Vector(1, 0, 0);
THEN("magnitude(v) = 1")
{
REQUIRE(v.magnitude() == 1);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Computing the magnitude of vector(0,0,1)", "[Tuple][Magnitude]")
SCENARIO("Computing the magnitude of vector(0,1,0)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(0, 0, 1);
GIVEN("v <-vector(0, 1, 0)")
{
Tuple v = Tuple::Vector(0, 1, 0);
REQUIRE(v.magnitude() == 1);
THEN("magnitude(v) = 1")
{
REQUIRE(v.magnitude() == 1);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Computing the magnitude of vector(1,2,3)", "[Tuple][Magnitude]")
SCENARIO("Computing the magnitude of vector(0,0,1)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(1, 2, 3);
GIVEN("v <-vector(0, 0, 1)")
{
Tuple v = Tuple::Vector(0, 0, 1);
REQUIRE(v.magnitude() == sqrt(14));
THEN("magnitude(v) = 1")
{
REQUIRE(v.magnitude() == 1);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Computing the magnitude of vector(-1,-2,-3)", "[Tuple][Magnitude]")
SCENARIO("Computing the magnitude of vector(1,2,3)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(-1, -2, -3);
GIVEN("v <-vector(1, 2, 3)")
{
Tuple v = Tuple::Vector(1, 2, 3);
REQUIRE(v.magnitude() == sqrt(14));
THEN("magnitude(v) = sqrt(14)")
{
REQUIRE(v.magnitude() == sqrt(14));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Normalize vector(4,0,0) gives (1,0,0)", "[Tuple][Normalize]")
SCENARIO("Computing the magnitude of vector(-1,-2,-3)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(4, 0, 0);
GIVEN("v <-vector(-1, -2, -3)")
{
Tuple v = Tuple::Vector(-1, -2, -3);
REQUIRE(v.normalize() == Tuple::Vector(1, 0, 0));
THEN("magnitude(v) = sqrt(14)")
{
REQUIRE(v.magnitude() == sqrt(14));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] Normalize vector(1,2,3)", "[Tuple][Normalize]")
SCENARIO("Normalize vector(4,0,0) gives (1,0,0)", "[features/tuples.feature]")
{
Tuple v = Tuple::Vector(1, 2, 3);
REQUIRE(v.normalize() == Tuple::Vector(1 / sqrtf(14), 2 / sqrtf(14), 3 / sqrtf(14)));
GIVEN("v <-vector(4, 0, 0)")
{
Tuple v = Tuple::Vector(4, 0, 0);
THEN("normalize(v) = vector(1, 0, 0)")
{
REQUIRE(v.normalize() == Tuple::Vector(1, 0, 0));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] The magnitude of a normalized vector", "[Tuple][Normalize]")
SCENARIO("Normalize vector(1,2,3)", "[features/tuples.feature]")
{
Tuple norm;
Tuple v = Tuple::Vector(1, 2, 3);
norm = v.normalize();
REQUIRE(norm.magnitude() == 1);
GIVEN("v <-vector(1, 2, 3)")
{
Tuple v = Tuple::Vector(1, 2, 3);
// vector (1/sqrt(14), 2/sqrt(14), 3/sqrt(14))
THEN("normalize(v) = approximately vector(0.26726, 0.53452, 0.80178)")
{
REQUIRE(v.normalize() == Tuple::Vector(1 / sqrtf(14), 2 / sqrtf(14), 3 / sqrtf(14)));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] The dot product of two tuples", "[Tuple][Dot]")
SCENARIO("The magnitude of a normalized vector", "[features/tuples.feature]")
{
Tuple a = Tuple::Vector(1, 2, 3);
Tuple b = Tuple::Vector(2, 3, 4);
REQUIRE(a.dot(b) == 20);
GIVEN("v <-vector(1, 2, 3)")
{
Tuple v = Tuple::Vector(1, 2, 3);
Tuple norm;
WHEN("norm <- normalize(v)")
{
norm = v.normalize();
THEN("magnitude(norm) = 1")
{
REQUIRE(norm.magnitude() == 1);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[01][Tuple] The cross product of two vector", "[Tuple][Cross]")
SCENARIO("The dot product of two tuples", "[features/tuples.feature]")
{
Tuple a = Tuple::Vector(1, 2, 3);
Tuple b = Tuple::Vector(2, 3, 4);
GIVEN("a <-vector(1, 2, 3)")
{
Tuple a = Tuple::Vector(1, 2, 3);
REQUIRE(a.cross(b) == Tuple::Vector(-1, 2, -1));
REQUIRE(b.cross(a) == Tuple::Vector(1, -2, 1));
AND_GIVEN("b <-vector(2, 3, 4)")
{
Tuple b = Tuple::Vector(2, 3, 4);
THEN("dot(a,b) = 20")
{
REQUIRE(a.dot(b) == 20);
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The cross product of two vectors", "[features/tuples.feature]")
{
GIVEN("a <-vector(1, 2, 3)")
{
Tuple a = Tuple::Vector(1, 2, 3);
AND_GIVEN("b <-vector(2, 3, 4)")
{
Tuple b = Tuple::Vector(2, 3, 4);
THEN("cross(a,b) = vector(-1, 2, -1)")
{
REQUIRE(a.cross(b) == Tuple::Vector(-1, 2, -1));
}
AND_THEN("cross(b,a) = vector(1, -2, -1)")
{
REQUIRE(b.cross(a) == Tuple::Vector(1, -2, 1));
}
}
}
}

View File

@@ -33,99 +33,184 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] colors are (red,green,blue) tuples", "[Colors]")
SCENARIO("Colors are (red,green,blue) tuples", "[features/tuples.feature]")
{
Color c(-0.5, 0.4, 1.7);
REQUIRE(c.red() == -0.5);
REQUIRE(c.green() == 0.4);
REQUIRE(c.blue() == 1.7);
GIVEN("c <-color(-0.5, 0.4, 1.7)")
{
Color c(-0.5, 0.4, 1.7);
THEN("c.red = -0.5")
{
REQUIRE(c.red() == -0.5);
}
AND_THEN("c.green = 0.4")
{
REQUIRE(c.green() == 0.4);
}
AND_THEN("c.blue = 1.7")
{
REQUIRE(c.blue() == 1.7);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Colors could be copied", "[Colors]")
SCENARIO("Colors could be copied", "[features/tuples.feature]")
{
Color c1(-0.5, 0.4, 1.7);
Color c2;
c2 = c1;
REQUIRE(c2.red() == -0.5);
REQUIRE(c2.green() == 0.4);
REQUIRE(c2.blue() == 1.7);
GIVEN("c1 <-color(-0.5, 0.4, 1.7)")
{
Color c1(-0.5, 0.4, 1.7);
AND_GIVEN("c2 <-color")
{
Color c2;
WHEN("c2 <- c1")
{
c2 = c1;
THEN("c2.red = -0.5")
{
REQUIRE(c2.red() == -0.5);
}
AND_THEN("c2.green = 0.4")
{
REQUIRE(c2.green() == 0.4);
}
AND_THEN("c2.blue = 1.7")
{
REQUIRE(c2.blue() == 1.7);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Adding colors", "[Colors]")
SCENARIO("Adding colors", "[features/tuples.feature]")
{
Color c1(0.9, 0.6, 0.75);
Color c2(0.7, 0.1, 0.25);
GIVEN("c1 <-color(0.9, 0.6, 0.75)")
{
Color c1(0.9, 0.6, 0.75);
AND_GIVEN("c2 <-color(0.7, 0.1, 0.25)")
{
Color c2(0.7, 0.1, 0.25);
REQUIRE((c1 + c2) == Color(1.6, 0.7, 1.0));
THEN("c1 + c2 = color(1.6, 0.7, 1.0)")
{
REQUIRE((c1 + c2) == Color(1.6, 0.7, 1.0));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Adding colors without modify c1", "[Colors]")
SCENARIO("Adding colors without modify c1", "[features/tuples.feature]")
{
Color c1(0.9, 0.6, 0.75);
Color c2(0.7, 0.1, 0.25);
Color c3 = c1 + c2;
REQUIRE((c1 + c2) == Color(1.6, 0.7, 1.0));
GIVEN("c1 <-color(0.9, 0.6, 0.75)")
{
Color c1(0.9, 0.6, 0.75);
AND_GIVEN("c2 <-color(0.7, 0.1, 0.25)")
{
Color c2(0.7, 0.1, 0.25);
WHEN("color c3 = c1 + c2")
{
Color c3 = c1 + c2;
THEN("c1 + c2 = color(1.6, 0.7, 1.0)")
{
REQUIRE((c1 + c2) == Color(1.6, 0.7, 1.0));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Subtracting colors", "[Colors]")
SCENARIO("Subtracting colors", "[features/tuples.feature]")
{
Color c1(0.9, 0.6, 0.75);
Color c2(0.7, 0.1, 0.25);
GIVEN("c1 <-color(0.9, 0.6, 0.75)")
{
Color c1(0.9, 0.6, 0.75);
AND_GIVEN("c2 <-color(0.7, 0.1, 0.25)")
{
Color c2(0.7, 0.1, 0.25);
REQUIRE((c1 - c2) == Color(0.2, 0.5, 0.5));
THEN("c1 - c2 = color(0.2, 0.5, 0.5)")
{
REQUIRE((c1 - c2) == Color(0.2, 0.5, 0.5));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Subtracting colors without modify c1", "[Colors]")
SCENARIO("Subtracting colors without modify c1", "[features/tuples.feature]")
{
Color c1(0.9, 0.6, 0.75);
Color c2(0.7, 0.1, 0.25);
Color c3 = c1 - c2;
REQUIRE((c1 - c2) == Color(0.2, 0.5, 0.5));
GIVEN("c1 <-color(0.9, 0.6, 0.75)")
{
Color c1(0.9, 0.6, 0.75);
AND_GIVEN("c2 <-color(0.7, 0.1, 0.25)")
{
Color c2(0.7, 0.1, 0.25);
WHEN("color c3 = c1 - c2")
{
Color c3 = c1 - c2;
THEN("c1 - c2 = color(0.2, 0.5, 0.5)")
{
REQUIRE((c1 - c2) == Color(0.2, 0.5, 0.5));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Multiplying a color by a scalar", "[Colors]")
SCENARIO("Multiplying a color by a scalar", "[features/tuples.feature]")
{
Color c(0.2, 0.3, 0.4);
REQUIRE(c * 2 == Color(0.4, 0.6, 0.8));
GIVEN("c <-color(0.2, 0.3, 0.4)")
{
Color c(0.2, 0.3, 0.4);
THEN("c * 2 = color(0.4, 0.6, 0.8)")
{
REQUIRE(c * 2 == Color(0.4, 0.6, 0.8));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Multiplying a color by a scalar without modify c", "[Colors]")
SCENARIO("Multiplying a color by a scalar without modify c", "[features/tuples.feature]")
{
Color c(0.2, 0.3, 0.4);
Color c3 = c * 4;
REQUIRE(c * 2 == Color(0.4, 0.6, 0.8));
GIVEN("c <-color(0.2, 0.3, 0.4)")
{
Color c(0.2, 0.3, 0.4);
WHEN("color c3 = c * 4")
{
Color c3 = c * 4;
THEN("c * 2 = color(0.4, 0.6, 0.8)")
{
REQUIRE(c * 2 == Color(0.4, 0.6, 0.8));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][01][Color] Multiplying a colors", "[Colors]")
SCENARIO("Multiplying a colors", "[features/tuples.feature]")
{
Color c1(1, 0.2, 0.4);
Color c2(0.9, 1, 0.1);
REQUIRE((c1 * c2) == Color(0.9, 0.2, 0.04));
GIVEN("c1 <-color(1, 0.2, 0.4)")
{
Color c1(1, 0.2, 0.4);
AND_GIVEN("c2 <-color(0.9, 1, 0.1)")
{
Color c2(0.9, 1, 0.1);
THEN("c1 * c2 = color(0.9, 0.2, 0.04)")
{
REQUIRE((c1 * c2) == Color(0.9, 0.2, 0.04));
}
}
}
}

View File

@@ -33,80 +33,136 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][02][Canvas] Creating a canvas", "[Canvas]")
SCENARIO("Creating a canvas", "[features/canvas.feature]")
{
Canvas c(10, 20);
REQUIRE(c.width() == 10);
REQUIRE(c.height() == 20);
for (int i = 0; i < 10; ++i)
GIVEN("c <-canvas(10, 20)")
{
for (int j = 0; j < 20; ++j)
Canvas c(10, 20);
THEN("c.width = 10")
{
REQUIRE(c.pixel_at(2, 3) == Color(0, 0, 0));
REQUIRE(c.width() == 10);
}
AND_THEN("c.height = 20")
{
REQUIRE(c.height() == 20);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][02][Canvas] Writing pixels to a canvas", "[Canvas]")
{
Canvas c(10, 20);
Color red(1, 0, 0);
c.write_pixel(2, 3, red);
REQUIRE(c.pixel_at(2, 3) == red);
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][02][Canvas] Constructing the PPM pixel data", "[Canvas]")
{
std::string ppm, the_ref_ppm;
Canvas c(5, 3);
Color c1(1.5, 0, 0);
Color c2(0, 0.5, 0);
Color c3(-0.5, 0, 1);
c.write_pixel(0, 0, c1);
c.write_pixel(2, 1, c2);
c.write_pixel(4, 2, c3);
ppm = c.to_ppm();
the_ref_ppm = "P3\n5 3\n255\n";
the_ref_ppm += "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
the_ref_ppm += "0 0 0 0 0 0 0 128 0 0 0 0 0 0 0\n";
the_ref_ppm += "0 0 0 0 0 0 0 0 0 0 0 0 0 0 255\n";
REQUIRE(ppm == the_ref_ppm);
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[02][02][Canvas] Split long lines in PPM files", "[Canvas]")
{
std::string ppm, the_ref_ppm;
Canvas c(10, 2);
for (int j = 0; j < 2; ++j)
{
for (int i = 0; i < 10; ++i)
{
c.write_pixel(i, j, Color(1, 0.8, 0.6));
for (int j = 0; j < 20; ++j)
{
AND_THEN("every pixel of c is color(0,0,0)")
{
REQUIRE(c.pixel_at(2, 3) == Color(0, 0, 0));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Writing pixels to a canvas", "[features/canvas.feature]")
{
GIVEN("c <-canvas(10, 20)")
{
Canvas c(10, 20);
AND_GIVEN("red <-color(1, 0, 0)")
{
Color red(1, 0, 0);
WHEN("write_pixel(c,2,3,red)")
{
c.write_pixel(2, 3, red);
THEN("pixel_at(c,2,3) = red")
{
REQUIRE(c.pixel_at(2, 3) == red);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Constructing the PPM pixel data", "[features/canvas.feature]")
{
std::string ppm, the_ref_ppm;
GIVEN("c <-canvas(5, 3)")
{
Canvas c(5, 3);
AND_GIVEN(" c1 color(1.5, 0, 0)")
{
Color c1(1.5, 0, 0);
AND_GIVEN(" c2 color(0, 0.5, 0)")
{
Color c2(0, 0.5, 0);
AND_GIVEN(" c3 color(-0.5, 0, 1))")
{
Color c3(-0.5, 0, 1);
WHEN("write_pixel(c, 0, 0, c1)")
{
c.write_pixel(0, 0, c1);
AND_WHEN("write_pixel(c, 2, 1, c2)")
{
c.write_pixel(2, 1, c2);
AND_WHEN("write_pixel(c, 4, 2, c3)")
{
c.write_pixel(4, 2, c3);
AND_WHEN("ppm <- canvas_to_ppm(c)")
{
ppm = c.to_ppm();
the_ref_ppm = "P3\n5 3\n255\n";
the_ref_ppm += "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
the_ref_ppm += "0 0 0 0 0 0 0 128 0 0 0 0 0 0 0\n";
the_ref_ppm += "0 0 0 0 0 0 0 0 0 0 0 0 0 0 255\n";
THEN("line 4-6 of ppm are 255 0 0 ....")
{
REQUIRE(ppm == the_ref_ppm);
}
}
}
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Split long lines in PPM files", "[features/canvas.feature]")
{
std::string ppm, the_ref_ppm;
GIVEN("c <-canvas(10, 2)")
{
Canvas c(10, 2);
WHEN("every pixel of c is set to color(1,0.8,0.6)")
{
for (int j = 0; j < 2; ++j)
{
for (int i = 0; i < 10; ++i)
{
c.write_pixel(i, j, Color(1, 0.8, 0.6));
}
}
AND_WHEN("ppm <- canvas_to_ppm(c)")
{
ppm = c.to_ppm();
the_ref_ppm = "P3\n10 2\n255\n";
the_ref_ppm += "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204\n";
the_ref_ppm += "153 255 204 153 255 204 153 255 204 153 255 204 153\n";
the_ref_ppm += "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204\n";
the_ref_ppm += "153 255 204 153 255 204 153 255 204 153 255 204 153\n";
THEN("line 4-7 of ppm are 255 204 153 255 204 ...")
{
REQUIRE(ppm == the_ref_ppm);
}
}
}
}
ppm = c.to_ppm();
the_ref_ppm = "P3\n10 2\n255\n";
the_ref_ppm += "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204\n";
the_ref_ppm += "153 255 204 153 255 204 153 255 204 153 255 204 153\n";
the_ref_ppm += "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204\n";
the_ref_ppm += "153 255 204 153 255 204 153 255 204 153 255 204 153\n";
REQUIRE(ppm == the_ref_ppm);
}

View File

@@ -33,431 +33,680 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Constructing and inspecting a 4x4 matrix", "[Matrix]")
SCENARIO("Constructing and inspecting a 4x4 matrix", "[features/matrices.feature]")
{
Matrix m = {
{ 1, 2, 3, 4},
{ 5.5, 6.5, 7.5, 8.5},
{ 9, 10, 11, 12},
{13.5, 14.5, 15.5, 16.5}
};
GIVEN("rgz following 4x4 matrix M")
{
Matrix M = {
{ 1, 2, 3, 4},
{ 5.5, 6.5, 7.5, 8.5},
{ 9, 10, 11, 12},
{13.5, 14.5, 15.5, 16.5}
};
REQUIRE(m.rows() == 4);
REQUIRE(m.cols() == 4);
THEN("M.rows = 4")
{
REQUIRE(M.rows() == 4);
}
AND_THEN("M.cols = 4")
{
REQUIRE(M.cols() == 4);
}
REQUIRE(m[0][0] == 1);
REQUIRE(m[0][3] == 4);
REQUIRE(m[1][0] == 5.5);
REQUIRE(m[1][2] == 7.5);
REQUIRE(m[2][2] == 11);
REQUIRE(m[3][0] == 13.5);
REQUIRE(m[3][2] == 15.5);
AND_THEN("M[0][0] = 1")
{
REQUIRE(M[0][0] == 1);
}
AND_THEN("M[0][3] = 4")
{
REQUIRE(M[0][3] == 4);
}
AND_THEN("M[1][0] = 5.5")
{
REQUIRE(M[1][0] == 5.5);
}
AND_THEN("M[1][2] = 7.5")
{
REQUIRE(M[1][2] == 7.5);
}
AND_THEN("M[2][2] = 11")
{
REQUIRE(M[2][2] == 11);
}
AND_THEN("M[3][0] = 13.5")
{
REQUIRE(M[3][0] == 13.5);
}
AND_THEN("M[3][2] = 15.5")
{
REQUIRE(M[3][2] == 15.5);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] A 2x2 matrix ought to be representable", "[Matrix]")
SCENARIO("A 2x2 matrix ought to be representable", "[features/matrices.feature]")
{
Matrix m = {
{-3, 5},
{ 1, -2}
};
REQUIRE(m.rows() == 2);
REQUIRE(m.cols() == 2);
REQUIRE(m[0][0] == -3);
REQUIRE(m[0][1] == 5);
REQUIRE(m[1][0] == 1);
REQUIRE(m[1][1] == -2);
GIVEN("the following 2x2 matrix M")
{
Matrix M = {
{-3, 5},
{ 1, -2}
};
THEN("M.rows = 2")
{
REQUIRE(M.rows() == 2);
}
AND_THEN("M.cols = 2")
{
REQUIRE(M.cols() == 2);
}
AND_THEN("M[0][0] = -3")
{
REQUIRE(M[0][0] == -3);
}
AND_THEN("M[0][1] = 5")
{
REQUIRE(M[0][1] == 5);
}
AND_THEN("M[1][0] = 1")
{
REQUIRE(M[1][0] == 1);
}
AND_THEN("M[1][1] = -2")
{
REQUIRE(M[1][1] == -2);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] A 3x3 matrix ought to be representable", "[Matrix]")
SCENARIO("A 3x3 matrix ought to be representable", "[features/matrices.feature]")
{
Matrix m = {
{-3, 5, 0},
{ 1, -2, -7},
{ 0, 1, 1}
};
GIVEN("the following 3x3 matrix M")
{
Matrix M = {
{-3, 5, 0},
{ 1, -2, -7},
{ 0, 1, 1}
};
THEN("M.rows = 3")
{
REQUIRE(M.rows() == 3);
}
AND_THEN("M.cols == 3")
{
REQUIRE(M.cols() == 3);
}
REQUIRE(m.rows() == 3);
REQUIRE(m.cols() == 3);
REQUIRE(m[0][0] == -3);
REQUIRE(m[1][1] == -2);
REQUIRE(m[2][2] == 1);
AND_THEN("M[0][0] = -3")
{
REQUIRE(M[0][0] == -3);
}
AND_THEN("M[1][1] = -2")
{
REQUIRE(M[1][1] == -2);
}
AND_THEN("M[2][2] = 1")
{
REQUIRE(M[2][2] == 1);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Matrix equality with identical matrices", "[Matrix]")
SCENARIO("Matrix equality with identical matrices", "[features/matrices.feature]")
{
Matrix a = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
Matrix b = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
REQUIRE(a == b);
GIVEN("the following matrix A")
{
Matrix A = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
AND_GIVEN("the following matrix B")
{
Matrix B = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
THEN("A = B")
{
REQUIRE(A == B);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Matrix equality with different matrices", "[Matrix]")
SCENARIO("Matrix equality with different matrices", "[features/matrices.feature]")
{
Matrix a = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
Matrix b = {
{2, 3, 4, 5},
{6, 7, 8, 9},
{8, 7, 6, 5},
{4, 3, 2, 1}
};
REQUIRE(a != b);
GIVEN("the following matrix A")
{
Matrix A = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
AND_GIVEN("the following matrix B")
{
Matrix B = {
{2, 3, 4, 5},
{6, 7, 8, 9},
{8, 7, 6, 5},
{4, 3, 2, 1}
};
THEN("A != B")
{
REQUIRE(A != B);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Multiplying two matrices", "[Matrix]")
SCENARIO("Multiplying two matrices", "[features/matrices.feature]")
{
Matrix a = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
Matrix b = {
{-2, 1, 2, 3},
{ 3, 2, 1, -1},
{ 4, 3, 6, 5},
{ 1, 2, 7, 8}
};
Matrix c = {
{20, 22, 50, 48},
{44, 54, 114, 108},
{40, 58, 110, 102},
{16, 26, 46, 42}
};
REQUIRE((a * b) == c);
GIVEN("the following matrix A")
{
Matrix A = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 8, 7, 6},
{5, 4, 3, 2}
};
AND_GIVEN("the following matrix B")
{
Matrix B = {
{-2, 1, 2, 3},
{ 3, 2, 1, -1},
{ 4, 3, 6, 5},
{ 1, 2, 7, 8}
};
AND_GIVEN("the following matrix C")
{
Matrix C = {
{20, 22, 50, 48},
{44, 54, 114, 108},
{40, 58, 110, 102},
{16, 26, 46, 42}
};
THEN("A * B = C")
REQUIRE((A * B) == C);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] a matrix multiplied by a tuple", "[Matrix]")
SCENARIO("A matrix multiplied by a tuple", "[features/matrices.feature]")
{
Matrix a = {
{1, 2, 3, 4},
{2, 4, 4, 2},
{8, 6, 4, 1},
{0, 0, 0, 1}
};
Tuple b(1, 2, 3, 1);
REQUIRE((a * b) == Tuple(18, 24, 33, 1));
GIVEN("the following matrix A")
{
Matrix A = {
{1, 2, 3, 4},
{2, 4, 4, 2},
{8, 6, 4, 1},
{0, 0, 0, 1}
};
AND_GIVEN("b <- tuple(1, 2, 3, 1)")
{
Tuple b(1, 2, 3, 1);
THEN("A * b = tuple(18, 24, 33, 1)")
{
REQUIRE((A * b) == Tuple(18, 24, 33, 1));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Multiplying a matrix by the identity matrix", "[Matrix]")
SCENARIO("Multiplying a matrix by the identity matrix", "[features/matrices.feature]")
{
Matrix a = {
{0, 1, 2, 4},
{1, 2, 4, 8},
{2, 4, 8, 16},
{4, 8, 16, 32}
};
REQUIRE((a * Matrix::identity()) == a);
GIVEN("the following matrix A")
{
Matrix A = {
{0, 1, 2, 4},
{1, 2, 4, 8},
{2, 4, 8, 16},
{4, 8, 16, 32}
};
THEN("A * identity_matrix = A")
{
REQUIRE((A * Matrix::identity()) == A);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Multiplying the identity matrix by a tuple", "[Matrix]")
SCENARIO("Multiplying the identity matrix by a tuple", "[features/matrices.feature]")
{
Tuple a(1, 2, 3, 4);
REQUIRE((Matrix::identity() * a) == a);
GIVEN("a <- tuple(1, 2, 3, 4)")
{
Tuple a(1, 2, 3, 4);
THEN("identity_matrix * a = a")
{
REQUIRE((Matrix::identity() * a) == a);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Transposing a matrix", "[Matrix]")
SCENARIO("Transposing a matrix", "[features/matrices.feature]")
{
Matrix a = {
{0, 9, 3, 0},
{9, 8, 0, 8},
{1, 8, 5, 3},
{0, 0, 5, 8}
};
Matrix transposed = {
{0, 9, 1, 0},
{9, 8, 8, 0},
{3, 0, 5, 5},
{0, 8, 3, 8}
};
GIVEN("the following matrix A")
{
Matrix A = {
{0, 9, 3, 0},
{9, 8, 0, 8},
{1, 8, 5, 3},
{0, 0, 5, 8}
};
THEN("transpose(A) is the following matrix")
{
Matrix transposed = {
{0, 9, 1, 0},
{9, 8, 8, 0},
{3, 0, 5, 5},
{0, 8, 3, 8}
};
a.transpose();
A.transpose();
REQUIRE(a == transposed);
REQUIRE(A == transposed);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Transposing the identity matrix", "[Matrix]")
SCENARIO("Transposing the identity matrix", "[features/matrices.feature]")
{
Matrix a = Matrix::identity();
GIVEN("A <- transpose(identity_matrix)")
{
Matrix A = Matrix::identity();
a.transpose();
REQUIRE(a == Matrix::identity());
A.transpose();
THEN("A = identity_matrix")
{
REQUIRE(A == Matrix::identity());
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the determinant of a 2x2 matrix", "[Matrix]")
SCENARIO("Calculating the determinant of a 2x2 matrix", "[features/matrices.feature]")
{
Matrix a = {
{ 1, 5},
{-3, 2}
};
REQUIRE(a.determinant() == 17);
GIVEN("the following 2x2 matrix A")
{
Matrix A = {
{ 1, 5},
{-3, 2}
};
THEN("determinant(A) = 17")
{
REQUIRE(A.determinant() == 17);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] A submatrix of a 3x3 matrix is a 2x2 matrix", "[Matrix]")
SCENARIO("A submatrix of a 3x3 matrix is a 2x2 matrix", "[features/matrices.feature]")
{
Matrix a = {
{ 1, 5, 0},
{-3, 2, 7},
{ 0, 6, -3}
};
GIVEN("the following 3x3 matrix A")
{
Matrix A = {
{ 1, 5, 0},
{-3, 2, 7},
{ 0, 6, -3}
};
Matrix b = {
{-3, 2},
{ 0, 6}
};
REQUIRE(a.sub_matrix(0, 2) == b);
Matrix B = {
{-3, 2},
{ 0, 6}
};
THEN("submatrix(A,0,2) is the following 2x2 matrix")
{
REQUIRE(A.sub_matrix(0, 2) == B);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] A submatrix of a 4x4 matrix is a 3x3 matrix", "[Matrix]")
SCENARIO("A submatrix of a 4x4 matrix is a 3x3 matrix", "[features/matrices.feature]")
{
Matrix a = {
{-6, 1, 1, 6},
{-8, 5, 8, 6},
{-1, 0, 8, 2},
{-7, 1, -1, 1}
};
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{-6, 1, 1, 6},
{-8, 5, 8, 6},
{-1, 0, 8, 2},
{-7, 1, -1, 1}
};
Matrix b = {
{-6, 1, 6},
{-8, 8, 6},
{-7, -1, 1}
};
REQUIRE(a.sub_matrix(2, 1) == b);
Matrix B = {
{-6, 1, 6},
{-8, 8, 6},
{-7, -1, 1}
};
THEN("submatrix(B,2,1) is the following 3x3 matrix")
{
REQUIRE(A.sub_matrix(2, 1) == B);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating a minor of a 3x3 matrix", "[Matrix]")
SCENARIO("Calculating a minor of a 3x3 matrix", "[features/matrices.feature]")
{
Matrix a = {
{3, 5, 0},
{2, -1, -7},
{6, -1, 5}
};
Matrix b = a.sub_matrix(1, 0);
REQUIRE(b.determinant() == 25);
REQUIRE(a.minor(1, 0) == 25);
GIVEN("the following 3x3 matrix A")
{
Matrix A = {
{3, 5, 0},
{2, -1, -7},
{6, -1, 5}
};
AND_GIVEN("B <- submatrix(A,1,0)")
{
Matrix B = A.sub_matrix(1, 0);
THEN("determinant(B) = 25")
{
REQUIRE(B.determinant() == 25);
}
AND_THEN("minor(A,1,0)=25")
{
REQUIRE(A.minor(1, 0) == 25);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating a cofactor of a 3x3 matrix", "[Matrix]")
SCENARIO("Calculating a cofactor of a 3x3 matrix", "[features/matrices.feature]")
{
Matrix a = {
{3, 5, 0},
{2, -1, -7},
{6, -1, 5}
};
REQUIRE(a.minor(0, 0) == -12);
REQUIRE(a.cofactor(0, 0) == -12);
REQUIRE(a.minor(1, 0) == 25);
REQUIRE(a.cofactor(1, 0) == -25);
GIVEN("the following 3x3 matrix A")
{
Matrix A = {
{3, 5, 0},
{2, -1, -7},
{6, -1, 5}
};
THEN("minor(A, 0, 0) = -12")
{
REQUIRE(A.minor(0, 0) == -12);
}
AND_THEN("cofactor(A, 0, 0) = -12")
{
REQUIRE(A.cofactor(0, 0) == -12);
}
AND_THEN("minor(A, 1, 0) = 25")
{
REQUIRE(A.minor(1, 0) == 25);
}
AND_THEN("cofactor(A, 1, 0) = -25")
{
REQUIRE(A.cofactor(1, 0) == -25);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the determinant of a 3x3 matrix", "[Matrix]")
SCENARIO("Calculating the determinant of a 3x3 matrix", "[features/matrices.feature]")
{
Matrix a = {
{ 1, 2, 6},
{-5, 8, -4},
{ 2, 6, 4}
};
REQUIRE(a.cofactor(0, 0) == 56);
REQUIRE(a.cofactor(0, 1) == 12);
REQUIRE(a.cofactor(0, 2) == -46);
REQUIRE(a.determinant() == -196);
GIVEN("the following 3x3 matrix A")
{
Matrix A = {
{ 1, 2, 6},
{-5, 8, -4},
{ 2, 6, 4}
};
THEN("cofactor(A, 0, 0) = 56")
{
REQUIRE(A.cofactor(0, 0) == 56);
}
AND_THEN("cofactor(A, 0, 1) = 12")
{
REQUIRE(A.cofactor(0, 1) == 12);
}
AND_THEN("cofactor(A, 0, 2) = -46")
{
REQUIRE(A.cofactor(0, 2) == -46);
}
AND_THEN("determinant(A) = -196")
{
REQUIRE(A.determinant() == -196);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the determinant of a 4x4 matrix", "[Matrix]")
SCENARIO("Calculating the determinant of a 4x4 matrix", "[features/matrices.feature]")
{
Matrix a = {
{-2, -8, 3, 5},
{-3, 1, 7, 3},
{ 1, 2, -9, 6},
{-6, 7, 7, -9}
};
REQUIRE(a.cofactor(0, 0) == 690);
REQUIRE(a.cofactor(0, 1) == 447);
REQUIRE(a.cofactor(0, 2) == 210);
REQUIRE(a.cofactor(0, 3) == 51);
REQUIRE(a.determinant() == -4071);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{-2, -8, 3, 5},
{-3, 1, 7, 3},
{ 1, 2, -9, 6},
{-6, 7, 7, -9}
};
THEN("cofactor(A, 0, 0) = 690")
{
REQUIRE(A.cofactor(0, 0) == 690);
}
AND_THEN("cofactor(A, 0, 1) = 447")
{
REQUIRE(A.cofactor(0, 1) == 447);
}
AND_THEN("cofactor(A, 0, 2) = 210")
{
REQUIRE(A.cofactor(0, 2) == 210);
}
AND_THEN("cofactor(A, 0, 3) = 51")
{
REQUIRE(A.cofactor(0, 3) == 51);
}
AND_THEN("determinant(A) = -4071")
{
REQUIRE(A.determinant() == -4071);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Testing an invertible matrix for invertibility", "[Matrix]")
SCENARIO("Testing an invertible matrix for invertibility", "[features/matrices.feature]")
{
Matrix a = {
{6, 4, 4, 4},
{5, 5, 7, 6},
{4, -9, 3, -7},
{9, 1, 7, -6}
};
REQUIRE(a.determinant() == -2120);
REQUIRE(a.invertible() == true);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{6, 4, 4, 4},
{5, 5, 7, 6},
{4, -9, 3, -7},
{9, 1, 7, -6}
};
THEN("determinant(A) = -2120")
{
REQUIRE(A.determinant() == -2120);
}
AND_THEN("A is invertible")
{
REQUIRE(A.invertible() == true);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Testing an noninvertible matrix for invertibility", "[Matrix]")
SCENARIO("Testing an noninvertible matrix for invertibility", "[features/matrices.feature]")
{
Matrix a = {
{-4, 2, -2, -3},
{ 9, 6, 2, 6},
{ 0, -5, 1, -5},
{ 0, 0, 0, 0}
};
REQUIRE(a.determinant() == 0);
REQUIRE(a.invertible() == false);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{-4, 2, -2, -3},
{ 9, 6, 2, 6},
{ 0, -5, 1, -5},
{ 0, 0, 0, 0}
};
THEN("determinant(A) = 0")
{
REQUIRE(A.determinant() == 0);
}
AND_THEN("A is not invertible")
{
REQUIRE(A.invertible() == false);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the inverse of a matrix", "[Matrix]")
SCENARIO("Calculating the inverse of a matrix", "[features/matrices.feature]")
{
Matrix a = {
{-5, 2, 6, -8},
{ 1, -5, 1, 8},
{ 7, 7, -6, -7},
{ 1, -3, 7, 4}
};
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{-5, 2, 6, -8},
{ 1, -5, 1, 8},
{ 7, 7, -6, -7},
{ 1, -3, 7, 4}
};
Matrix a_inverted = {
{ 0.21805, 0.45113, 0.24060, -0.04511},
{-0.80827, -1.45677, -0.44361, 0.52068},
{-0.07895, -0.22368, -0.05263, 0.19737},
{-0.52256, -0.81391, -0.30075, 0.30639}
};
Matrix b = a.inverse();
REQUIRE(a.determinant() == 532);
REQUIRE(a.cofactor(2, 3) == -160);
REQUIRE(b[3][2] == -160.0 / 532.0);
REQUIRE(a.cofactor(3, 2) == 105);
REQUIRE(b[2][3] == 105.0 / 532.0);
REQUIRE(b == a_inverted);
Matrix a_inverted = {
{ 0.21805, 0.45113, 0.24060, -0.04511},
{-0.80827, -1.45677, -0.44361, 0.52068},
{-0.07895, -0.22368, -0.05263, 0.19737},
{-0.52256, -0.81391, -0.30075, 0.30639}
};
AND_GIVEN("B <- inverse(A)")
{
Matrix B = A.inverse();
THEN("determinant(A) = 532")
{
REQUIRE(A.determinant() == 532);
}
AND_THEN("cofactor(A, 2, 3) = -160")
{
REQUIRE(A.cofactor(2, 3) == -160);
}
AND_THEN("B[3][2] = -160.0 / 532.0")
{
REQUIRE(B[3][2] == -160.0 / 532.0);
}
AND_THEN("cofactor(A, 3, 2) = 105")
{
REQUIRE(A.cofactor(3, 2) == 105);
}
AND_THEN("B[2][3] = 105.0 / 532.0")
{
REQUIRE(B[2][3] == 105.0 / 532.0);
}
AND_THEN("B is the following 4x4 matrix")
{
REQUIRE(B == a_inverted);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the inverse of another matrix", "[Matrix]")
SCENARIO("Calculating the inverse of another matrix", "[features/matrices.feature]")
{
Matrix a = {
{ 8, -5, 9, 2},
{ 7, 5, 6, 1},
{-6, 0, 9, 6},
{-3, 0, -9, -4}
};
Matrix a_inverted = {
{-0.15385, -0.15385, -0.28205, -0.53846},
{-0.07692, 0.12308, 0.02564, 0.03077},
{ 0.35897, 0.35897, 0.43590, 0.92308},
{-0.69231, -0.69231, -0.76923, -1.92308}
};
REQUIRE(a.inverse() == a_inverted);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{ 8, -5, 9, 2},
{ 7, 5, 6, 1},
{-6, 0, 9, 6},
{-3, 0, -9, -4}
};
Matrix a_inverted = {
{-0.15385, -0.15385, -0.28205, -0.53846},
{-0.07692, 0.12308, 0.02564, 0.03077},
{ 0.35897, 0.35897, 0.43590, 0.92308},
{-0.69231, -0.69231, -0.76923, -1.92308}
};
THEN("inverse(A) is the following matrix")
{
REQUIRE(A.inverse() == a_inverted);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Calculating the inverse of third matrix", "[Matrix]")
SCENARIO("Calculating the inverse of third matrix", "[features/matrices.feature]")
{
Matrix a = {
{ 9, 3, 0, 9},
{-5, -2, -6, -3},
{-4, 9, 6, 4},
{-7, 6, 6, 2}
};
Matrix a_inverted = {
{-0.04074, -0.07778, 0.14444, -0.22222},
{-0.07778, 0.03333, 0.36667, -0.33333},
{-0.02901, -0.14630, -0.10926, 0.12963},
{ 0.17778, 0.06667, -0.26667, 0.33333}
};
REQUIRE(a.inverse() == a_inverted);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{ 9, 3, 0, 9},
{-5, -2, -6, -3},
{-4, 9, 6, 4},
{-7, 6, 6, 2}
};
Matrix a_inverted = {
{-0.04074, -0.07778, 0.14444, -0.22222},
{-0.07778, 0.03333, 0.36667, -0.33333},
{-0.02901, -0.14630, -0.10926, 0.12963},
{ 0.17778, 0.06667, -0.26667, 0.33333}
};
THEN("inverse(A) is the following matrix")
{
REQUIRE(A.inverse() == a_inverted);
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[03][Matrix] Multiplying a product by its inverse", "[Matrix]")
SCENARIO("Multiplying a product by its inverse", "[features/matrices.feature]")
{
Matrix a = {
{ 3, -9, 7, 3},
{ 3, -8, 2, -9},
{-4, 4, 4, 1},
{-6, 5, -1, 1}
};
Matrix b = {
{8, 2, 2, 2},
{3, -1, 7, 0},
{7, 0, 5, 4},
{6, -2, 0, 5}
};
Matrix c = a * b;
REQUIRE(c * b.inverse() == a);
GIVEN("the following 4x4 matrix A")
{
Matrix A = {
{ 3, -9, 7, 3},
{ 3, -8, 2, -9},
{-4, 4, 4, 1},
{-6, 5, -1, 1}
};
AND_GIVEN("the following 4x4 matrix B")
{
Matrix B = {
{8, 2, 2, 2},
{3, -1, 7, 0},
{7, 0, 5, 4},
{6, -2, 0, 5}
};
AND_GIVEN("C <- A * B")
{
Matrix C = A * B;
THEN("C * inverse(B) = A")
{
REQUIRE(C * B.inverse() == A);
}
}
}
}
}

View File

@@ -33,204 +33,408 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Multiplying by a translation matrix", "[Matrix]")
SCENARIO("Multiplying by a translation matrix", "[features/transformations.feature]")
{
Matrix transform = Matrix::translation(5, -3, 2);
Tuple p = Tuple::Point(-3, 4, 5);
REQUIRE(transform * p == Tuple::Point(2, 1, 7));
GIVEN("transform <- translation(5, -3, 2)")
{
Matrix transform = Matrix::translation(5, -3, 2);
AND_GIVEN("p <- point(-3, 4, 5)")
{
Tuple p = Tuple::Point(-3, 4, 5);
THEN("transform * p = point(2, 1, 7)")
{
REQUIRE(transform * p == Tuple::Point(2, 1, 7));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Multiplying by the inverse of a translation matrix", "[Matrix]")
SCENARIO("Multiplying by the inverse of a translation matrix", "[features/transformations.feature]")
{
Matrix transform = Matrix::translation(5, -3, 2);
Matrix inv = transform.inverse();
Tuple p = Tuple::Point(-3, 4, 5);
REQUIRE(inv * p == Tuple::Point(-8, 7, 3));
GIVEN("transform <- translation(5, -3, 2)")
{
Matrix transform = Matrix::translation(5, -3, 2);
AND_GIVEN("inv <- inverse(transform)")
{
Matrix inv = transform.inverse();
AND_GIVEN("p <- point(-3, 4, 5)")
{
Tuple p = Tuple::Point(-3, 4, 5);
THEN("inv * p = point(-8, 7, 3)")
{
REQUIRE(inv * p == Tuple::Point(-8, 7, 3));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Translation does not affect vectors", "[Matrix]")
SCENARIO("Translation does not affect vectors", "[features/transformations.feature]")
{
Matrix transform = Matrix::translation(5, -3, 2);
Tuple v = Tuple::Vector(-3, 4, 5);
REQUIRE(transform * v == v);
GIVEN("transform <- translation(5, -3, 2)")
{
Matrix transform = Matrix::translation(5, -3, 2);
AND_GIVEN("v <- vector(-3, 4, 5)")
{
Tuple v = Tuple::Vector(-3, 4, 5);
THEN("transform * v = v")
{
REQUIRE(transform * v == v);
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A scaling matrix applied to a point", "[Matrix]")
SCENARIO("A scaling matrix applied to a point", "[features/transformations.feature]")
{
Matrix transform = Matrix::scaling(2, 3, 4);
Tuple p = Tuple::Point(-4, 6, 8);
REQUIRE(transform * p == Tuple::Point(-8, 18, 32));
GIVEN("transform <- scaling(2, 3, 4)")
{
Matrix transform = Matrix::scaling(2, 3, 4);
AND_GIVEN("p <- point(-4, 6, 8)")
{
Tuple p = Tuple::Point(-4, 6, 8);
THEN("transform * p = point(-8, 18, 32)")
{
REQUIRE(transform * p == Tuple::Point(-8, 18, 32));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A scaling matrix applied to a vector", "[Matrix]")
SCENARIO("A scaling matrix applied to a vector", "[features/transformations.feature]")
{
Matrix transform = Matrix::scaling(2, 3, 4);
Tuple v = Tuple::Vector(-4, 6, 8);
REQUIRE(transform * v == Tuple::Vector(-8, 18, 32));
GIVEN("transform <- scaling(2, 3, 4)")
{
Matrix transform = Matrix::scaling(2, 3, 4);
AND_GIVEN("v <- vector(-4, 6, 8)")
{
Tuple v = Tuple::Vector(-4, 6, 8);
THEN("transform * p = vector(-8, 18, 32)")
{
REQUIRE(transform * v == Tuple::Vector(-8, 18, 32));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Multiplying by the inverse of a scaling matrix", "[Matrix]")
SCENARIO("Multiplying by the inverse of a scaling matrix", "[features/transformations.feature]")
{
Matrix transform = Matrix::scaling(2, 3, 4);
Matrix inv = transform.inverse();
Tuple v = Tuple::Vector(-4, 6, 8);
REQUIRE(inv * v == Tuple::Vector(-2, 2, 2));
GIVEN("transform <- scaling(2, 3, 4)")
{
Matrix transform = Matrix::scaling(2, 3, 4);
AND_GIVEN("inv <- inverse(transform)")
{
Matrix inv = transform.inverse();
AND_GIVEN("v <- vector(-4, 6, 8)")
{
Tuple v = Tuple::Vector(-4, 6, 8);
THEN("inv * v = vector(-2, 2, 2)")
{
REQUIRE(inv * v == Tuple::Vector(-2, 2, 2));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Reflection is scaling by a negative value", "[Matrix]")
SCENARIO("Reflection is scaling by a negative value", "[features/transformations.feature]")
{
Matrix transform = Matrix::scaling(-1, 1, 1);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(-2, 3, 4));
GIVEN("transform <- scaling(-1, 1, 1)")
{
Matrix transform = Matrix::scaling(-1, 1, 1);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p = point(-2, 3, 4)")
{
REQUIRE(transform * p == Tuple::Point(-2, 3, 4));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Rotating a point around the x axis", "[Matrix]")
SCENARIO("Rotating a point around the x axis", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(0, 1, 0);
Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4);
Matrix full_quarter = Matrix::rotation_x(std::numbers::pi / 2);
REQUIRE(half_quarter * p == Tuple::Point(0, sqrt(2) / 2, sqrt(2) / 2));
REQUIRE(full_quarter * p == Tuple::Point(0, 0, 1));
GIVEN("p <- point(0, 1, 0)")
{
Tuple p = Tuple::Point(0, 1, 0);
AND_GIVEN("half_quarter <- rotation_x(pi/4)")
{
Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4);
AND_GIVEN("full_quarter <- rotation_x(pi/2)")
{
Matrix full_quarter = Matrix::rotation_x(std::numbers::pi / 2);
THEN("half_quarter * p = point(0, sqrt(2) / 2, sqrt(2) / 2)")
{
REQUIRE(half_quarter * p == Tuple::Point(0, sqrt(2) / 2, sqrt(2) / 2));
}
AND_THEN("full_quarter * p == point(0, 0, 1)")
{
REQUIRE(full_quarter * p == Tuple::Point(0, 0, 1));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] The inverse of an x-rotation rotates in the opposite direction", "[Matrix]")
SCENARIO("The inverse of an x-rotation rotates in the opposite direction", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(0, 1, 0);
Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4);
Matrix inv = half_quarter.inverse();
REQUIRE(inv * p == Tuple::Point(0, sqrt(2) / 2, -sqrt(2) / 2));
GIVEN("p <- point(0, 1, 0)")
{
Tuple p = Tuple::Point(0, 1, 0);
AND_GIVEN("half_quarter <- rotation_x(pi/4)")
{
Matrix half_quarter = Matrix::rotation_x(std::numbers::pi / 4);
AND_GIVEN("inv <- inverse(half_quarter)")
{
Matrix inv = half_quarter.inverse();
THEN("inv * p = point(0, sqrt(2) / 2, -sqrt(2) / 2)")
{
REQUIRE(inv * p == Tuple::Point(0, sqrt(2) / 2, -sqrt(2) / 2));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Rotating a point around the y axis", "[Matrix]")
SCENARIO("Rotating a point around the y axis", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(0, 0, 1);
Matrix half_quarter = Matrix::rotation_y(std::numbers::pi / 4);
Matrix full_quarter = Matrix::rotation_y(std::numbers::pi / 2);
REQUIRE(half_quarter * p == Tuple::Point(sqrt(2) / 2, 0, sqrt(2) / 2));
REQUIRE(full_quarter * p == Tuple::Point(1, 0, 0));
GIVEN("p <- point(0, 1, 0)")
{
Tuple p = Tuple::Point(0, 0, 1);
AND_GIVEN("half_quarter <- rotation_y(pi/4)")
{
Matrix half_quarter = Matrix::rotation_y(std::numbers::pi / 4);
AND_GIVEN("full_quarter <- rotation_y(pi/2)")
{
Matrix full_quarter = Matrix::rotation_y(std::numbers::pi / 2);
THEN("half_quarter * p = point(sqrt(2) / 2, 0, sqrt(2) / 2)")
{
REQUIRE(half_quarter * p == Tuple::Point(sqrt(2) / 2, 0, sqrt(2) / 2));
}
AND_THEN("full_quarter * p = point(1, 0, 0)")
{
REQUIRE(full_quarter * p == Tuple::Point(1, 0, 0));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Rotating a point around the z axis", "[Matrix]")
SCENARIO("Rotating a point around the z axis", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(0, 1, 0);
Matrix half_quarter = Matrix::rotation_z(std::numbers::pi / 4);
Matrix full_quarter = Matrix::rotation_z(std::numbers::pi / 2);
GIVEN("p <- point(0, 1, 0)")
{
Tuple p = Tuple::Point(0, 1, 0);
AND_GIVEN("full_quarter <- rotation_z(pi/4)")
{
Matrix half_quarter = Matrix::rotation_z(std::numbers::pi / 4);
AND_GIVEN("full_quarter <- rotation_z(pi/2)")
{
Matrix full_quarter = Matrix::rotation_z(std::numbers::pi / 2);
Tuple z = half_quarter * p;
REQUIRE(half_quarter * p == Tuple::Point(-sqrt(2) / 2, sqrt(2) / 2, 0));
REQUIRE(full_quarter * p == Tuple::Point(-1, 0, 0));
Tuple z = half_quarter * p;
THEN("half_quarter * p = point(-sqrt(2) / 2, sqrt(2) / 2, 0)")
{
REQUIRE(half_quarter * p == Tuple::Point(-sqrt(2) / 2, sqrt(2) / 2, 0));
}
AND_THEN("full_quarter * p = point(-1, 0, 0)")
{
REQUIRE(full_quarter * p == Tuple::Point(-1, 0, 0));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A shearing transformation moves x in proportion to y", "[Matrix]")
SCENARIO("A shearing transformation moves x in proportion to y", "[features/transformations.feature]")
{
Matrix transform = Matrix::shearing(1, 0, 0, 0, 0, 0);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(5, 3, 4));
GIVEN("transform <- shearing(1, 0, 0, 0, 0, 0)")
{
Matrix transform = Matrix::shearing(1, 0, 0, 0, 0, 0);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p == point(5, 3, 4)")
{
REQUIRE(transform * p == Tuple::Point(5, 3, 4));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A shearing transformation moves y in proportion to x", "[Matrix]")
SCENARIO("A shearing transformation moves y in proportion to x", "[features/transformations.feature]")
{
Matrix transform = Matrix::shearing(0, 0, 1, 0, 0, 0);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(2, 5, 4));
GIVEN("transform <- shearing(0, 0, 1, 0, 0, 0)")
{
Matrix transform = Matrix::shearing(0, 0, 1, 0, 0, 0);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p == point(2, 5, 4)")
{
REQUIRE(transform * p == Tuple::Point(2, 5, 4));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A shearing transformation moves y in proportion to z", "[Matrix]")
SCENARIO("A shearing transformation moves y in proportion to z", "[features/transformations.feature]")
{
Matrix transform = Matrix::shearing(0, 0, 0, 1, 0, 0);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(2, 7, 4));
GIVEN("transform <- shearing(0, 0, 0, 1, 0, 0)")
{
Matrix transform = Matrix::shearing(0, 0, 0, 1, 0, 0);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p == point(2, 7, 4)")
{
REQUIRE(transform * p == Tuple::Point(2, 7, 4));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A shearing transformation moves z in proportion to x", "[Matrix]")
SCENARIO("A shearing transformation moves z in proportion to x", "[features/transformations.feature]")
{
Matrix transform = Matrix::shearing(0, 0, 0, 0, 1, 0);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(2, 3, 6));
GIVEN("transform <- shearing(0, 0, 0, 0, 1, 0)")
{
Matrix transform = Matrix::shearing(0, 0, 0, 0, 1, 0);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p == point(2, 3, 6)")
{
REQUIRE(transform * p == Tuple::Point(2, 3, 6));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] A shearing transformation moves z in proportion to y", "[Matrix]")
SCENARIO("A shearing transformation moves z in proportion to y", "[features/transformations.feature]")
{
Matrix transform = Matrix::shearing(0, 0, 0, 0, 0, 1);
Tuple p = Tuple::Point(2, 3, 4);
REQUIRE(transform * p == Tuple::Point(2, 3, 7));
GIVEN("transform <- shearing(0, 0, 0, 0, 0, 1)")
{
Matrix transform = Matrix::shearing(0, 0, 0, 0, 0, 1);
AND_GIVEN("p <- point(2, 3, 4)")
{
Tuple p = Tuple::Point(2, 3, 4);
THEN("transform * p == point(2, 3, 7)")
{
REQUIRE(transform * p == Tuple::Point(2, 3, 7));
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Individual transformations are applied in sequence", "[Matrix]")
SCENARIO("Individual transformations are applied in sequence", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(1, 0, 1);
Matrix a = Matrix::rotation_x(std::numbers::pi / 2);
Matrix b = Matrix::scaling(5, 5, 5);
Matrix c = Matrix::translation(10, 5, 7);
GIVEN("p <- point(1, 0, 1)")
{
Tuple p = Tuple::Point(1, 0, 1);
AND_GIVEN("A <- rotation_x(pi/2)")
{
Matrix A = Matrix::rotation_x(std::numbers::pi / 2);
AND_GIVEN("B <- scaling(5, 5, 5)")
{
Matrix B = Matrix::scaling(5, 5, 5);
AND_GIVEN("C <- translation(10, 5, 7))")
{
Matrix C = Matrix::translation(10, 5, 7);
// Appply rotation first.
Tuple p2 = a * p;
REQUIRE(p2 == Tuple::Point(1, -1, 0));
// Then Apply scaling
Tuple p3 = b * p2;
REQUIRE(p3 == Tuple::Point(5, -5, 0));
// Then Apply translation
Tuple p4 = c * p3;
REQUIRE(p4 == Tuple::Point(15, 0, 7));
// Apply rotation first.
WHEN("p2 <- A * p")
{
Tuple p2 = A * p;
THEN("p2 = point(1, -1, 0)")
{
REQUIRE(p2 == Tuple::Point(1, -1, 0));
}
// Then Apply scaling
WHEN("p3 <- B * p2")
{
Tuple p3 = B * p2;
THEN("p3 = point(5, -5, 0)")
{
REQUIRE(p3 == Tuple::Point(5, -5, 0));
}
// Then Apply translation
WHEN("p4 = C * p3")
{
Tuple p4 = C * p3;
THEN("p4 = point(15, 0, 7)")
{
REQUIRE(p4 == Tuple::Point(15, 0, 7));
}
}
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[04][Trans] Chained transformation must be applied in rever order", "[Matrix]")
SCENARIO("Chained transformation must be applied in revert order", "[features/transformations.feature]")
{
Tuple p = Tuple::Point(1, 0, 1);
Matrix a = Matrix::rotation_x(std::numbers::pi / 2);
Matrix b = Matrix::scaling(5, 5, 5);
Matrix c = Matrix::translation(10, 5, 7);
Matrix t = c * b * a;
REQUIRE(t * p == Tuple::Point(15, 0, 7));
GIVEN("p <- point(1, 0, 1)")
{
Tuple p = Tuple::Point(1, 0, 1);
AND_GIVEN("A <- rotation_x(pi/2)")
{
Matrix A = Matrix::rotation_x(std::numbers::pi / 2);
AND_GIVEN("B <- scaling(5, 5, 5)")
{
Matrix B = Matrix::scaling(5, 5, 5);
AND_GIVEN("C <- translation(10, 5, 7))")
{
Matrix C = Matrix::translation(10, 5, 7);
WHEN("t <- C * B * A")
{
Matrix T = C * B * A;
THEN("T * p == point(15, 0, 7)")
{
REQUIRE(T * p == Tuple::Point(15, 0, 7));
}
}
}
}
}
}
}

View File

@@ -35,31 +35,59 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Creating and querying a ray", "[Rays]")
SCENARIO("Creating and querying a ray", "[features/rays.feature]")
{
Tuple origin = Tuple::Point(1, 2, 3);
Tuple direction = Tuple::Vector(4, 5, 6);
Ray r(origin, direction);
REQUIRE(r.origin() == origin);
REQUIRE(r.direction() == direction);
GIVEN("origin <- point(1, 2, 3)")
{
Tuple origin = Tuple::Point(1, 2, 3);
AND_GIVEN("direction <- vector(4, 5, 6)")
{
Tuple direction = Tuple::Vector(4, 5, 6);
WHEN("r <- ray(origin, direction)")
{
Ray r(origin, direction);
THEN("r.origin = origin")
{
REQUIRE(r.origin() == origin);
}
AND_THEN("r.direction = direction")
{
REQUIRE(r.direction() == direction);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Computing a point from a distance", "[Rays]")
SCENARIO("Computing a point from a distance", "[features/rays.feature]")
{
Ray r(Tuple::Point(2, 3, 4), Tuple::Vector(1, 0, 0));
REQUIRE(r.position(0) == Tuple::Point(2, 3, 4));
REQUIRE(r.position(1) == Tuple::Point(3, 3, 4));
REQUIRE(r.position(-1) == Tuple::Point(1, 3, 4));
REQUIRE(r.position(2.5) == Tuple::Point(4.5, 3, 4));
GIVEN("r <- ray(point(2, 3, 4), vector(1, 0, 0))")
{
Ray r(Tuple::Point(2, 3, 4), Tuple::Vector(1, 0, 0));
THEN("position(r,0) = point(2, 3, 4)")
{
REQUIRE(r.position(0) == Tuple::Point(2, 3, 4));
}
AND_THEN("position(r,1) == point(3, 3, 4)")
{
REQUIRE(r.position(1) == Tuple::Point(3, 3, 4));
}
AND_THEN("position(r,-1) = point(1, 3, 4)")
{
REQUIRE(r.position(-1) == Tuple::Point(1, 3, 4));
}
AND_THEN("position(r,2.5) == point(4.5, 3, 4)")
{
REQUIRE(r.position(2.5) == Tuple::Point(4.5, 3, 4));
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] a ray intersects a sphere at two points", "[Sphere]")
SCENARIO("A ray intersects a sphere at two points", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -72,7 +100,7 @@ TEST_CASE("[05][Rays] a ray intersects a sphere at two points", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] a ray intersects a sphere at a tangent", "[Sphere]")
SCENARIO("A ray intersects a sphere at a tangent", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 1, -5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -85,7 +113,7 @@ TEST_CASE("[05][Rays] a ray intersects a sphere at a tangent", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] a ray misses a sphere", "[Sphere]")
SCENARIO("A ray misses a sphere", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 2, -5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -96,7 +124,7 @@ TEST_CASE("[05][Rays] a ray misses a sphere", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] a originates inside a sphere", "[Sphere]")
SCENARIO("A originates inside a sphere", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -109,7 +137,7 @@ TEST_CASE("[05][Rays] a originates inside a sphere", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] a sphere is behind a ray", "[Sphere]")
SCENARIO("A sphere is behind a ray", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -122,7 +150,7 @@ TEST_CASE("[05][Rays] a sphere is behind a ray", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Test Sphere Object", "[Sphere]")
SCENARIO("Test Sphere Object", "[features/spheres.feature]")
{
Sphere s1;
Sphere s2 = s1;
@@ -134,7 +162,7 @@ TEST_CASE("[05][Rays] Test Sphere Object", "[Sphere]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] An intersection encapsulates t and object", "[Intersections]")
SCENARIO("An intersection encapsulates t and object", "[features/intersections.feature]")
{
Sphere s;
Intersection i(3.5, s);
@@ -145,7 +173,7 @@ TEST_CASE("[05][Rays] An intersection encapsulates t and object", "[Intersection
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Aggregating intersections", "[Intersections]")
SCENARIO("Aggregating intersections", "[features/intersections.feature]")
{
Sphere s;
Intersection i1(1, s);
@@ -159,7 +187,7 @@ TEST_CASE("[05][Rays] Aggregating intersections", "[Intersections]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Intersect set the object on the intersection", "[Intersections]")
SCENARIO("Intersect sets the object on the intersection", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -172,7 +200,7 @@ TEST_CASE("[05][Rays] Intersect set the object on the intersection", "[Intersect
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] The hit, when all intersections have positive t", "[Intersections]")
SCENARIO("The hit, when all intersections have positive t", "[features/intersections.feature]")
{
Sphere s;
Intersection i1(1, s);
@@ -186,7 +214,7 @@ TEST_CASE("[05][Rays] The hit, when all intersections have positive t", "[Inters
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] The hit, when some intersections have negative t", "[Intersections]")
SCENARIO("The hit, when some intersections have negative t", "[features/intersections.feature]")
{
Sphere s;
Intersection i1(-1, s);
@@ -200,7 +228,7 @@ TEST_CASE("[05][Rays] The hit, when some intersections have negative t", "[Inter
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] The hit, when all intersections have negative t", "[Intersections]")
SCENARIO("The hit, when all intersections have negative t", "[features/intersections.feature]")
{
Sphere s;
Intersection i1(-2, s);
@@ -214,7 +242,7 @@ TEST_CASE("[05][Rays] The hit, when all intersections have negative t", "[Inters
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] The hit is always the lowest nonnegative intersection", "[Intersections]")
SCENARIO("The hit is always the lowest nonnegative intersection", "[features/intersections.feature]")
{
Sphere s;
Intersection i1(5, s);
@@ -230,7 +258,7 @@ TEST_CASE("[05][Rays] The hit is always the lowest nonnegative intersection", "[
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Translating a ray", "[Rays]")
SCENARIO("Translating a ray", "[features/rays.feature]")
{
Ray r(Tuple::Point(1, 2, 3), Tuple::Vector(0, 1, 0));
Matrix m = Matrix::translation(3, 4, 5);
@@ -242,7 +270,7 @@ TEST_CASE("[05][Rays] Translating a ray", "[Rays]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Scaling a ray", "[Rays]")
SCENARIO("Scaling a ray", "[features/rays.feature]")
{
Ray r(Tuple::Point(1, 2, 3), Tuple::Vector(0, 1, 0));
Matrix m = Matrix::scaling(2, 3, 4);
@@ -254,15 +282,21 @@ TEST_CASE("[05][Rays] Scaling a ray", "[Rays]")
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] A sphere's default transformation", "[Sphere]")
SCENARIO("A sphere's default transformation", "[features/spheres.feature]")
{
Sphere s;
REQUIRE(s.transform() == Matrix::identity());
GIVEN("s <- Sphere()")
{
Sphere s;
THEN("s.transform = identity_matrix")
{
REQUIRE(s.transform() == Matrix::identity());
}
}
}
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Changing a sphere's transformation", "[Sphere]")
SCENARIO("Changing a sphere's transformation", "[features/spheres.feature]")
{
Sphere s;
Matrix t = Matrix::translation(2, 3, 4);
@@ -271,8 +305,8 @@ TEST_CASE("[05][Rays] Changing a sphere's transformation", "[Sphere]")
}
/* ------------------------------------------------------------------------- */
#if 0
TEST_CASE("[05][Rays] Intersecting a scaled sphere with a ray", "[Sphere]")
SCENARIO("Intersecting a scaled sphere with a ray", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
Sphere s;
@@ -283,10 +317,10 @@ TEST_CASE("[05][Rays] Intersecting a scaled sphere with a ray", "[Sphere]")
REQUIRE(xs[0].distance_t() == 3);
REQUIRE(xs[1].distance_t() == 7);
}
#endif
/* ------------------------------------------------------------------------- */
TEST_CASE("[05][Rays] Intersecting a translated sphere with a ray", "[Sphere]")
SCENARIO("Intersecting a translated sphere with a ray", "[features/spheres.feature]")
{
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
Sphere s;