From 2a2d8c3dd5bfac27f4e3c097b5d26e051fe652f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 23 Dec 2010 23:11:21 +0100 Subject: [PATCH] Template vector class. --- src/Test/CMakeLists.txt | 1 + src/Test/VectorTest.cpp | 122 ++++++++++++++++++++++++++++++ src/Test/VectorTest.h | 39 ++++++++++ src/Vector.h | 161 ++++++++++++++++++++++++++++++++++++++++ src/constants.h | 32 ++++++++ 5 files changed, 355 insertions(+) create mode 100644 src/Test/VectorTest.cpp create mode 100644 src/Test/VectorTest.h create mode 100644 src/Vector.h create mode 100644 src/constants.h diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 4bf36b9c2..2fe1df812 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1 +1,2 @@ +magnum_add_test(VectorTest VectorTest.h VectorTest.cpp) magnum_add_test(MatrixTest MatrixTest.h MatrixTest.cpp) diff --git a/src/Test/VectorTest.cpp b/src/Test/VectorTest.cpp new file mode 100644 index 000000000..87821b508 --- /dev/null +++ b/src/Test/VectorTest.cpp @@ -0,0 +1,122 @@ +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "VectorTest.h" + +#include +#include + +#include "Vector.h" +#include "constants.h" + +QTEST_APPLESS_MAIN(Magnum::Test::VectorTest) + +using namespace std; + +namespace Magnum { namespace Test { + +typedef Vector Vector4; + +void VectorTest::construct() { + float zero[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + QVERIFY(Vector4() == Vector4(zero)); +} + +void VectorTest::data() { + Vector4 v; + v.set(2, 1.0f); + v.add(2, 0.5f); + + v.set(0, 1.0f); + + float data[] = { 1.0f, 0.0f, 1.5f, 0.0f }; + QVERIFY(v == Vector4(data)); +} + +void VectorTest::bracketOperator() { + Vector4 v1, v2; + v1.set(0, 1.0f); + v1.set(1, v1.at(0)); + v1.set(3, 0.5f); + v1.add(3, 2.5f); + + v2[0] = 1.0f; + v2[1] = v2[0]; + v2[3] = 0.5f; + v2[3] += 2.5f; + + QVERIFY(v1 == v2); +} + +void VectorTest::copy() { + Vector4 v1; + + v1.set(3, 1.0f); + + Vector4 v2(v1); + Vector4 v3; + v3.set(0, 0.0f); /* this line is here so it's not optimized to Vector4 v3(v1) */ + v3 = v1; + + /* Change original */ + v1.set(2, 1.0f); + + /* Verify the copy is the same as original original */ + Vector4 original; + original.set(3, 1.0f); + + QVERIFY(v2 == original); + QVERIFY(v3 == original); +} + +void VectorTest::dot() { + float first[] = { 1.0f, 0.5f, 0.75f, 1.5f }; + float second[] = { 2.0f, 4.0f, 1.0f, 7.0f }; + + QVERIFY(Vector4(first)*Vector4(second) == 15.25f); +} + +void VectorTest::multiplyDivide() { + float vec[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + float multiplied[] = { -1.5f, -3.0f, -4.5f, -6.0f }; + + QVERIFY(Vector4(vec)*-1.5f == Vector4(multiplied)); + QVERIFY(Vector4(multiplied)/-1.5f == Vector4(vec)); +} + +void VectorTest::addSubstract() { + float a[] = { 0.5f, -7.5f, 9.0f, -11.0f }; + float b[] = { -0.5, 1.0f, 0.0f, 7.5f }; + float expected[] = { 0.0f, -6.5f, 9.0f, -3.5f }; + + QVERIFY(Vector4(a)+Vector4(b) == Vector4(expected)); + QVERIFY(Vector4(expected)-Vector4(b) == Vector4(a)); +} + +void VectorTest::length() { + float vec[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + + QVERIFY(abs(Vector4(vec).length() - 5.4772256f) < EPSILON); +} + +void VectorTest::normalized() { + float vec[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float normalized[] = { 0.5f, 0.5f, 0.5f, 0.5f }; + + QVERIFY(Vector4(vec).normalized() == Vector4(normalized)); +} + +}} diff --git a/src/Test/VectorTest.h b/src/Test/VectorTest.h new file mode 100644 index 000000000..43c7213c2 --- /dev/null +++ b/src/Test/VectorTest.h @@ -0,0 +1,39 @@ +#ifndef Magnum_Test_VectorTest_h +#define Magnum_Test_VectorTest_h +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +namespace Magnum { namespace Test { + +class VectorTest: public QObject { + Q_OBJECT + + private slots: + void construct(); + void data(); + void bracketOperator(); + void copy(); + void dot(); + void multiplyDivide(); + void addSubstract(); + void length(); + void normalized(); +}; + +}} + +#endif diff --git a/src/Vector.h b/src/Vector.h new file mode 100644 index 000000000..7b122e31b --- /dev/null +++ b/src/Vector.h @@ -0,0 +1,161 @@ +#ifndef Magnum_Vector_h +#define Magnum_Vector_h +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Vector + */ + +#include +#include + +namespace Magnum { + +/** @brief Vector */ +template class Vector { + public: + /** @brief Default constructor */ + inline Vector() { + memset(_data, 0, size*sizeof(T)); + }; + + /** + * @brief Constructor + * @param data Array of @c size length. + */ + inline Vector(const T* data) { setData(data); } + + /** @brief Copy constructor */ + inline Vector(const Vector& other) { + setData(other.data()); + } + + /** @brief Assignment operator */ + inline Vector& operator=(const Vector& other) { + setData(other.data()); + return *this; + } + + /** + * @brief Raw data + * @return Array of @c size length. + */ + inline const T* data() const { return _data; } + + /** + * @brief Set raw data + * @param data Array of @c size length. + */ + inline void setData(const T* data) { + memcpy(_data, data, size*sizeof(T)); + } + + /** @brief Value at given position */ + inline T at(size_t pos) const { return _data[pos]; } + + /** @brief Value at given position */ + inline T operator[](size_t pos) const { return _data[pos]; } + + /** @brief Reference to value at given position */ + inline T& operator[](size_t pos) { return _data[pos]; } + + /** @brief Set value at given position */ + inline void set(size_t pos, T value) { _data[pos] = value; } + + /** @brief Add value to given position */ + inline void add(size_t pos, T value) { _data[pos] += value; } + + /** @brief Equality operator */ + inline bool operator==(const Vector& other) const { + return memcmp(_data, other.data(), size*sizeof(T)) == 0; + } + + /** @brief Non-equality operator */ + inline bool operator!=(const Vector& other) const { + return !operator==(other); + } + + /** @brief Dot product */ + T operator*(const Vector& other) const { + T out; + + for(size_t i = 0; i != size; ++i) + out += at(i)*other.at(i); + + return out; + } + + /** @brief Multiply vector */ + Vector operator*(T number) const { + Vector out; + + for(size_t i = 0; i != size; ++i) + out.set(i, at(i)*number); + + return out; + } + + /** @brief Divide vector */ + Vector operator/(T number) const { + Vector out; + + for(size_t i = 0; i != size; ++i) + out.set(i, at(i)/number); + + return out; + } + + /** @brief Add two vectors */ + Vector operator+(const Vector& other) const { + Vector out; + + for(size_t i = 0; i != size; ++i) + out.set(i, at(i)+other.at(i)); + + return out; + } + + /** @brief Substract two vectors */ + Vector operator-(const Vector& other) const { + Vector out; + + for(size_t i = 0; i != size; ++i) + out.set(i, at(i)-other.at(i)); + + return out; + } + + /** @brief Vector length */ + T length() const { + T out; + for(size_t i = 0; i != size; ++i) + out += pow(at(i), 2); + + return sqrt(out); + } + + /** @brief Normalized vector (of length 1) */ + Vector normalized() const { + return *this/length(); + } + + private: + T _data[size]; +}; + +} + +#endif diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 000000000..77d38e3ea --- /dev/null +++ b/src/constants.h @@ -0,0 +1,32 @@ +#ifndef Magnum_constants_h +#define Magnum_constants_h +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Constants + */ + +namespace Magnum { + +/** @brief Pi */ +#define PI 3.1415926535 + +/** @brief Maximal tolerance when comparing doubles */ +#define EPSILON 1.0e-8 + +} + +#endif