diff --git a/source/include/tuples.h b/source/include/tuples.h new file mode 100644 index 0000000..95b475a --- /dev/null +++ b/source/include/tuples.h @@ -0,0 +1,59 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Tuples header + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#ifndef DORAYME_TUPLES_H +#define DORAYME_TUPLES_H + +#include + +class Tuple +{ +public: + double x, y, z, w; + +public: + Tuple(double x, double y, double z) : x(x), y(y), z(z), w(0.0) {}; + Tuple(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {}; + bool isPoint() { return (this->w == 1.0); }; + bool isVector() { return (this->w == 0.0); }; + + bool operator==(const Tuple &b) const { return double_equal(this->x, b.x) && + double_equal(this->y, b.y) && + double_equal(this->z, b.z) && + double_equal(this->w, b.w); }; + + Tuple operator+(const Tuple &b) const { return Tuple(this->x + b.x, this->y + b.y, + this->z + b.z, this->w + b.w); }; + + Tuple operator-(const Tuple &b) const { return Tuple(this->x - b.x, this->y - b.y, + this->z - b.z, this->w - b.w); }; + Tuple operator-() const { return Tuple(-this->x, -this->y, -this->z, -this->w); }; + Tuple operator*(const double &b) const { return Tuple(this->x * b, this->y * b, + this->z * b, this->w * b); }; + Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b, + this->z / b, this->w / b); }; + + double magnitude(); + Tuple normalise(); + double dot(const Tuple &b); +}; + +class Point: public Tuple +{ +public: + Point(double x, double y, double z) : Tuple(x, y, z, 1.0) {}; +}; + +class Vector: public Tuple +{ +public: + Vector(double x, double y, double z) : Tuple(x, y, z, 0.0) {}; + Vector cross(const Vector &b) const; +}; + +#endif /* DORAYME_TUPLES_H */ diff --git a/source/tuples.cpp b/source/tuples.cpp new file mode 100644 index 0000000..daa7b96 --- /dev/null +++ b/source/tuples.cpp @@ -0,0 +1,35 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Tuples implementation + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include + +#include + + +double Tuple::magnitude() +{ + return sqrt(pow(this->x, 2) + pow(this->y, 2) + pow(this->z, 2) + pow(this->w, 2)); +} + +Tuple Tuple::normalise() +{ + double mag = this->magnitude(); + return Tuple(this->x / mag, this->y / mag, this->z / mag, this->w / mag); +} + +double Tuple::dot(const Tuple &b) +{ + return this->x * b.x + this->y * b.y + this->z * b.z + this->w * b.w; +} + +Vector Vector::cross(const Vector &b) const +{ + return Vector(this->y * b.z - this->z * b.y, + this->z * b.x - this->x * b.z, + this->x * b.y - this->y * b.x); +} \ No newline at end of file diff --git a/tests/tuples_test.cpp b/tests/tuples_test.cpp new file mode 100644 index 0000000..127e47e --- /dev/null +++ b/tests/tuples_test.cpp @@ -0,0 +1,183 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Tuples tests + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include +#include + +TEST(TuplesTests, Tuple_With_w_equal_1_and_is_point) +{ + Tuple a = Tuple(4.3, -4.2, 3.1, 1.0); + + ASSERT_EQ(a.x, 4.3); + ASSERT_EQ(a.y, -4.2); + ASSERT_EQ(a.z, 3.1); + ASSERT_EQ(a.w, 1.0); + ASSERT_TRUE(a.isPoint()); + ASSERT_FALSE(a.isVector()); +} + +TEST(TuplesTests, Tuple_With_w_equal_0_and_is_vector) +{ + Tuple a = Tuple(4.3, -4.2, 3.1, 0.0); + + ASSERT_EQ(a.x, 4.3); + ASSERT_EQ(a.y, -4.2); + ASSERT_EQ(a.z, 3.1); + ASSERT_EQ(a.w, 0.0); + ASSERT_FALSE(a.isPoint()); + ASSERT_TRUE(a.isVector()); +} + +TEST(TuplesTests, Point_create_tuples_with_w_equal_1) +{ + Tuple a = Point(4, -4, 3); + + ASSERT_EQ(a, Tuple(4, -4, 3, 1)); +} + +TEST(TuplesTests, Vector_create_tuples_with_w_equal_0) +{ + Tuple a = Vector(4, -4, 3); + + ASSERT_EQ(a, Tuple(4, -4, 3, 0)); +} + +TEST(TuplesTests, Adding_two_tuples) +{ + Tuple a1 = Tuple(3, -2, 5, 1); + Tuple a2 = Tuple(-2, 3, 1, 0); + + ASSERT_EQ(a1 + a2, Tuple(1, 1, 6, 1)); +} + +TEST(TuplesTests, Substracting_two_points) +{ + Point p1 = Point(3, 2, 1); + Point p2 = Point(5, 6, 7); + + ASSERT_EQ(p1 - p2, Vector(-2, -4, -6)); +} + +TEST(TuplesTests, Substracting_a_vector_from_a_point) +{ + Point p = Point(3, 2, 1); + Vector v = Vector(5, 6, 7); + + ASSERT_EQ(p - v, Point(-2, -4, -6)); +} + +TEST(TuplesTests, Substracting_two_vectors) +{ + Vector v1 = Vector(3, 2, 1); + Vector v2 = Vector(5, 6, 7); + + ASSERT_EQ(v1 - v2, Vector(-2, -4, -6)); +} + +TEST(TuplesTests, Substracting_a_vector_from_zero_vector) +{ + Vector zero = Vector(0, 0, 0); + Vector v = Vector(1, -2, 3); + + ASSERT_EQ(zero - v, Vector(-1, 2, -3)); +} + +TEST(TuplesTests, Negating_a_tuple) +{ + Tuple a = Tuple(1, -2, 3, -4); + + ASSERT_EQ(-a, Tuple(-1, 2, -3, 4)); +} + +TEST(TuplesTests, Multiplying_a_tuple_by_a_scalar) +{ + Tuple a = Tuple(1, -2, 3, -4); + + ASSERT_EQ(a * 3.5, Tuple(3.5, -7, 10.5, -14)); +} + +TEST(TuplesTests, Multiplying_a_tuple_by_a_fraction) +{ + Tuple a = Tuple(1, -2, 3, -4); + + ASSERT_EQ(a * 0.5, Tuple(0.5, -1, 1.5, -2)); +} + +TEST(TuplesTests, Dividing_a_tuple_by_a_scalar) +{ + Tuple a = Tuple(1, -2, 3, -4); + + ASSERT_EQ(a / 2, Tuple(0.5, -1, 1.5, -2)); +} + +TEST(TuplesTests, Computing_the_magnitude_of_vector_1_0_0) +{ + Vector v = Vector(1, 0, 0); + + ASSERT_EQ(v.magnitude(), 1); +} + +TEST(TuplesTests, Computing_the_magnitude_of_vector_0_1_0) +{ + Vector v = Vector(0, 1, 0); + + ASSERT_EQ(v.magnitude(), 1); +} + +TEST(TuplesTests, Computing_the_magnitude_of_vector_0_0_1) +{ + Vector v = Vector(0, 0, 1); + + ASSERT_EQ(v.magnitude(), 1); +} + +TEST(TuplesTests, Computing_the_magnitude_of_vector_1_2_3) +{ + Vector v = Vector(1, 2, 3); + + ASSERT_EQ(v.magnitude(), sqrt(14)); +} + +TEST(TuplesTests, Computing_the_magnitude_of_vector_n1_n2_n3) +{ + Vector v = Vector(-1, -2, -3); + + ASSERT_EQ(v.magnitude(), sqrt(14)); +} + +TEST(TuplesTests, Nomilise_vector_4_0_0_give_1_0_0) +{ + Vector v = Vector(4, 0, 0); + + ASSERT_EQ(v.normalise(), Vector(1, 0, 0)); +} + +TEST(TuplesTests, Nomilise_vector_1_2_3) +{ + Vector v = Vector(1, 2, 3); + + ASSERT_EQ(v.normalise(), Vector(1 / sqrt(14), 2 / sqrt(14), 3 / sqrt(14))); +} + +TEST(TuplesTests, Dot_product_of_two_tuples) +{ + Vector a = Vector(1, 2, 3); + Vector b = Vector(2, 3, 4); + + ASSERT_EQ(a.dot(b), 20); +} + +TEST(TuplesTests, Cross_product_of_two_vector) +{ + Vector a = Vector(1, 2, 3); + Vector b = Vector(2, 3, 4); + + ASSERT_EQ(a.cross(b), Vector(-1, 2, -1)); + ASSERT_EQ(b.cross(a), Vector(1, -2, 1)); +}