commit d2076b82264a085a507a707f622419fb641503fd Author: william Date: Mon Apr 1 17:18:18 2024 -0400 Init diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e0c6fc2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.15) +project(GTI320-labos) + +#-------------------------------------------------- +# Add google test and setup build +#-------------------------------------------------- +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.11.0 +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# No need for GMock +set( BUILD_GMOCK OFF CACHE BOOL "" FORCE) +set( INSTALL_GTEST OFF CACHE BOOL "" FORCE) +set( GTEST_FORCE_SHARED_CRT ON CACHE BOOL "" FORCE) +set( GTEST_DISABLE_PTHREADS ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +#-------------------------------------------------- +# Add nanogui +#-------------------------------------------------- +include(FetchContent) +FetchContent_Declare( + nanogui + GIT_REPOSITORY https://github.com/mitsuba-renderer/nanogui.git + GIT_PROGRESS TRUE +) +set( NANOGUI_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set( NANOGUI_BUILD_SHARED OFF CACHE BOOL "" FORCE) +set( NANOGUI_BUILD_PYTHON OFF CACHE BOOL "" FORCE) +set( NANOGUI_USE_OPENGL ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(nanogui) + +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +include_directories(${CMAKE_SOURCE_DIR}/labo01/src ${COMMON_INCLUDES}) +add_subdirectory(labo01) +add_subdirectory(labo_ik) + +if( MSVC ) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT labo_ik) +endif() + diff --git a/labo01/CMakeLists.txt b/labo01/CMakeLists.txt new file mode 100644 index 0000000..26b203f --- /dev/null +++ b/labo01/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.15) + +project(labo01) + +# Setup language requirements +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Add .cpp and .h files +file(GLOB_RECURSE TESTS_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" CONFIGURE_DEPENDS "tests/*.cpp") +file(GLOB_RECURSE MAIN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" CONFIGURE_DEPENDS "src/*.h") +add_executable(labo01 main.cpp ${MAIN_SOURCES} ${TESTS_SOURCES}) + +# Add linking information for Google Test +target_link_libraries(labo01 gtest) + + +# Set labo01 as the startup project for Visual Studio +if( MSVC ) + set_property(TARGET labo01 PROPERTY VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/labo01) +endif() + diff --git a/labo01/main.cpp b/labo01/main.cpp new file mode 100644 index 0000000..5b3200c --- /dev/null +++ b/labo01/main.cpp @@ -0,0 +1,28 @@ +/** + * @file main.cpp + * + * @brief Execute unit tests for a simple linear algebra library. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include + +int main(int argc, char** argv) +{ + // Executer tous les tests unitaires. + // + // Les tests sont écrites dans les fichiers: + // tests/Tests1a.cpp + // tests/Tests1b.cpp + // tests/TestsSupplementaire1a.cpp + // tests/TestsSupplementaire1b.cpp + // + ::testing::InitGoogleTest(&argc, argv); + const int ret = RUN_ALL_TESTS(); + + return ret; +} diff --git a/labo01/src/DenseStorage.h b/labo01/src/DenseStorage.h new file mode 100644 index 0000000..cfa95e2 --- /dev/null +++ b/labo01/src/DenseStorage.h @@ -0,0 +1,220 @@ +#pragma once + +/** + * @file DenseStorage.h + * + * @brief Stockage dense pour des données à taille fixe ou dynamique. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include +#include + +namespace gti320 +{ + enum SizeType { Dynamic = -1 }; + + /** + * Stockage à taille fixe. + * + * Le nombre de données à stocker est connu au moment de la compilation. + * Ce nombre est donné par le paramètre de patron : _Size + * + * Un tampon (tableau) de taille `_Size_` est alloué sur la pile d'exécution. + */ + template + class DenseStorage + { + private: + + // TODO déclarer une variable m_data et allouer la mémoire pour y stocker _Size éléments + _Scalar* m_data; // <-- Ceci n'est pas bon, à modifier + + public: + + /** + * Constructeur par défaut + */ + DenseStorage() { } + + /** + * Constructeur de copie + */ + DenseStorage(const DenseStorage& other) + { + memcpy(m_data, other.m_data, sizeof(m_data)); + } + + /** + * Constructeur avec taille spécifiée. + * Doit être la même que la taille spécifiée dans le patron + * + */ + explicit DenseStorage(int _size) + { + assert(_size > 0 && _size == _Size); + } + + /** + * Constructeur avec taille (_size) et données initiales (_data). + */ + explicit DenseStorage(const _Scalar* _data, int _size) + { + assert(_size >= 0 && _size == _Size); + memcpy(m_data, _data, sizeof(_Scalar) * _size); + } + + /** + * Opérateur de copie + */ + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + assert(other.size() == _Size); + memcpy(m_data, other.m_data, sizeof(m_data)); + } + return *this; + } + + static int size() { return _Size; } + + /** + * Redimensionne le stockage pour qu'il contienne `size` élément. + */ + void resize(int size) + { + // Ne rien faire. Invalide pour les matrices à taille fixe. + } + + /** + * Mets tous les éléments à zéro. + */ + void setZero() + { + memset(m_data, 0, sizeof(_Scalar) * _Size); + } + + /** + * Accès au tampon de données (en lecteur seulement) + */ + const _Scalar* data() const + { + return m_data; + } + + /** + * Accès au tampon de données (pour lecture et écriture) + */ + _Scalar* data() + { + return m_data; + } + }; + + + + /** + * Stockage à taille dynamique. + * + * Le nombre de données à stocker est déterminé à l'exécution. + * Un tampon de la taille demandée doit être alloué sur le tas via + * l'opérateur `new []` et la mémoire doit être libérée avec `delete[]` + */ + template + class DenseStorage<_Scalar, Dynamic> + { + private: + _Scalar* m_data; + int m_size; + + public: + + /** + * Constructeur par défaut + */ + DenseStorage() : m_data(nullptr), m_size(0) {} + + /** + * Constructeur avec taille spécifiée + */ + explicit DenseStorage(int _size) : m_data(nullptr), m_size(_size) + { + // TODO allouer un tampon pour stocker _size éléments de type _Scalar. + + // TODO initialiser ce tampon à zéro. + } + + /** + * Constructeur de copie + */ + DenseStorage(const DenseStorage& other) + : m_data(nullptr) + , m_size(other.m_size) + { + // TODO allouer un tampon pour stocker _size éléments de type _Scalar. + + // TODO copier other.m_data dans m_data. + + } + + /** + * Opérateur de copie + */ + DenseStorage& operator=(const DenseStorage& other) + { + // TODO implémenter ! + return *this; + } + + /** + * Destructeur + */ + ~DenseStorage() + { + // TODO libérer la mémoire allouée + + } + + /** + * Retourne la taille du tampon + */ + inline int size() const { return m_size; } + + /** + * Redimensionne le tampon alloué pour le stockage. + * La mémoire qui n'est plus utilisée doit être libérée. + * + * Note :​ Toutes opérations de redimensionnement entraînent une réallocation de mémoire. + * Il n’est pas pertinent de copier les données car le résultat serait de toute façon incohérent. + */ + void resize(int _size) + { + // TODO redimensionner la mémoire allouée + + } + + /** + * Met tous les éléments à zéro. + */ + void setZero() + { + // TODO implémenter ! + } + + /** + * Accès au tampon de données (en lecteur seulement) + */ + const _Scalar* data() const { return m_data; } + + /** + * Accès au tampon de données (pour lecture et écriture) + */ + _Scalar* data() { return m_data; } + }; + +} diff --git a/labo01/src/Math3D.h b/labo01/src/Math3D.h new file mode 100644 index 0000000..d58e333 --- /dev/null +++ b/labo01/src/Math3D.h @@ -0,0 +1,110 @@ +#pragma once + +/** + * @file Math3D.h + * + * @brief Fonctions pour l'intinialisation et la manipulation de matrices de + * rotation, des matrices de transformations en coordonnées homogènes et les + * vecteurs 3D. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" +#include "Operators.h" + +#ifndef _USE_MATH_DEFINES +#define _USE_MATH_DEFINES +#endif + +#include + + +namespace gti320 { + + // Deux types de vecteurs 3D considérés ici + typedef Vector Vector3d; + typedef Vector Vector3f; + + // Dans le cadre de ce projet, nous considérons seulement deux + // cas : + // + // - les rotations + // - les translations + // + // Deux types de matrices en coordonnées homogèes : + typedef Matrix Matrix4d; + typedef Matrix Matrix4f; + // + // Deux types de matrices pour les rotations + typedef Matrix Matrix3d; + typedef Matrix Matrix3f; + + /** + * Initialise et retourne la matrice identité + */ + template<> + inline void Matrix4d::setIdentity() + { + // TODO affecter la valeur 0.0 partout, sauf sur la diagonale principale où c'est 1.0. + // Note: ceci est une redéfinition d'une fonction membre! + } + + /** + * Calcul de la matrice inverse, SPÉCIALISÉ pour le cas d'une matrice de + * transformation en coordonnées homogènes. + * + * TODO (vous pouvez supposer qu'il s'agit d'une matrice de transformation + * en coordonnées homogènes) + */ + template<> + inline Matrix4d Matrix4d::inverse() const + { + // TODO : implémenter + return Matrix4d(); // Pas bon, à changer + } + + /** + * Calcul de la matrice inverse, SPÉCIALISÉ pour le cas d'une matrice de rotation. + * + * (vous pouvez supposer qu'il s'agit d'une matrice de rotation) + */ + template<> + inline Matrix3d Matrix3d::inverse() const + { + // TODO : implémenter + return Matrix3d(); + } + + + /** + * Multiplication d'une matrice 4x4 avec un vecteur 3D où la matrice + * représente une transformation en coordonnées homogène. + */ + template + Vector<_Scalar, 3> operator*(const Matrix<_Scalar, 4, 4, ColumnStorage>& A, const Vector<_Scalar, 3>& v) + { + // TODO : implémenter + return Vector<_Scalar, 3>(); // pas bon, à changer + } + + + /** + * Initialise et retourne la matrice de rotation définie par les angles + * d'Euler XYZ exprimés en radians. + * + * La matrice doit correspondre au produit : Rz*Ry*Rx. + */ + template + static Matrix<_Scalar, 3, 3> makeRotation(_Scalar x, _Scalar y, _Scalar z) + { + // TODO : implémenter + + return Matrix<_Scalar, 3, 3>(); // pas bon, à changer + } + +} diff --git a/labo01/src/Matrix.h b/labo01/src/Matrix.h new file mode 100644 index 0000000..d3f83ec --- /dev/null +++ b/labo01/src/Matrix.h @@ -0,0 +1,350 @@ +#pragma once + +/** + * @file Matrix.h + * + * @brief Implémentation de matrices simples. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "MatrixBase.h" + +namespace gti320 +{ + enum StorageType + { + ColumnStorage = 0, + RowStorage = 1 + }; + + // Déclaration avancée + template class SubMatrix; + + /** + * Classe Matrix spécialisé pour le cas générique. (defaut par colonne) + * + * (le cas d'un stockage par ligne fait l'objet d'une spécialisation de patron, voir plus bas) + */ + template + class Matrix : public MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile> { + public: + + /** + * Constructeur par défaut + */ + Matrix() : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>() { } + + /** + * Constructeur de copie + */ + Matrix(const Matrix& other) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(other) { } + + /** + * Constructeur avec spécification du nombre de ligne et de colonnes + */ + explicit Matrix(int _rows, int _cols) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(_rows, _cols) { } + + /** + * Destructeur + */ + ~Matrix() { } + + /** + * Opérateur de copie à partir d'une sous-matrice. + * + * Exemple : + * Matrix<...> A(...); + * Matrix<...> B(...); + * B = A.block(i,j,m,n); + + */ + template + Matrix& operator= (const SubMatrix<_OtherScalar, OtherRows, _OtherCols, _OtherStorage>& submatrix) + { + // TODO copier les données de la sous-matrice. + // Note : si les dimensions ne correspondent pas, la matrice doit être redimensionnée. + // Vous pouvez présumer qu'il s'agit d'un stockage par colonnes. + return *this; + } + + /** + * Accesseur à une entrée de la matrice (lecture seule) + */ + _Scalar operator()(int i, int j) const + { + // TODO implementer + return (double)(i + j); + } + + /** + * Accesseur à une entrée de la matrice (lecture ou écriture) + */ + _Scalar& operator()(int i, int j) + { + // TODO implementer + // Indice : l'implémentation est identique à celle de la fonction précédente. + _Scalar x = (double)(i + j); + return x; + } + + /** + * Crée une sous-matrice pour un block de taille (rows, cols) à partir de l'index (i,j). + */ + SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType> block(int i, int j, int rows, int cols) const + { + return SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType>(*this, i, j, rows, cols); + } + + /** + * Calcule l'inverse de la matrice + */ + Matrix inverse() const + { + // Do nothing. + return *this; + } + + /** + * Retourne la transposée de la matrice + */ + template + Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> transpose() const + { + // TODO calcule et retourne la transposée de la matrice. + + return Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage>(); // pas bon, à changer + } + + /** + * Affecte l'identité à la matrice + */ + inline void setIdentity() + { + // TODO affecter la valeur 0.0 partour, sauf sur la diagonale principale où c'est 1.0.. + // Votre implémentation devrait aussi fonctionner pour des matrices qui ne sont pas carrées. + } + + }; + + /** + * Classe Matrix spécialisée pour un stockage par lignes + */ + template + class Matrix< _Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage> : public MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile> { + + public: + /** + * Constructeur par défaut + */ + Matrix() : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>() { } + + /** + * Constructeur de copie + */ + Matrix(const Matrix& other) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(other) { } + + /** + * Constructeur avec spécification du nombre de ligne et de colonnes + */ + explicit Matrix(int rows, int cols) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(rows, cols) { } + + /** + * Destructeur + */ + ~Matrix() { } + + /** + * Opérateur de copie à partir d'une sous-matrice. + * + * Exemple : + * Matrix<...> A(...); + * Matrix<...> B(...); + * B = A.block(i,j,m,n); + */ + template + Matrix& operator= (const SubMatrix<_OtherScalar, OtherRows, _OtherCols, _OtherStorage>& submatrix) + { + // TODO copier les données de la sous-matrice. + // Note : si les dimensions ne correspondent pas, la matrice doit être redimensionnée. + // Vous pouvez présumer qu'il s'agit d'un stockage par lignes. + return *this; + } + + /** + * Accesseur à une entrée de la matrice (lecture seule) + */ + _Scalar operator()(int i, int j) const + { + // TODO implementer + return 0.0; + } + + /** + * Accesseur à une entrée de la matrice (lecture ou écriture) + */ + _Scalar& operator()(int i, int j) + { + // TODO implementer + _Scalar x = 0.0; + return x; + } + + /** + * Crée une sous-matrice pour un block de taille (rows, cols) à partir de l'index (i,j). + */ + SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage> block(int i, int j, int rows, int cols) const { + return SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage>(*this, i, j, rows, cols); + } + + /** + * Calcule l'inverse de la matrice + */ + Matrix inverse() const + { + // Do nothing. + return *this; + } + + /** + * Retourne la transposée de la matrice + */ + Matrix<_Scalar, _ColsAtCompile, _RowsAtCompile, ColumnStorage> transpose() const + { + // TODO calcule et retourne la transposée de la matrice. + // Optimisez cette fonction en tenant compte du type de stockage utilisé. + + return Matrix<_Scalar, _ColsAtCompile, _RowsAtCompile, ColumnStorage>(); + } + + /** + * Affecte l'identité à la matrice + */ + inline void setIdentity() + { + // TODO affecter la valeur 0.0 partour, sauf sur la diagonale principale où c'est 1.0.. + // Votre implémentation devrait aussi fonctionner pour des matrices qui ne sont pas carrées. + } + + }; + + /** + * Classe pour accéder à une sous-matrice. + * + * Un sous-matrice ne copie pas les données. Au lieu de cela, elle conserve une + * référence à la matrice originale. + */ + template + class SubMatrix + { + private: + // Référence à la matrice originale + Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType>& m_matrix; + + // Constructeur par défaut (privé) + SubMatrix() {} + + // (i,j) est le coin supérieur gauche de la sous-matrice + int m_i; // Décalage en ligne + int m_j; // Décalage en colonne + + // la sous-matrice est de dimension : m_rows x m_cols + int m_rows; // Hauteur de la sous-matrice (nombre de lignes) + int m_cols; // Largeur de la sous-matrice (nombre de colonnes) + + public: + + /** + * Constructeur à partir d'une référence en lecture seule à une matrice. + */ + SubMatrix(const Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType>& _matrix, int _i, int _j, int _rows, int _cols) : + m_matrix(const_cast&>(_matrix)), + m_i(_i), m_j(_j), m_rows(_rows), m_cols(_cols) + { + } + + /** + * Constructeur à partir d'une référence en lecture et écriture à une matrice. + */ + explicit SubMatrix(Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType>& _matrix, int _i, int _j, int _rows, int _cols) : + m_matrix(_matrix), + m_i(_i), m_j(_j), m_rows(_rows), m_cols(_cols) + { + + } + + /** + * Constructeur de copie + */ + SubMatrix(const SubMatrix& other) : + m_matrix(other.m_matrix), + m_i(other.m_i), m_j(other.m_j), m_rows(other.m_rows), m_cols(other.m_cols) + { + } + + /** + * Destructeur + */ + ~SubMatrix() { } + + /** + * Opérateur de copie (à partir d'une matrice) + * + * Copies toutes les entrées de la matrice dans la sous-matrice. + * + * Note : la taille de la matrice doit correspondre à la taille de la + * sous-matrice. + */ + template + SubMatrix& operator= (const Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage>& matrix) + { + // TODO Cpopie les valeurs de la matrice dans la sous-matrice. + // Note les dimensions de la matrice doivent correspondre à celle de + // la sous-matrice. + return *this; + } + + /** + * Accesseur aux entrées de la sous-matrice (lecture seule) + * + * Note : il faut s'assurer que les indices respectent la taille de la + * sous-matrice + */ + _Scalar operator()(int i, int j) const + { + // TODO implémenter + return 0.0; + } + + /** + * Accesseur aux entrées de la sous-matrice (lecture et écriture) + * + * Note : il faut s'assurer que les indices respectent la taille de la + * sous-matrice + */ + _Scalar& operator()(int i, int j) + { + // TODO implémenter + _Scalar x = 0.0; + return x; + } + + /** + * Retourne la transposée de la sous-matrice sous la forme d'une matrice. + */ + template + Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> transpose() const + { + // TODO implémenter + return Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage>(); + } + + inline int rows() const { return m_rows; } + inline int cols() const { return m_cols; } + + }; + +} diff --git a/labo01/src/MatrixBase.h b/labo01/src/MatrixBase.h new file mode 100644 index 0000000..2e5c46f --- /dev/null +++ b/labo01/src/MatrixBase.h @@ -0,0 +1,357 @@ +#pragma once + +/** + * @file MatrixBase.h + * + * @brief Classe contenant les éléments de base des matrices et des vecteurs. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "DenseStorage.h" + +namespace gti320 +{ + + /** + * Classe de base pour les matrices et vecteurs à taille fixe. + */ + template + class MatrixBase + { + protected: + DenseStorage<_Scalar, _Rows* _Cols> m_storage; + + public: + + typedef _Scalar Scalar; + + /** + * Constructeur par défaut + */ + MatrixBase() : m_storage() { } + + /** + * Constructeur de copie + */ + MatrixBase(const MatrixBase& other) : m_storage(other.m_storage) { } + + explicit MatrixBase(int _rows, int _cols) : m_storage() { } + + /** + * Destructeur + */ + ~MatrixBase() { } + + + /** + * Redimensionne la matrice + */ + void resize(int _rows, int _cols) + { + // Ne rien faire. + } + + /** + * Opérateur de copie + */ + MatrixBase& operator=(const MatrixBase& other) + { + if (this != &other) + { + m_storage = other.m_storage; + } + return *this; + } + + inline void setZero() { m_storage.setZero(); } + static inline int cols() { return _Cols; } + static inline int rows() { return _Rows; } + + /** + * Accès à la donnée membre de stockage (en lecture seule) + */ + const DenseStorage<_Scalar, _Rows* _Cols>& storage() const + { + return m_storage; + } + + /** + * Nombre d'éléments stockés dans le tampon. + */ + inline int size() const + { + return m_storage.size(); + } + + /** + * Accès au tampon de données ((lecture seule)) + */ + const _Scalar* data() const + { + return m_storage.data(); + } + + }; + + /** + * Classe de base pour les matrices avec un nombre de lignes dynamique et un + * nombre fixe de colonnes. + */ + template + class MatrixBase<_Scalar, Dynamic, _Cols> + { + protected: + + DenseStorage<_Scalar, Dynamic> m_storage; + int m_rows; + + public: + + typedef _Scalar Scalar; + + /** + * Constructeur par défaut + */ + MatrixBase() : m_storage(), m_rows(0) { } + + explicit MatrixBase(int _rows, int _cols) : m_storage(_rows* _Cols), m_rows(_rows) { } + + /** + * Constructeur de copie + */ + MatrixBase(const MatrixBase& other) : m_storage(other.m_storage), m_rows(other.m_rows) { } + + /** + * Destructeur + */ + ~MatrixBase() { } + + /** + * Opérateur de copie + */ + MatrixBase& operator=(const MatrixBase& other) + { + if (this != &other) + { + m_storage = other.m_storage; + m_rows = other.m_rows; + } + return *this; + } + + /** + * Redimensionne la matrice + */ + void resize(int _rows, int _cols) + { + assert(_cols == _Cols); + m_storage.resize(_rows * _Cols); + m_rows = _rows; + } + + inline void setZero() { m_storage.setZero(); } + + static inline int cols() { return _Cols; } + inline int rows() const { return m_rows; } + + /** + * Accès à la donnée membre de stockage (en lecture seule) + */ + const DenseStorage<_Scalar, Dynamic>& storage() const + { + return m_storage; + } + + /** + * Nombre d'éléments stockés dans le tampon. + */ + inline int size() const + { + return m_storage.size(); + } + + /** + * Accès au tampon de données ((lecture seule)) + */ + const _Scalar* data() const + { + return m_storage.data(); + } + }; + + /** + * Classe de base pour les matrices avec un nombre fixe de lignes et un + * nombre de colonnes dynamique. + */ + template + class MatrixBase<_Scalar, _Rows, Dynamic> + { + protected: + + DenseStorage<_Scalar, Dynamic> m_storage; + int m_cols; + + public: + + typedef _Scalar Scalar; + + /** + * Constructeur par défaut + */ + MatrixBase() : m_storage() { } + + explicit MatrixBase(int _rows, int _cols) : m_storage(_rows* _cols), m_cols(_cols) { } + + /** + * Constructeur de copie + */ + MatrixBase(const MatrixBase& other) : m_storage(other.m_storage), m_cols(other.m_cols) { } + + /** + * Destructeur + */ + ~MatrixBase() { } + + /** + * Opérateur de copie + */ + MatrixBase& operator=(const MatrixBase& other) + { + if (this != &other) { + m_storage = other.m_storage; + m_cols = other.m_cols; + } + + return *this; + } + + /** + * Redimensionne la matrice + */ + void resize(int _rows, int _cols) + { + assert(_rows == _Rows); + m_storage.resize(_Rows * _cols); + m_cols = _cols; + } + + inline void setZero() { m_storage.setZero(); } + + inline int cols() const { return m_cols; } + static inline int rows() { return _Rows; } + + /** + * Accès à la donnée membre de stockage (en lecture seule) + */ + const DenseStorage<_Scalar, Dynamic>& storage() const + { + return m_storage; + } + + /** + * Nombre d'éléments stockés dans le tampon. + */ + inline int size() const + { + return m_storage.size(); + } + + /** + * Accès au tampon de données ((lecture seule)) + */ + const _Scalar* data() const + { + return m_storage.data(); + } + }; + + /** + * Classe de base pour les matrices avec un nombre de lignes et de colonnes + * dynamiques. + */ + template + class MatrixBase<_Scalar, Dynamic, Dynamic> + { + protected: + + DenseStorage<_Scalar, Dynamic> m_storage; + int m_cols; + int m_rows; + + public: + typedef _Scalar Scalar; + + /** + * Constructeur par défaut + */ + MatrixBase() : m_storage(), m_rows(0), m_cols(0) { } + + explicit MatrixBase(int _rows, int _cols) : m_storage(_rows* _cols), m_rows(_rows), m_cols(_cols) { } + + /** + * Constructeur de copie + */ + MatrixBase(const MatrixBase& other) : m_storage(other.m_storage), m_rows(other.m_rows), m_cols(other.m_cols) { } + + /** + * Destructeur + */ + ~MatrixBase() { } + + /** + * Opérateur de copie + */ + MatrixBase& operator=(const MatrixBase& other) + { + if (this != &other) + { + resize(other.m_rows, other.m_cols); + m_storage = other.m_storage; + } + return *this; + } + + /** + * Redimensionne la matrice + */ + void resize(int _rows, int _cols) + { + m_storage.resize(_rows * _cols); + m_rows = _rows; + m_cols = _cols; + } + + inline void setZero() { m_storage.setZero(); } + + inline int cols() const { return m_cols; } + inline int rows() const { return m_rows; } + + /** + * Accès à la donnée membre de stockage (en lecture seule) + */ + const DenseStorage<_Scalar, Dynamic>& storage() const + { + return m_storage; + } + + /** + * Nombre d'éléments stockés dans le tampon. + */ + inline int size() const + { + return m_storage.size(); + } + + /** + * Accès au tampon de données ((lecture seule)) + */ + const _Scalar* data() const + { + return m_storage.data(); + } + }; +} diff --git a/labo01/src/Operators.h b/labo01/src/Operators.h new file mode 100644 index 0000000..7fa2f3b --- /dev/null +++ b/labo01/src/Operators.h @@ -0,0 +1,179 @@ +#pragma once + +/** + * @file Operators.h + * + * @brief Opérateurs arithmétiques pour les matrices et les vecteurs. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" + + /** + * Implémentation de divers opérateurs arithmétiques pour les matrices et les vecteurs. + */ +namespace gti320 { + + /** + * Multiplication : Matrice * Matrice (générique) + */ + template + Matrix<_Scalar, RowsA, ColsB> operator*(const Matrix<_Scalar, RowsA, ColsA, StorageA>& A, const Matrix<_Scalar, RowsB, ColsB, StorageB>& B) + { + // TODO implémenter + return Matrix<_Scalar, RowsA, ColsB>(); + } + + /** + * Multiplication : Matrice (colonne) * Matrice (ligne) + * + * Spécialisation de l'opérateur de multiplication pour le cas où les matrices + * ont un stockage à taille dynamique et où la matrice de gauche utilise un + * stockage par colonnes et celle de droite un stockage par lignes. + */ + template + Matrix<_Scalar, Dynamic, Dynamic> operator*(const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& A, const Matrix<_Scalar, Dynamic, Dynamic, RowStorage>& B) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic>(); + } + + /** + * Multiplication : Matrice (ligne) * Matrice (colonne) + * + * Spécialisation de l'opérateur de multiplication pour le cas où les matrices + * ont un stockage à taille dynamique et où la matrice de gauche utilise un + * stockage par lignes et celle de droite un stockage par colonnes. + */ + template + Matrix<_Scalar, Dynamic, Dynamic> operator*(const Matrix<_Scalar, Dynamic, Dynamic, RowStorage>& A, const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& B) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic>(); + } + + + /** + * Addition : Matrice + Matrice (générique) + */ + template + Matrix<_Scalar, Rows, Cols> operator+(const Matrix<_Scalar, Rows, Cols, StorageA>& A, const Matrix<_Scalar, Rows, Cols, StorageB>& B) + { + // TODO : implémenter + return Matrix<_Scalar, Rows, Cols>(); + } + + /** + * Addition : Matrice (colonne) + Matrice (colonne) + * + * Spécialisation de l'opérateur d'addition pour le cas où les deux matrices + * sont stockées par colonnes. + */ + template + Matrix<_Scalar, Dynamic, Dynamic> operator+(const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& A, const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& B) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic>(); + } + + /** + * Addition : Matrice (ligne) + Matrice (ligne) + * + * Spécialisation de l'opérateur d'addition pour le cas où les deux matrices + * sont stockées par lignes. + */ + template + Matrix<_Scalar, Dynamic, Dynamic, RowStorage> operator+(const Matrix<_Scalar, Dynamic, Dynamic, RowStorage>& A, const Matrix<_Scalar, Dynamic, Dynamic, RowStorage>& B) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic, RowStorage>(); + } + + /** + * Multiplication : Scalaire * Matrice (colonne) + * + * Spécialisation de l'opérateur de multiplication par un scalaire pour le + * cas d'une matrice stockée par colonnes. + */ + template + Matrix<_Scalar, _Rows, _Cols, ColumnStorage> operator*(const _Scalar& a, const Matrix<_Scalar, _Rows, _Cols, ColumnStorage>& A) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic>(); + } + + /** + * Multiplication : Scalaire * Matrice (ligne) + * + * Spécialisation de l'opérateur de multiplication par un scalaire pour le + * cas d'une matrice stockée par lignes. + */ + template + Matrix<_Scalar, _Rows, _Cols, RowStorage> operator*(const _Scalar& a, const Matrix<_Scalar, _Rows, _Cols, RowStorage>& A) + { + // TODO : implémenter + return Matrix<_Scalar, Dynamic, Dynamic, RowStorage>(); + } + + /** + * Multiplication : Matrice (ligne) * Vecteur + * + * Spécialisation de l'opérateur de multiplication matrice*vecteur pour le + * cas où la matrice est représentée par lignes. + */ + template + Vector<_Scalar, _Rows> operator*(const Matrix<_Scalar, _Rows, _Cols, RowStorage>& A, const Vector<_Scalar, _Cols>& v) + { + // TODO : implémenter + return Vector<_Scalar, _Rows>(); + } + + /** + * Multiplication : Matrice (colonne) * Vecteur + * + * Spécialisation de l'opérateur de multiplication matrice*vecteur pour le + * cas où la matrice est représentée par colonnes. + */ + template + Vector<_Scalar, _Rows> operator*(const Matrix<_Scalar, _Rows, _Cols, ColumnStorage>& A, const Vector<_Scalar, _Cols>& v) + { + // TODO : implémenter + return Vector<_Scalar, _Rows>(); + } + + /** + * Multiplication : Scalaire * Vecteur + */ + template + Vector<_Scalar, _Rows> operator*(const _Scalar& a, const Vector<_Scalar, _Rows>& v) + { + // TODO : implémenter + return Vector<_Scalar, _Rows>(); + } + + + /** + * Addition : Vecteur + Vecteur + */ + template + Vector<_Scalar, _RowsA> operator+(const Vector<_Scalar, _RowsA>& a, const Vector<_Scalar, _RowsB>& b) + { + // TODO : implémenter + return Vector<_Scalar, _RowsA>(); + } + + /** + * Soustraction : Vecteur - Vecteur + */ + template + Vector<_Scalar, _RowsA> operator-(const Vector<_Scalar, _RowsA>& a, const Vector<_Scalar, _RowsB>& b) + { + // TODO : implémenter + return Vector<_Scalar, _RowsA>(); + } +} diff --git a/labo01/src/Vector.h b/labo01/src/Vector.h new file mode 100644 index 0000000..6f1e4e2 --- /dev/null +++ b/labo01/src/Vector.h @@ -0,0 +1,104 @@ +#pragma once + +/** + * @file Vector.h + * + * @brief Implémentation de vecteurs simples + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include +#include "MatrixBase.h" + +namespace gti320 { + + /** + * Classe vecteur générique. + * + * Cette classe réutilise la classe `MatrixBase` et ses spécialisations de + * templates pour les manipulation bas niveau. + */ + template + class Vector : public MatrixBase<_Scalar, _Rows, 1> { + public: + + /** + * Constructeur par défaut + */ + Vector() : MatrixBase<_Scalar, _Rows, 1>() { } + + /** + * Contructeur à partir d'un taille (rows). + */ + explicit Vector(int rows) : MatrixBase<_Scalar, _Rows, 1>(rows, 1) { } + + /** + * Constructeur de copie + */ + Vector(const Vector& other) : MatrixBase<_Scalar, _Rows, 1>(other) { } + + /** + * Destructeur + */ + ~Vector() { } + + /** + * Opérateur de copie + */ + Vector& operator=(const Vector& other) + { + // TODO implémenter + this->m_storage = other.m_storage; + return *this; + } + + /** + * Accesseur à une entrée du vecteur (lecture seule) + */ + _Scalar operator()(int i) const + { + // TODO implémenter + return (double)i; + } + + /** + * Accesseur à une entrée du vecteur (lecture et écriture) + */ + _Scalar& operator()(int i) + { + // TODO implémenter + _Scalar x = (double)i; + return x; + } + + /** + * Modifie le nombre de lignes du vecteur + */ + void resize(int _rows) + { + MatrixBase<_Scalar, _Rows, 1>::resize(_rows, 1); + } + + /** + * Produit scalaire de *this et other. + */ + inline _Scalar dot(const Vector& other) const + { + // TODO implémenter + return 0.0; + } + + /** + * Retourne la norme euclidienne du vecteur + */ + inline _Scalar norm() const + { + // TODO implémenter + return 0.0; + } + }; +} diff --git a/labo01/tests/Tests1a.cpp b/labo01/tests/Tests1a.cpp new file mode 100644 index 0000000..c383d3b --- /dev/null +++ b/labo01/tests/Tests1a.cpp @@ -0,0 +1,398 @@ +/** + * @file Tests1a.cpp + * + * @brief Tests unitaires de la partie 1b + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" + +#include +#include + +using namespace gti320; + +TEST(TestLabo1a, DotAndNorm) { + { + Vector u; u(0) = 81.74804972455644; u(1) = -74.09304417781078; u(2) = -91.38202093790602; + Vector v; v(0) = 81.1462118959985; v(1) = 29.763442976156085; v(2) = 39.00787276684184; + EXPECT_NEAR(u.dot(v), 863.662223794679, 1e-4) << "(u=(81.74804972455644, -74.09304417781078, -91.38202093790602), v= (81.1462118959985, 29.763442976156085, 39.00787276684184))"; + EXPECT_NEAR(u.norm(), 143.25919370148452, 1e-4) << "(u=(81.74804972455644, -74.09304417781078, -91.38202093790602))"; + u = v; + EXPECT_NEAR(u.norm(), 94.82712892764025, 1e-4) << "u=(81.74804972455644, -74.09304417781078, -91.38202093790602)"; + } + { + Vector u; u(0) = 13.087936541928485; u(1) = -26.541934227528046; u(2) = -48.13859302157102; + Vector v; v(0) = -66.28108277028942; v(1) = 11.919000480625243; v(2) = -96.21367167640467; + EXPECT_NEAR(u.dot(v), 3447.7548518990116, 1e-4) << "(u=(13.087936541928485, -26.541934227528046, -48.13859302157102), v= (-66.28108277028942, 11.919000480625243, -96.21367167640467))"; + EXPECT_NEAR(u.norm(), 56.50745520336602, 1e-4) << "(u=(13.087936541928485, -26.541934227528046, -48.13859302157102))"; + u = v; + EXPECT_NEAR(u.norm(), 117.44068768154457, 1e-4) << "u=(13.087936541928485, -26.541934227528046, -48.13859302157102)"; + } + { + Vector u; u(0) = -79.56972852806103; u(1) = -64.04761691711548; u(2) = 75.76398532227091; + Vector v; v(0) = 68.1521534060019; v(1) = -38.02548546805114; v(2) = 44.66242384133133; + EXPECT_NEAR(u.dot(v), 396.3966055984092, 1e-4) << "(u=(-79.56972852806103, -64.04761691711548, 75.76398532227091), v= (68.1521534060019, -38.02548546805114, 44.66242384133133))"; + EXPECT_NEAR(u.norm(), 127.17554954748255, 1e-4) << "(u=(-79.56972852806103, -64.04761691711548, 75.76398532227091))"; + u = v; + EXPECT_NEAR(u.norm(), 89.91877258025103, 1e-4) << "u=(-79.56972852806103, -64.04761691711548, 75.76398532227091)"; + } + { + Vector u; u(0) = -27.829925590795995; u(1) = 97.52374799957443; u(2) = -71.29949583706774; + Vector v; v(0) = 15.413123773966177; v(1) = -25.9678191712148; v(2) = -70.46329734352945; + EXPECT_NEAR(u.dot(v), 2062.5724349077673, 1e-4) << "(u=(-27.829925590795995, 97.52374799957443, -71.29949583706774), v= (15.413123773966177, -25.9678191712148, -70.46329734352945))"; + EXPECT_NEAR(u.norm(), 123.97178827819569, 1e-4) << "(u=(-27.829925590795995, 97.52374799957443, -71.29949583706774))"; + u = v; + EXPECT_NEAR(u.norm(), 76.66138721353245, 1e-4) << "u=(-27.829925590795995, 97.52374799957443, -71.29949583706774)"; + } + { + Vector u; u(0) = 46.94969707999718; u(1) = 92.7292896206543; u(2) = 61.3890905084975; + Vector v; v(0) = 91.40236621394195; v(1) = -23.911909695536067; v(2) = -66.18706904017846; + EXPECT_NEAR(u.dot(v), -1989.1849652004407, 1e-4) << "(u=(46.94969707999718, 92.7292896206543, 61.3890905084975), v= (91.40236621394195, -23.911909695536067, -66.18706904017846))"; + EXPECT_NEAR(u.norm(), 120.71294728783312, 1e-4) << "(u=(46.94969707999718, 92.7292896206543, 61.3890905084975))"; + u = v; + EXPECT_NEAR(u.norm(), 115.3555377211011, 1e-4) << "u=(46.94969707999718, 92.7292896206543, 61.3890905084975)"; + } + { + Vector u; u(0) = 9.836648455487577; u(1) = 27.373779624683323; u(2) = 33.47163213808042; + Vector v; v(0) = -17.904556153169437; v(1) = -10.39159035574184; v(2) = 36.045191146582226; + EXPECT_NEAR(u.dot(v), 745.913449426867, 1e-4) << "(u=(9.836648455487577, 27.373779624683323, 33.47163213808042), v= (-17.904556153169437, -10.39159035574184, 36.045191146582226))"; + EXPECT_NEAR(u.norm(), 44.344488065198725, 1e-4) << "(u=(9.836648455487577, 27.373779624683323, 33.47163213808042))"; + u = v; + EXPECT_NEAR(u.norm(), 41.566983123113395, 1e-4) << "u=(9.836648455487577, 27.373779624683323, 33.47163213808042)"; + } + { + Vector u; u(0) = 77.34524968701723; u(1) = -86.53838659054598; u(2) = 52.511893628372974; + Vector v; v(0) = 39.390038592378005; v(1) = -53.13512176642368; v(2) = 60.23922457130902; + EXPECT_NEAR(u.dot(v), 10808.13583201148, 1e-4) << "(u=(77.34524968701723, -86.53838659054598, 52.511893628372974), v= (39.390038592378005, -53.13512176642368, 60.23922457130902))"; + EXPECT_NEAR(u.norm(), 127.39183245121873, 1e-4) << "(u=(77.34524968701723, -86.53838659054598, 52.511893628372974))"; + u = v; + EXPECT_NEAR(u.norm(), 89.4632912562147, 1e-4) << "u=(77.34524968701723, -86.53838659054598, 52.511893628372974)"; + } + { + Vector u; u(0) = 72.58764125601218; u(1) = 13.004884623782146; u(2) = 6.688195585248067; + Vector v; v(0) = -41.68110389567836; v(1) = 65.83906651972734; v(2) = 64.45916748876758; + EXPECT_NEAR(u.dot(v), -1738.1880334803595, 1e-4) << "(u=(72.58764125601218, 13.004884623782146, 6.688195585248067), v= (-41.68110389567836, 65.83906651972734, 64.45916748876758))"; + EXPECT_NEAR(u.norm(), 74.04609812391155, 1e-4) << "(u=(72.58764125601218, 13.004884623782146, 6.688195585248067))"; + u = v; + EXPECT_NEAR(u.norm(), 101.12903329655835, 1e-4) << "u=(72.58764125601218, 13.004884623782146, 6.688195585248067)"; + } + { + Vector u; u(0) = 44.123038783178856; u(1) = 59.032307289173275; u(2) = -96.45920641599031; + Vector v; v(0) = -23.433056105942327; v(1) = -95.82287577132844; v(2) = -87.71884659805113; + EXPECT_NEAR(u.dot(v), 1770.7072393377675, 1e-4) << "(u=(44.123038783178856, 59.032307289173275, -96.45920641599031), v= (-23.433056105942327, -95.82287577132844, -87.71884659805113))"; + EXPECT_NEAR(u.norm(), 121.39206875965131, 1e-4) << "(u=(44.123038783178856, 59.032307289173275, -96.45920641599031))"; + u = v; + EXPECT_NEAR(u.norm(), 132.006544110677, 1e-4) << "u=(44.123038783178856, 59.032307289173275, -96.45920641599031)"; + } + { + Vector u; u(0) = -7.594864170286073; u(1) = -92.12702535387345; u(2) = 10.61833019724412; + Vector v; v(0) = -57.88532008253067; v(1) = -61.95047768934079; v(2) = -50.9801175870505; + EXPECT_NEAR(u.dot(v), 5605.620650217189, 1e-4) << "(u=(-7.594864170286073, -92.12702535387345, 10.61833019724412), v= (-57.88532008253067, -61.95047768934079, -50.9801175870505))"; + EXPECT_NEAR(u.norm(), 93.04740565161417, 1e-4) << "(u=(-7.594864170286073, -92.12702535387345, 10.61833019724412))"; + u = v; + EXPECT_NEAR(u.norm(), 98.9320188623685, 1e-4) << "u=(-7.594864170286073, -92.12702535387345, 10.61833019724412)"; + } + { + Vector u; u(0) = 28.01623276831728; u(1) = -35.47111447521442; u(2) = -80.09707278049716; + Vector v; v(0) = 62.23810927998369; v(1) = -69.45561657190204; v(2) = -17.998932897185853; + EXPECT_NEAR(u.dot(v), 5649.007321253708, 1e-4) << "(u=(28.01623276831728, -35.47111447521442, -80.09707278049716), v= (62.23810927998369, -69.45561657190204, -17.998932897185853))"; + EXPECT_NEAR(u.norm(), 91.97092110361056, 1e-4) << "(u=(28.01623276831728, -35.47111447521442, -80.09707278049716))"; + u = v; + EXPECT_NEAR(u.norm(), 94.98224310663369, 1e-4) << "u=(28.01623276831728, -35.47111447521442, -80.09707278049716)"; + } + { + Vector u; u(0) = 17.056114318144637; u(1) = -47.87236586884536; u(2) = -66.233990996889; + Vector v; v(0) = -16.5274983107699; v(1) = -61.98159750757431; v(2) = -95.73085862430288; + EXPECT_NEAR(u.dot(v), 9025.947640683207, 1e-4) << "(u=(17.056114318144637, -47.87236586884536, -66.233990996889), v= (-16.5274983107699, -61.98159750757431, -95.73085862430288))"; + EXPECT_NEAR(u.norm(), 83.48422613218729, 1e-4) << "(u=(17.056114318144637, -47.87236586884536, -66.233990996889))"; + u = v; + EXPECT_NEAR(u.norm(), 115.23573197124973, 1e-4) << "u=(17.056114318144637, -47.87236586884536, -66.233990996889)"; + } + { + Vector u; u(0) = 53.68514451573557; u(1) = 40.487633535881685; u(2) = -34.39102876903675; + Vector v; v(0) = 5.723467714467617; v(1) = -11.984939376053532; v(2) = 71.57117734380691; + EXPECT_NEAR(u.dot(v), -2639.3830610897676, 1e-4) << "(u=(53.68514451573557, 40.487633535881685, -34.39102876903675), v= (5.723467714467617, -11.984939376053532, 71.57117734380691))"; + EXPECT_NEAR(u.norm(), 75.52540016977055, 1e-4) << "(u=(53.68514451573557, 40.487633535881685, -34.39102876903675))"; + u = v; + EXPECT_NEAR(u.norm(), 72.79306478576713, 1e-4) << "u=(53.68514451573557, 40.487633535881685, -34.39102876903675)"; + } + { + Vector u; u(0) = -19.41880304735801; u(1) = 80.15388147841654; u(2) = 18.762371448279836; + Vector v; v(0) = 56.544323419883455; v(1) = 37.75922627098413; v(2) = -45.767718603712495; + EXPECT_NEAR(u.dot(v), 1069.8145305211428, 1e-4) << "(u=(-19.41880304735801, 80.15388147841654, 18.762371448279836), v= (56.544323419883455, 37.75922627098413, -45.767718603712495))"; + EXPECT_NEAR(u.norm(), 84.57991020455952, 1e-4) << "(u=(-19.41880304735801, 80.15388147841654, 18.762371448279836))"; + u = v; + EXPECT_NEAR(u.norm(), 81.96159921441485, 1e-4) << "u=(-19.41880304735801, 80.15388147841654, 18.762371448279836)"; + } + { + Vector u; u(0) = 14.53101118226931; u(1) = -87.12123268098249; u(2) = -12.733552633138217; + Vector v; v(0) = -96.36370344463752; v(1) = -81.8797705320039; v(2) = -25.593956628649764; + EXPECT_NEAR(u.dot(v), 6059.106481886422, 1e-4) << "(u=(14.53101118226931, -87.12123268098249, -12.733552633138217), v= (-96.36370344463752, -81.8797705320039, -25.593956628649764))"; + EXPECT_NEAR(u.norm(), 89.23790020217884, 1e-4) << "(u=(14.53101118226931, -87.12123268098249, -12.733552633138217))"; + u = v; + EXPECT_NEAR(u.norm(), 129.01670736710366, 1e-4) << "u=(14.53101118226931, -87.12123268098249, -12.733552633138217)"; + } + { + Vector u; u(0) = -68.15128360202914; u(1) = -35.22142681790423; u(2) = -80.20820520692742; + Vector v; v(0) = -71.59083714955358; v(1) = -22.11220916087268; v(2) = -41.412146034892785; + EXPECT_NEAR(u.dot(v), 8979.424909853704, 1e-4) << "(u=(-68.15128360202914, -35.22142681790423, -80.20820520692742), v= (-71.59083714955358, -22.11220916087268, -41.412146034892785))"; + EXPECT_NEAR(u.norm(), 110.98874963801407, 1e-4) << "(u=(-68.15128360202914, -35.22142681790423, -80.20820520692742))"; + u = v; + EXPECT_NEAR(u.norm(), 85.61053438078382, 1e-4) << "u=(-68.15128360202914, -35.22142681790423, -80.20820520692742)"; + } + { + Vector u; u(0) = 32.15880264107108; u(1) = -27.044272757999167; u(2) = -21.93384224298498; + Vector v; v(0) = 94.98651607465004; v(1) = 96.25601423462368; v(2) = -4.364871517549744; + EXPECT_NEAR(u.dot(v), 547.2171237254174, 1e-4) << "(u=(32.15880264107108, -27.044272757999167, -21.93384224298498), v= (94.98651607465004, 96.25601423462368, -4.364871517549744))"; + EXPECT_NEAR(u.norm(), 47.399100327501664, 1e-4) << "(u=(32.15880264107108, -27.044272757999167, -21.93384224298498))"; + u = v; + EXPECT_NEAR(u.norm(), 135.3022934606082, 1e-4) << "u=(32.15880264107108, -27.044272757999167, -21.93384224298498)"; + } + { + Vector u; u(0) = -38.55884639660741; u(1) = -32.44768663392304; u(2) = -86.51014461651837; + Vector v; v(0) = -32.975270310868936; v(1) = -48.59524328395069; v(2) = -92.16520328196806; + EXPECT_NEAR(u.dot(v), 10821.51667331416, 1e-4) << "(u=(-38.55884639660741, -32.44768663392304, -86.51014461651837), v= (-32.975270310868936, -48.59524328395069, -92.16520328196806))"; + EXPECT_NEAR(u.norm(), 100.1181408382185, 1e-4) << "(u=(-38.55884639660741, -32.44768663392304, -86.51014461651837))"; + u = v; + EXPECT_NEAR(u.norm(), 109.2853641523316, 1e-4) << "u=(-38.55884639660741, -32.44768663392304, -86.51014461651837)"; + } + { + Vector u; u(0) = -93.94403064987613; u(1) = -22.806019440495206; u(2) = -6.186803379242534; + Vector v; v(0) = 99.58719003758503; v(1) = 11.426147026760503; v(2) = 89.17338366240898; + EXPECT_NEAR(u.dot(v), -10167.905155829267, 1e-4) << "(u=(-93.94403064987613, -22.806019440495206, -6.186803379242534), v= (99.58719003758503, 11.426147026760503, 89.17338366240898))"; + EXPECT_NEAR(u.norm(), 96.87038739221866, 1e-4) << "(u=(-93.94403064987613, -22.806019440495206, -6.186803379242534))"; + u = v; + EXPECT_NEAR(u.norm(), 134.1642933468604, 1e-4) << "u=(-93.94403064987613, -22.806019440495206, -6.186803379242534)"; + } + { + Vector u; u(0) = 49.70172009239852; u(1) = 35.23095832735339; u(2) = -95.645812626239; + Vector v; v(0) = -26.17330847186834; v(1) = -13.328976428902024; v(2) = 43.288466758804674; + EXPECT_NEAR(u.dot(v), -5910.811645163534, 1e-4) << "(u=(49.70172009239852, 35.23095832735339, -95.645812626239), v= (-26.17330847186834, -13.328976428902024, 43.288466758804674))"; + EXPECT_NEAR(u.norm(), 113.40018905513546, 1e-4) << "(u=(49.70172009239852, 35.23095832735339, -95.645812626239))"; + u = v; + EXPECT_NEAR(u.norm(), 52.31247502588592, 1e-4) << "u=(49.70172009239852, 35.23095832735339, -95.645812626239)"; + } +} + +// Test les matrice avec redimensionnement dynamique +TEST(TestLabo1a, StaticMatrixTests) +{ + // Crée une matrice à taille fixe + Matrix M; + EXPECT_EQ(M.cols(), 5); + EXPECT_EQ(M.rows(), 3); + + // Redimensionne la matrice (la taille ne doit pas changer). + M.resize(100, 1000); + EXPECT_EQ(M.cols(), 5); + EXPECT_EQ(M.rows(), 3); + + // Test - stockage par colonnes + Matrix ColM; + ColM.setZero(); + ColM(0, 0) = 1.0; + ColM(90, 17) = 99.0; + ColM(10, 33) = 7.2; + EXPECT_EQ(ColM(0, 0), 1.0); + EXPECT_EQ(ColM(90, 17), 99.0); + EXPECT_EQ(ColM(10, 33), 7.2); + + // Test - stockage par lignes + Matrix RowM; + RowM.setZero(); + RowM(0, 0) = 2.1; + RowM(3, 3) = -0.2; + RowM(4, 3) = 1.2; + EXPECT_EQ(RowM.rows(), 5); + EXPECT_EQ(RowM.cols(), 4); + EXPECT_DOUBLE_EQ(RowM(0, 0), 2.1); + EXPECT_DOUBLE_EQ(RowM(3, 3), -0.2); + EXPECT_DOUBLE_EQ(RowM(4, 3), 1.2); + EXPECT_DOUBLE_EQ(RowM(3, 2), 0.0); + + // Transposée + const auto RowMT = RowM.transpose(); + EXPECT_EQ(RowMT.rows(), 4); + EXPECT_EQ(RowMT.cols(), 5); + EXPECT_DOUBLE_EQ(RowMT(0, 0), 2.1); + EXPECT_DOUBLE_EQ(RowMT(3, 3), -0.2); + EXPECT_DOUBLE_EQ(RowMT(3, 4), 1.2); + EXPECT_DOUBLE_EQ(RowMT(2, 3), 0.0); +} + + +// Test les matrice avec redimensionnement dynamique +TEST(TestLabo1a, DynamicMatrixTests) +{ + // Crée une matrice à taille dynamique + // (note : les valeurs par défaut du patron de la classe `Matrix` mettent le + // le nombre de ligne et de colonnes à `Dynamic`) + Matrix M(3, 5); + EXPECT_EQ(M.cols(), 5); + EXPECT_EQ(M.rows(), 3); + + // Redimensionne la matrice + M.resize(100, 1000); + EXPECT_EQ(M.cols(), 1000); + EXPECT_EQ(M.rows(), 100); + + // Test - stockage par colonnes + Matrix ColM(100, 100); + ColM.setZero(); + ColM(0, 0) = 1.0; + ColM(99, 99) = 99.0; + ColM(10, 33) = 5.0; + EXPECT_EQ(ColM(0, 0), 1.0); + EXPECT_EQ(ColM(10, 33), 5.0); + EXPECT_EQ(ColM(99, 99), 99.0); + + // Test - stockage par lignes + Matrix RowM(5, 4); + RowM.setZero(); + RowM(0, 0) = 2.1; + RowM(3, 3) = -0.2; + RowM(4, 3) = 1.2; + EXPECT_EQ(RowM.rows(), 5); + EXPECT_EQ(RowM.cols(), 4); + EXPECT_DOUBLE_EQ(RowM(0, 0), 2.1); + EXPECT_DOUBLE_EQ(RowM(3, 3), -0.2); + EXPECT_DOUBLE_EQ(RowM(4, 3), 1.2); + EXPECT_DOUBLE_EQ(RowM(3, 2), 0.0); + + // Transposée + const auto RowMT = RowM.transpose(); + EXPECT_EQ(RowMT.rows(), 4); + EXPECT_EQ(RowMT.cols(), 5); + EXPECT_DOUBLE_EQ(RowMT(0, 0), 2.1); + EXPECT_DOUBLE_EQ(RowMT(3, 3), -0.2); + EXPECT_DOUBLE_EQ(RowMT(3, 4), 1.2); + EXPECT_DOUBLE_EQ(RowMT(2, 3), 0.0); +} + +/** + * Test pour les vecteurs à taille dynamique + */ +TEST(TestLabo1a, DynamicVectorSizeTest) +{ + Vector v(5); + v.setZero(); + + EXPECT_EQ(v.rows(), 5); + + v.resize(3); + EXPECT_EQ(v.rows(), 3); + + v(0) = 1.0; + v(1) = 2.0; + v(2) = 3.0; + + EXPECT_DOUBLE_EQ(v.norm(), 3.7416573867739413855837487323165); + + Vector v2(3); + v2.setZero(); + v2(1) = 2.0; + + EXPECT_DOUBLE_EQ(v2.dot(v), 4.0); + EXPECT_DOUBLE_EQ(v2(0), 0.0); + EXPECT_DOUBLE_EQ(v2(1), 2.0); + EXPECT_DOUBLE_EQ(v2(2), 0.0); +} + +TEST(TestLabo1a, Transpose) { + { + Matrix m; m.resize(3, 2); + m(0, 0) = 96.65562704596559; m(0, 1) = -5.374125981819006; m(1, 0) = 64.81364389648456; m(1, 1) = -69.97868420900502; m(2, 0) = -48.298014749653696; m(2, 1) = 81.5535983882881; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), 96.65562704596559); EXPECT_DOUBLE_EQ(mtr(0, 1), 64.81364389648456); EXPECT_DOUBLE_EQ(mtr(0, 2), -48.298014749653696); EXPECT_DOUBLE_EQ(mtr(1, 0), -5.374125981819006); EXPECT_DOUBLE_EQ(mtr(1, 1), -69.97868420900502); EXPECT_DOUBLE_EQ(mtr(1, 2), 81.5535983882881); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), 96.65562704596559); EXPECT_DOUBLE_EQ(mtc(0, 1), 64.81364389648456); EXPECT_DOUBLE_EQ(mtc(0, 2), -48.298014749653696); EXPECT_DOUBLE_EQ(mtc(1, 0), -5.374125981819006); EXPECT_DOUBLE_EQ(mtc(1, 1), -69.97868420900502); EXPECT_DOUBLE_EQ(mtc(1, 2), 81.5535983882881); + } + { + Matrix m; m.resize(3, 11); + m(0, 0) = -93.11774348806081; m(0, 1) = -98.38480859022877; m(0, 2) = -70.06261616604155; m(0, 3) = 84.87535684986423; m(0, 4) = -99.9818642210925; m(0, 5) = -25.11185567441916; m(0, 6) = 8.85590979917103; m(0, 7) = 32.717509759851936; m(0, 8) = 12.677927494307738; m(0, 9) = -76.92757015087707; m(0, 10) = -80.99502606313347; m(1, 0) = -14.108330840223957; m(1, 1) = -94.81883611699344; m(1, 2) = -45.060719301725285; m(1, 3) = -41.383939879963094; m(1, 4) = 80.36741308691853; m(1, 5) = -87.50961508738959; m(1, 6) = -32.65290161505921; m(1, 7) = 18.529868291798238; m(1, 8) = -46.169755352790595; m(1, 9) = 83.67078184672366; m(1, 10) = -30.02053885691531; m(2, 0) = 5.8022044043901815; m(2, 1) = -39.507965223996266; m(2, 2) = 38.099939917456425; m(2, 3) = -11.891042873050296; m(2, 4) = 53.89070563872062; m(2, 5) = 23.280098882479578; m(2, 6) = -5.0318917624474295; m(2, 7) = 31.50255873280196; m(2, 8) = 22.629046207699318; m(2, 9) = 3.5102931218199416; m(2, 10) = -95.03021938861154; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), -93.11774348806081); EXPECT_DOUBLE_EQ(mtr(0, 1), -14.108330840223957); EXPECT_DOUBLE_EQ(mtr(0, 2), 5.8022044043901815); EXPECT_DOUBLE_EQ(mtr(1, 0), -98.38480859022877); EXPECT_DOUBLE_EQ(mtr(1, 1), -94.81883611699344); EXPECT_DOUBLE_EQ(mtr(1, 2), -39.507965223996266); EXPECT_DOUBLE_EQ(mtr(2, 0), -70.06261616604155); EXPECT_DOUBLE_EQ(mtr(2, 1), -45.060719301725285); EXPECT_DOUBLE_EQ(mtr(2, 2), 38.099939917456425); EXPECT_DOUBLE_EQ(mtr(3, 0), 84.87535684986423); EXPECT_DOUBLE_EQ(mtr(3, 1), -41.383939879963094); EXPECT_DOUBLE_EQ(mtr(3, 2), -11.891042873050296); EXPECT_DOUBLE_EQ(mtr(4, 0), -99.9818642210925); EXPECT_DOUBLE_EQ(mtr(4, 1), 80.36741308691853); EXPECT_DOUBLE_EQ(mtr(4, 2), 53.89070563872062); EXPECT_DOUBLE_EQ(mtr(5, 0), -25.11185567441916); EXPECT_DOUBLE_EQ(mtr(5, 1), -87.50961508738959); EXPECT_DOUBLE_EQ(mtr(5, 2), 23.280098882479578); EXPECT_DOUBLE_EQ(mtr(6, 0), 8.85590979917103); EXPECT_DOUBLE_EQ(mtr(6, 1), -32.65290161505921); EXPECT_DOUBLE_EQ(mtr(6, 2), -5.0318917624474295); EXPECT_DOUBLE_EQ(mtr(7, 0), 32.717509759851936); EXPECT_DOUBLE_EQ(mtr(7, 1), 18.529868291798238); EXPECT_DOUBLE_EQ(mtr(7, 2), 31.50255873280196); EXPECT_DOUBLE_EQ(mtr(8, 0), 12.677927494307738); EXPECT_DOUBLE_EQ(mtr(8, 1), -46.169755352790595); EXPECT_DOUBLE_EQ(mtr(8, 2), 22.629046207699318); EXPECT_DOUBLE_EQ(mtr(9, 0), -76.92757015087707); EXPECT_DOUBLE_EQ(mtr(9, 1), 83.67078184672366); EXPECT_DOUBLE_EQ(mtr(9, 2), 3.5102931218199416); EXPECT_DOUBLE_EQ(mtr(10, 0), -80.99502606313347); EXPECT_DOUBLE_EQ(mtr(10, 1), -30.02053885691531); EXPECT_DOUBLE_EQ(mtr(10, 2), -95.03021938861154); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), -93.11774348806081); EXPECT_DOUBLE_EQ(mtc(0, 1), -14.108330840223957); EXPECT_DOUBLE_EQ(mtc(0, 2), 5.8022044043901815); EXPECT_DOUBLE_EQ(mtc(1, 0), -98.38480859022877); EXPECT_DOUBLE_EQ(mtc(1, 1), -94.81883611699344); EXPECT_DOUBLE_EQ(mtc(1, 2), -39.507965223996266); EXPECT_DOUBLE_EQ(mtc(2, 0), -70.06261616604155); EXPECT_DOUBLE_EQ(mtc(2, 1), -45.060719301725285); EXPECT_DOUBLE_EQ(mtc(2, 2), 38.099939917456425); EXPECT_DOUBLE_EQ(mtc(3, 0), 84.87535684986423); EXPECT_DOUBLE_EQ(mtc(3, 1), -41.383939879963094); EXPECT_DOUBLE_EQ(mtc(3, 2), -11.891042873050296); EXPECT_DOUBLE_EQ(mtc(4, 0), -99.9818642210925); EXPECT_DOUBLE_EQ(mtc(4, 1), 80.36741308691853); EXPECT_DOUBLE_EQ(mtc(4, 2), 53.89070563872062); EXPECT_DOUBLE_EQ(mtc(5, 0), -25.11185567441916); EXPECT_DOUBLE_EQ(mtc(5, 1), -87.50961508738959); EXPECT_DOUBLE_EQ(mtc(5, 2), 23.280098882479578); EXPECT_DOUBLE_EQ(mtc(6, 0), 8.85590979917103); EXPECT_DOUBLE_EQ(mtc(6, 1), -32.65290161505921); EXPECT_DOUBLE_EQ(mtc(6, 2), -5.0318917624474295); EXPECT_DOUBLE_EQ(mtc(7, 0), 32.717509759851936); EXPECT_DOUBLE_EQ(mtc(7, 1), 18.529868291798238); EXPECT_DOUBLE_EQ(mtc(7, 2), 31.50255873280196); EXPECT_DOUBLE_EQ(mtc(8, 0), 12.677927494307738); EXPECT_DOUBLE_EQ(mtc(8, 1), -46.169755352790595); EXPECT_DOUBLE_EQ(mtc(8, 2), 22.629046207699318); EXPECT_DOUBLE_EQ(mtc(9, 0), -76.92757015087707); EXPECT_DOUBLE_EQ(mtc(9, 1), 83.67078184672366); EXPECT_DOUBLE_EQ(mtc(9, 2), 3.5102931218199416); EXPECT_DOUBLE_EQ(mtc(10, 0), -80.99502606313347); EXPECT_DOUBLE_EQ(mtc(10, 1), -30.02053885691531); EXPECT_DOUBLE_EQ(mtc(10, 2), -95.03021938861154); + } + { + Matrix m; m.resize(3, 19); + m(0, 0) = 50.864090811708934; m(0, 1) = 86.72545584739655; m(0, 2) = -59.41096188367827; m(0, 3) = -81.01855448213378; m(0, 4) = -44.75527142333435; m(0, 5) = 6.881484559867502; m(0, 6) = 75.66386662485408; m(0, 7) = -56.002568995946575; m(0, 8) = -44.600865729883445; m(0, 9) = -18.413408652944696; m(0, 10) = -97.11569037525811; m(0, 11) = 53.19666636708692; m(0, 12) = -64.58909530248837; m(0, 13) = -13.336152508799714; m(0, 14) = -69.12350514623267; m(0, 15) = 56.52730125536351; m(0, 16) = 89.92552663330136; m(0, 17) = 94.33106257780301; m(0, 18) = 76.55814809986282; m(1, 0) = 14.747374583026797; m(1, 1) = -12.087041962746213; m(1, 2) = -63.3966872965287; m(1, 3) = -11.386504830855642; m(1, 4) = -76.29669292020178; m(1, 5) = -66.38097797841678; m(1, 6) = -20.191218640024687; m(1, 7) = -48.05245125934678; m(1, 8) = -83.87380388512868; m(1, 9) = -21.25569067138788; m(1, 10) = 4.889708648539596; m(1, 11) = -85.80217867074691; m(1, 12) = -85.26796006798745; m(1, 13) = 3.8169098134350605; m(1, 14) = 73.4920467291056; m(1, 15) = 98.24187210950205; m(1, 16) = -9.878913280704495; m(1, 17) = -63.027946780158196; m(1, 18) = 55.64310458734482; m(2, 0) = -75.20410363410058; m(2, 1) = 45.30781974344674; m(2, 2) = -43.85391331821933; m(2, 3) = 67.45134132003074; m(2, 4) = 55.35009554124747; m(2, 5) = -24.1599830304106; m(2, 6) = 89.85022708733555; m(2, 7) = 63.770995127367826; m(2, 8) = -7.388429976036122; m(2, 9) = 8.073425560498507; m(2, 10) = 76.76129649290999; m(2, 11) = -50.19697292034915; m(2, 12) = -25.310526646715076; m(2, 13) = 14.496228473119118; m(2, 14) = 46.35572803496012; m(2, 15) = -43.2905212948518; m(2, 16) = 72.28250601709692; m(2, 17) = 59.72857548888601; m(2, 18) = 39.776820197984875; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), 50.864090811708934); EXPECT_DOUBLE_EQ(mtr(0, 1), 14.747374583026797); EXPECT_DOUBLE_EQ(mtr(0, 2), -75.20410363410058); EXPECT_DOUBLE_EQ(mtr(1, 0), 86.72545584739655); EXPECT_DOUBLE_EQ(mtr(1, 1), -12.087041962746213); EXPECT_DOUBLE_EQ(mtr(1, 2), 45.30781974344674); EXPECT_DOUBLE_EQ(mtr(2, 0), -59.41096188367827); EXPECT_DOUBLE_EQ(mtr(2, 1), -63.3966872965287); EXPECT_DOUBLE_EQ(mtr(2, 2), -43.85391331821933); EXPECT_DOUBLE_EQ(mtr(3, 0), -81.01855448213378); EXPECT_DOUBLE_EQ(mtr(3, 1), -11.386504830855642); EXPECT_DOUBLE_EQ(mtr(3, 2), 67.45134132003074); EXPECT_DOUBLE_EQ(mtr(4, 0), -44.75527142333435); EXPECT_DOUBLE_EQ(mtr(4, 1), -76.29669292020178); EXPECT_DOUBLE_EQ(mtr(4, 2), 55.35009554124747); EXPECT_DOUBLE_EQ(mtr(5, 0), 6.881484559867502); EXPECT_DOUBLE_EQ(mtr(5, 1), -66.38097797841678); EXPECT_DOUBLE_EQ(mtr(5, 2), -24.1599830304106); EXPECT_DOUBLE_EQ(mtr(6, 0), 75.66386662485408); EXPECT_DOUBLE_EQ(mtr(6, 1), -20.191218640024687); EXPECT_DOUBLE_EQ(mtr(6, 2), 89.85022708733555); EXPECT_DOUBLE_EQ(mtr(7, 0), -56.002568995946575); EXPECT_DOUBLE_EQ(mtr(7, 1), -48.05245125934678); EXPECT_DOUBLE_EQ(mtr(7, 2), 63.770995127367826); EXPECT_DOUBLE_EQ(mtr(8, 0), -44.600865729883445); EXPECT_DOUBLE_EQ(mtr(8, 1), -83.87380388512868); EXPECT_DOUBLE_EQ(mtr(8, 2), -7.388429976036122); EXPECT_DOUBLE_EQ(mtr(9, 0), -18.413408652944696); EXPECT_DOUBLE_EQ(mtr(9, 1), -21.25569067138788); EXPECT_DOUBLE_EQ(mtr(9, 2), 8.073425560498507); EXPECT_DOUBLE_EQ(mtr(10, 0), -97.11569037525811); EXPECT_DOUBLE_EQ(mtr(10, 1), 4.889708648539596); EXPECT_DOUBLE_EQ(mtr(10, 2), 76.76129649290999); EXPECT_DOUBLE_EQ(mtr(11, 0), 53.19666636708692); EXPECT_DOUBLE_EQ(mtr(11, 1), -85.80217867074691); EXPECT_DOUBLE_EQ(mtr(11, 2), -50.19697292034915); EXPECT_DOUBLE_EQ(mtr(12, 0), -64.58909530248837); EXPECT_DOUBLE_EQ(mtr(12, 1), -85.26796006798745); EXPECT_DOUBLE_EQ(mtr(12, 2), -25.310526646715076); EXPECT_DOUBLE_EQ(mtr(13, 0), -13.336152508799714); EXPECT_DOUBLE_EQ(mtr(13, 1), 3.8169098134350605); EXPECT_DOUBLE_EQ(mtr(13, 2), 14.496228473119118); EXPECT_DOUBLE_EQ(mtr(14, 0), -69.12350514623267); EXPECT_DOUBLE_EQ(mtr(14, 1), 73.4920467291056); EXPECT_DOUBLE_EQ(mtr(14, 2), 46.35572803496012); EXPECT_DOUBLE_EQ(mtr(15, 0), 56.52730125536351); EXPECT_DOUBLE_EQ(mtr(15, 1), 98.24187210950205); EXPECT_DOUBLE_EQ(mtr(15, 2), -43.2905212948518); EXPECT_DOUBLE_EQ(mtr(16, 0), 89.92552663330136); EXPECT_DOUBLE_EQ(mtr(16, 1), -9.878913280704495); EXPECT_DOUBLE_EQ(mtr(16, 2), 72.28250601709692); EXPECT_DOUBLE_EQ(mtr(17, 0), 94.33106257780301); EXPECT_DOUBLE_EQ(mtr(17, 1), -63.027946780158196); EXPECT_DOUBLE_EQ(mtr(17, 2), 59.72857548888601); EXPECT_DOUBLE_EQ(mtr(18, 0), 76.55814809986282); EXPECT_DOUBLE_EQ(mtr(18, 1), 55.64310458734482); EXPECT_DOUBLE_EQ(mtr(18, 2), 39.776820197984875); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), 50.864090811708934); EXPECT_DOUBLE_EQ(mtc(0, 1), 14.747374583026797); EXPECT_DOUBLE_EQ(mtc(0, 2), -75.20410363410058); EXPECT_DOUBLE_EQ(mtc(1, 0), 86.72545584739655); EXPECT_DOUBLE_EQ(mtc(1, 1), -12.087041962746213); EXPECT_DOUBLE_EQ(mtc(1, 2), 45.30781974344674); EXPECT_DOUBLE_EQ(mtc(2, 0), -59.41096188367827); EXPECT_DOUBLE_EQ(mtc(2, 1), -63.3966872965287); EXPECT_DOUBLE_EQ(mtc(2, 2), -43.85391331821933); EXPECT_DOUBLE_EQ(mtc(3, 0), -81.01855448213378); EXPECT_DOUBLE_EQ(mtc(3, 1), -11.386504830855642); EXPECT_DOUBLE_EQ(mtc(3, 2), 67.45134132003074); EXPECT_DOUBLE_EQ(mtc(4, 0), -44.75527142333435); EXPECT_DOUBLE_EQ(mtc(4, 1), -76.29669292020178); EXPECT_DOUBLE_EQ(mtc(4, 2), 55.35009554124747); EXPECT_DOUBLE_EQ(mtc(5, 0), 6.881484559867502); EXPECT_DOUBLE_EQ(mtc(5, 1), -66.38097797841678); EXPECT_DOUBLE_EQ(mtc(5, 2), -24.1599830304106); EXPECT_DOUBLE_EQ(mtc(6, 0), 75.66386662485408); EXPECT_DOUBLE_EQ(mtc(6, 1), -20.191218640024687); EXPECT_DOUBLE_EQ(mtc(6, 2), 89.85022708733555); EXPECT_DOUBLE_EQ(mtc(7, 0), -56.002568995946575); EXPECT_DOUBLE_EQ(mtc(7, 1), -48.05245125934678); EXPECT_DOUBLE_EQ(mtc(7, 2), 63.770995127367826); EXPECT_DOUBLE_EQ(mtc(8, 0), -44.600865729883445); EXPECT_DOUBLE_EQ(mtc(8, 1), -83.87380388512868); EXPECT_DOUBLE_EQ(mtc(8, 2), -7.388429976036122); EXPECT_DOUBLE_EQ(mtc(9, 0), -18.413408652944696); EXPECT_DOUBLE_EQ(mtc(9, 1), -21.25569067138788); EXPECT_DOUBLE_EQ(mtc(9, 2), 8.073425560498507); EXPECT_DOUBLE_EQ(mtc(10, 0), -97.11569037525811); EXPECT_DOUBLE_EQ(mtc(10, 1), 4.889708648539596); EXPECT_DOUBLE_EQ(mtc(10, 2), 76.76129649290999); EXPECT_DOUBLE_EQ(mtc(11, 0), 53.19666636708692); EXPECT_DOUBLE_EQ(mtc(11, 1), -85.80217867074691); EXPECT_DOUBLE_EQ(mtc(11, 2), -50.19697292034915); EXPECT_DOUBLE_EQ(mtc(12, 0), -64.58909530248837); EXPECT_DOUBLE_EQ(mtc(12, 1), -85.26796006798745); EXPECT_DOUBLE_EQ(mtc(12, 2), -25.310526646715076); EXPECT_DOUBLE_EQ(mtc(13, 0), -13.336152508799714); EXPECT_DOUBLE_EQ(mtc(13, 1), 3.8169098134350605); EXPECT_DOUBLE_EQ(mtc(13, 2), 14.496228473119118); EXPECT_DOUBLE_EQ(mtc(14, 0), -69.12350514623267); EXPECT_DOUBLE_EQ(mtc(14, 1), 73.4920467291056); EXPECT_DOUBLE_EQ(mtc(14, 2), 46.35572803496012); EXPECT_DOUBLE_EQ(mtc(15, 0), 56.52730125536351); EXPECT_DOUBLE_EQ(mtc(15, 1), 98.24187210950205); EXPECT_DOUBLE_EQ(mtc(15, 2), -43.2905212948518); EXPECT_DOUBLE_EQ(mtc(16, 0), 89.92552663330136); EXPECT_DOUBLE_EQ(mtc(16, 1), -9.878913280704495); EXPECT_DOUBLE_EQ(mtc(16, 2), 72.28250601709692); EXPECT_DOUBLE_EQ(mtc(17, 0), 94.33106257780301); EXPECT_DOUBLE_EQ(mtc(17, 1), -63.027946780158196); EXPECT_DOUBLE_EQ(mtc(17, 2), 59.72857548888601); EXPECT_DOUBLE_EQ(mtc(18, 0), 76.55814809986282); EXPECT_DOUBLE_EQ(mtc(18, 1), 55.64310458734482); EXPECT_DOUBLE_EQ(mtc(18, 2), 39.776820197984875); + } + { + Matrix m; m.resize(3, 12); + m(0, 0) = -32.75375661346618; m(0, 1) = -13.6098421772042; m(0, 2) = -46.86521220477553; m(0, 3) = 59.00702831249865; m(0, 4) = -4.564740481250126; m(0, 5) = 16.232920948792312; m(0, 6) = -65.0828541930055; m(0, 7) = -57.88248367433246; m(0, 8) = -81.72734394349992; m(0, 9) = 28.080964462881383; m(0, 10) = 36.6937632974539; m(0, 11) = 41.35837714070166; m(1, 0) = -47.68004182743719; m(1, 1) = -64.19046526329765; m(1, 2) = -75.66374889412242; m(1, 3) = -82.35155489863575; m(1, 4) = -75.40948179339736; m(1, 5) = -21.839837867220055; m(1, 6) = -7.047883213897393; m(1, 7) = -28.576424866142986; m(1, 8) = 36.45450614900494; m(1, 9) = -9.122226758045997; m(1, 10) = 39.94779111587877; m(1, 11) = 9.684112064820866; m(2, 0) = 34.000255287178476; m(2, 1) = 64.99966038549962; m(2, 2) = -11.973673265362649; m(2, 3) = 80.2812674443403; m(2, 4) = 95.91223898270886; m(2, 5) = -27.634369350449873; m(2, 6) = -75.21066302899243; m(2, 7) = -20.700089950120855; m(2, 8) = 86.68513293601455; m(2, 9) = 75.43854998281424; m(2, 10) = -88.06922362937304; m(2, 11) = -92.34886576586136; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), -32.75375661346618); EXPECT_DOUBLE_EQ(mtr(0, 1), -47.68004182743719); EXPECT_DOUBLE_EQ(mtr(0, 2), 34.000255287178476); EXPECT_DOUBLE_EQ(mtr(1, 0), -13.6098421772042); EXPECT_DOUBLE_EQ(mtr(1, 1), -64.19046526329765); EXPECT_DOUBLE_EQ(mtr(1, 2), 64.99966038549962); EXPECT_DOUBLE_EQ(mtr(2, 0), -46.86521220477553); EXPECT_DOUBLE_EQ(mtr(2, 1), -75.66374889412242); EXPECT_DOUBLE_EQ(mtr(2, 2), -11.973673265362649); EXPECT_DOUBLE_EQ(mtr(3, 0), 59.00702831249865); EXPECT_DOUBLE_EQ(mtr(3, 1), -82.35155489863575); EXPECT_DOUBLE_EQ(mtr(3, 2), 80.2812674443403); EXPECT_DOUBLE_EQ(mtr(4, 0), -4.564740481250126); EXPECT_DOUBLE_EQ(mtr(4, 1), -75.40948179339736); EXPECT_DOUBLE_EQ(mtr(4, 2), 95.91223898270886); EXPECT_DOUBLE_EQ(mtr(5, 0), 16.232920948792312); EXPECT_DOUBLE_EQ(mtr(5, 1), -21.839837867220055); EXPECT_DOUBLE_EQ(mtr(5, 2), -27.634369350449873); EXPECT_DOUBLE_EQ(mtr(6, 0), -65.0828541930055); EXPECT_DOUBLE_EQ(mtr(6, 1), -7.047883213897393); EXPECT_DOUBLE_EQ(mtr(6, 2), -75.21066302899243); EXPECT_DOUBLE_EQ(mtr(7, 0), -57.88248367433246); EXPECT_DOUBLE_EQ(mtr(7, 1), -28.576424866142986); EXPECT_DOUBLE_EQ(mtr(7, 2), -20.700089950120855); EXPECT_DOUBLE_EQ(mtr(8, 0), -81.72734394349992); EXPECT_DOUBLE_EQ(mtr(8, 1), 36.45450614900494); EXPECT_DOUBLE_EQ(mtr(8, 2), 86.68513293601455); EXPECT_DOUBLE_EQ(mtr(9, 0), 28.080964462881383); EXPECT_DOUBLE_EQ(mtr(9, 1), -9.122226758045997); EXPECT_DOUBLE_EQ(mtr(9, 2), 75.43854998281424); EXPECT_DOUBLE_EQ(mtr(10, 0), 36.6937632974539); EXPECT_DOUBLE_EQ(mtr(10, 1), 39.94779111587877); EXPECT_DOUBLE_EQ(mtr(10, 2), -88.06922362937304); EXPECT_DOUBLE_EQ(mtr(11, 0), 41.35837714070166); EXPECT_DOUBLE_EQ(mtr(11, 1), 9.684112064820866); EXPECT_DOUBLE_EQ(mtr(11, 2), -92.34886576586136); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), -32.75375661346618); EXPECT_DOUBLE_EQ(mtc(0, 1), -47.68004182743719); EXPECT_DOUBLE_EQ(mtc(0, 2), 34.000255287178476); EXPECT_DOUBLE_EQ(mtc(1, 0), -13.6098421772042); EXPECT_DOUBLE_EQ(mtc(1, 1), -64.19046526329765); EXPECT_DOUBLE_EQ(mtc(1, 2), 64.99966038549962); EXPECT_DOUBLE_EQ(mtc(2, 0), -46.86521220477553); EXPECT_DOUBLE_EQ(mtc(2, 1), -75.66374889412242); EXPECT_DOUBLE_EQ(mtc(2, 2), -11.973673265362649); EXPECT_DOUBLE_EQ(mtc(3, 0), 59.00702831249865); EXPECT_DOUBLE_EQ(mtc(3, 1), -82.35155489863575); EXPECT_DOUBLE_EQ(mtc(3, 2), 80.2812674443403); EXPECT_DOUBLE_EQ(mtc(4, 0), -4.564740481250126); EXPECT_DOUBLE_EQ(mtc(4, 1), -75.40948179339736); EXPECT_DOUBLE_EQ(mtc(4, 2), 95.91223898270886); EXPECT_DOUBLE_EQ(mtc(5, 0), 16.232920948792312); EXPECT_DOUBLE_EQ(mtc(5, 1), -21.839837867220055); EXPECT_DOUBLE_EQ(mtc(5, 2), -27.634369350449873); EXPECT_DOUBLE_EQ(mtc(6, 0), -65.0828541930055); EXPECT_DOUBLE_EQ(mtc(6, 1), -7.047883213897393); EXPECT_DOUBLE_EQ(mtc(6, 2), -75.21066302899243); EXPECT_DOUBLE_EQ(mtc(7, 0), -57.88248367433246); EXPECT_DOUBLE_EQ(mtc(7, 1), -28.576424866142986); EXPECT_DOUBLE_EQ(mtc(7, 2), -20.700089950120855); EXPECT_DOUBLE_EQ(mtc(8, 0), -81.72734394349992); EXPECT_DOUBLE_EQ(mtc(8, 1), 36.45450614900494); EXPECT_DOUBLE_EQ(mtc(8, 2), 86.68513293601455); EXPECT_DOUBLE_EQ(mtc(9, 0), 28.080964462881383); EXPECT_DOUBLE_EQ(mtc(9, 1), -9.122226758045997); EXPECT_DOUBLE_EQ(mtc(9, 2), 75.43854998281424); EXPECT_DOUBLE_EQ(mtc(10, 0), 36.6937632974539); EXPECT_DOUBLE_EQ(mtc(10, 1), 39.94779111587877); EXPECT_DOUBLE_EQ(mtc(10, 2), -88.06922362937304); EXPECT_DOUBLE_EQ(mtc(11, 0), 41.35837714070166); EXPECT_DOUBLE_EQ(mtc(11, 1), 9.684112064820866); EXPECT_DOUBLE_EQ(mtc(11, 2), -92.34886576586136); + } + { + Matrix m; m.resize(3, 17); + m(0, 0) = 41.19222807334356; m(0, 1) = -9.647827035990119; m(0, 2) = 79.08578232010518; m(0, 3) = -81.30050511004372; m(0, 4) = 5.2008331502779725; m(0, 5) = -94.16930980955891; m(0, 6) = -13.738166181380976; m(0, 7) = 31.708028058804274; m(0, 8) = -98.07812519655093; m(0, 9) = -51.718134217817926; m(0, 10) = -81.49405897174573; m(0, 11) = 86.09136014594006; m(0, 12) = -23.14506976740256; m(0, 13) = 76.3616884219812; m(0, 14) = 60.28344358729666; m(0, 15) = -35.34123633864937; m(0, 16) = -87.33936780992902; m(1, 0) = 25.563530352835954; m(1, 1) = -43.62388501728416; m(1, 2) = 0.5379451108277209; m(1, 3) = 40.11963964000961; m(1, 4) = -63.945471933511236; m(1, 5) = 25.47334071885645; m(1, 6) = 20.998951793092573; m(1, 7) = 23.964236092014318; m(1, 8) = -53.69611952912465; m(1, 9) = -48.45849352784126; m(1, 10) = 0.03386109792266723; m(1, 11) = -43.90344163766924; m(1, 12) = -6.698621092523396; m(1, 13) = -99.37831178796779; m(1, 14) = -9.64088536276411; m(1, 15) = 3.118955974716698; m(1, 16) = -81.5481380106742; m(2, 0) = 62.07279507925867; m(2, 1) = 90.29145840318458; m(2, 2) = -25.71415288702252; m(2, 3) = 74.7395459171091; m(2, 4) = 24.394997421168824; m(2, 5) = -58.2301634354434; m(2, 6) = -4.768291835922895; m(2, 7) = 49.704487303266575; m(2, 8) = 18.65157355854312; m(2, 9) = 98.9073219636636; m(2, 10) = -45.19000115648366; m(2, 11) = -45.249286237965315; m(2, 12) = 97.09143831741096; m(2, 13) = -31.80834068260583; m(2, 14) = -78.03982967131924; m(2, 15) = -14.844621355572116; m(2, 16) = -66.64707457523824; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), 41.19222807334356); EXPECT_DOUBLE_EQ(mtr(0, 1), 25.563530352835954); EXPECT_DOUBLE_EQ(mtr(0, 2), 62.07279507925867); EXPECT_DOUBLE_EQ(mtr(1, 0), -9.647827035990119); EXPECT_DOUBLE_EQ(mtr(1, 1), -43.62388501728416); EXPECT_DOUBLE_EQ(mtr(1, 2), 90.29145840318458); EXPECT_DOUBLE_EQ(mtr(2, 0), 79.08578232010518); EXPECT_DOUBLE_EQ(mtr(2, 1), 0.5379451108277209); EXPECT_DOUBLE_EQ(mtr(2, 2), -25.71415288702252); EXPECT_DOUBLE_EQ(mtr(3, 0), -81.30050511004372); EXPECT_DOUBLE_EQ(mtr(3, 1), 40.11963964000961); EXPECT_DOUBLE_EQ(mtr(3, 2), 74.7395459171091); EXPECT_DOUBLE_EQ(mtr(4, 0), 5.2008331502779725); EXPECT_DOUBLE_EQ(mtr(4, 1), -63.945471933511236); EXPECT_DOUBLE_EQ(mtr(4, 2), 24.394997421168824); EXPECT_DOUBLE_EQ(mtr(5, 0), -94.16930980955891); EXPECT_DOUBLE_EQ(mtr(5, 1), 25.47334071885645); EXPECT_DOUBLE_EQ(mtr(5, 2), -58.2301634354434); EXPECT_DOUBLE_EQ(mtr(6, 0), -13.738166181380976); EXPECT_DOUBLE_EQ(mtr(6, 1), 20.998951793092573); EXPECT_DOUBLE_EQ(mtr(6, 2), -4.768291835922895); EXPECT_DOUBLE_EQ(mtr(7, 0), 31.708028058804274); EXPECT_DOUBLE_EQ(mtr(7, 1), 23.964236092014318); EXPECT_DOUBLE_EQ(mtr(7, 2), 49.704487303266575); EXPECT_DOUBLE_EQ(mtr(8, 0), -98.07812519655093); EXPECT_DOUBLE_EQ(mtr(8, 1), -53.69611952912465); EXPECT_DOUBLE_EQ(mtr(8, 2), 18.65157355854312); EXPECT_DOUBLE_EQ(mtr(9, 0), -51.718134217817926); EXPECT_DOUBLE_EQ(mtr(9, 1), -48.45849352784126); EXPECT_DOUBLE_EQ(mtr(9, 2), 98.9073219636636); EXPECT_DOUBLE_EQ(mtr(10, 0), -81.49405897174573); EXPECT_DOUBLE_EQ(mtr(10, 1), 0.03386109792266723); EXPECT_DOUBLE_EQ(mtr(10, 2), -45.19000115648366); EXPECT_DOUBLE_EQ(mtr(11, 0), 86.09136014594006); EXPECT_DOUBLE_EQ(mtr(11, 1), -43.90344163766924); EXPECT_DOUBLE_EQ(mtr(11, 2), -45.249286237965315); EXPECT_DOUBLE_EQ(mtr(12, 0), -23.14506976740256); EXPECT_DOUBLE_EQ(mtr(12, 1), -6.698621092523396); EXPECT_DOUBLE_EQ(mtr(12, 2), 97.09143831741096); EXPECT_DOUBLE_EQ(mtr(13, 0), 76.3616884219812); EXPECT_DOUBLE_EQ(mtr(13, 1), -99.37831178796779); EXPECT_DOUBLE_EQ(mtr(13, 2), -31.80834068260583); EXPECT_DOUBLE_EQ(mtr(14, 0), 60.28344358729666); EXPECT_DOUBLE_EQ(mtr(14, 1), -9.64088536276411); EXPECT_DOUBLE_EQ(mtr(14, 2), -78.03982967131924); EXPECT_DOUBLE_EQ(mtr(15, 0), -35.34123633864937); EXPECT_DOUBLE_EQ(mtr(15, 1), 3.118955974716698); EXPECT_DOUBLE_EQ(mtr(15, 2), -14.844621355572116); EXPECT_DOUBLE_EQ(mtr(16, 0), -87.33936780992902); EXPECT_DOUBLE_EQ(mtr(16, 1), -81.5481380106742); EXPECT_DOUBLE_EQ(mtr(16, 2), -66.64707457523824); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), 41.19222807334356); EXPECT_DOUBLE_EQ(mtc(0, 1), 25.563530352835954); EXPECT_DOUBLE_EQ(mtc(0, 2), 62.07279507925867); EXPECT_DOUBLE_EQ(mtc(1, 0), -9.647827035990119); EXPECT_DOUBLE_EQ(mtc(1, 1), -43.62388501728416); EXPECT_DOUBLE_EQ(mtc(1, 2), 90.29145840318458); EXPECT_DOUBLE_EQ(mtc(2, 0), 79.08578232010518); EXPECT_DOUBLE_EQ(mtc(2, 1), 0.5379451108277209); EXPECT_DOUBLE_EQ(mtc(2, 2), -25.71415288702252); EXPECT_DOUBLE_EQ(mtc(3, 0), -81.30050511004372); EXPECT_DOUBLE_EQ(mtc(3, 1), 40.11963964000961); EXPECT_DOUBLE_EQ(mtc(3, 2), 74.7395459171091); EXPECT_DOUBLE_EQ(mtc(4, 0), 5.2008331502779725); EXPECT_DOUBLE_EQ(mtc(4, 1), -63.945471933511236); EXPECT_DOUBLE_EQ(mtc(4, 2), 24.394997421168824); EXPECT_DOUBLE_EQ(mtc(5, 0), -94.16930980955891); EXPECT_DOUBLE_EQ(mtc(5, 1), 25.47334071885645); EXPECT_DOUBLE_EQ(mtc(5, 2), -58.2301634354434); EXPECT_DOUBLE_EQ(mtc(6, 0), -13.738166181380976); EXPECT_DOUBLE_EQ(mtc(6, 1), 20.998951793092573); EXPECT_DOUBLE_EQ(mtc(6, 2), -4.768291835922895); EXPECT_DOUBLE_EQ(mtc(7, 0), 31.708028058804274); EXPECT_DOUBLE_EQ(mtc(7, 1), 23.964236092014318); EXPECT_DOUBLE_EQ(mtc(7, 2), 49.704487303266575); EXPECT_DOUBLE_EQ(mtc(8, 0), -98.07812519655093); EXPECT_DOUBLE_EQ(mtc(8, 1), -53.69611952912465); EXPECT_DOUBLE_EQ(mtc(8, 2), 18.65157355854312); EXPECT_DOUBLE_EQ(mtc(9, 0), -51.718134217817926); EXPECT_DOUBLE_EQ(mtc(9, 1), -48.45849352784126); EXPECT_DOUBLE_EQ(mtc(9, 2), 98.9073219636636); EXPECT_DOUBLE_EQ(mtc(10, 0), -81.49405897174573); EXPECT_DOUBLE_EQ(mtc(10, 1), 0.03386109792266723); EXPECT_DOUBLE_EQ(mtc(10, 2), -45.19000115648366); EXPECT_DOUBLE_EQ(mtc(11, 0), 86.09136014594006); EXPECT_DOUBLE_EQ(mtc(11, 1), -43.90344163766924); EXPECT_DOUBLE_EQ(mtc(11, 2), -45.249286237965315); EXPECT_DOUBLE_EQ(mtc(12, 0), -23.14506976740256); EXPECT_DOUBLE_EQ(mtc(12, 1), -6.698621092523396); EXPECT_DOUBLE_EQ(mtc(12, 2), 97.09143831741096); EXPECT_DOUBLE_EQ(mtc(13, 0), 76.3616884219812); EXPECT_DOUBLE_EQ(mtc(13, 1), -99.37831178796779); EXPECT_DOUBLE_EQ(mtc(13, 2), -31.80834068260583); EXPECT_DOUBLE_EQ(mtc(14, 0), 60.28344358729666); EXPECT_DOUBLE_EQ(mtc(14, 1), -9.64088536276411); EXPECT_DOUBLE_EQ(mtc(14, 2), -78.03982967131924); EXPECT_DOUBLE_EQ(mtc(15, 0), -35.34123633864937); EXPECT_DOUBLE_EQ(mtc(15, 1), 3.118955974716698); EXPECT_DOUBLE_EQ(mtc(15, 2), -14.844621355572116); EXPECT_DOUBLE_EQ(mtc(16, 0), -87.33936780992902); EXPECT_DOUBLE_EQ(mtc(16, 1), -81.5481380106742); EXPECT_DOUBLE_EQ(mtc(16, 2), -66.64707457523824); + } + { + Matrix m; m.resize(3, 11); + m(0, 0) = -44.385915446696366; m(0, 1) = 28.793505461441015; m(0, 2) = 71.2114986465838; m(0, 3) = 51.14773880111491; m(0, 4) = -7.958682467368476; m(0, 5) = -83.09905041318346; m(0, 6) = -22.191719125506793; m(0, 7) = -2.2844026553076873; m(0, 8) = -85.89049887253955; m(0, 9) = 7.359151344016439; m(0, 10) = -12.836173824817394; m(1, 0) = 60.864624834962456; m(1, 1) = 55.31797716120735; m(1, 2) = 54.86505134841502; m(1, 3) = 1.2088001265842365; m(1, 4) = 51.71783583087824; m(1, 5) = -97.7984372019131; m(1, 6) = -21.276052450577225; m(1, 7) = -38.9853136735308; m(1, 8) = -83.47696130822689; m(1, 9) = 3.197398523431062; m(1, 10) = -81.03476411018644; m(2, 0) = 78.17495315633076; m(2, 1) = -81.81693970564498; m(2, 2) = -30.34183030075195; m(2, 3) = -15.609525205781651; m(2, 4) = -27.0093291175411; m(2, 5) = 42.95413233280735; m(2, 6) = -72.61359152573652; m(2, 7) = 78.95917814822454; m(2, 8) = -83.12124753315223; m(2, 9) = 74.1286028999458; m(2, 10) = -87.09605709830836; + Matrix mtr = m.transpose(); + EXPECT_DOUBLE_EQ(mtr(0, 0), -44.385915446696366); EXPECT_DOUBLE_EQ(mtr(0, 1), 60.864624834962456); EXPECT_DOUBLE_EQ(mtr(0, 2), 78.17495315633076); EXPECT_DOUBLE_EQ(mtr(1, 0), 28.793505461441015); EXPECT_DOUBLE_EQ(mtr(1, 1), 55.31797716120735); EXPECT_DOUBLE_EQ(mtr(1, 2), -81.81693970564498); EXPECT_DOUBLE_EQ(mtr(2, 0), 71.2114986465838); EXPECT_DOUBLE_EQ(mtr(2, 1), 54.86505134841502); EXPECT_DOUBLE_EQ(mtr(2, 2), -30.34183030075195); EXPECT_DOUBLE_EQ(mtr(3, 0), 51.14773880111491); EXPECT_DOUBLE_EQ(mtr(3, 1), 1.2088001265842365); EXPECT_DOUBLE_EQ(mtr(3, 2), -15.609525205781651); EXPECT_DOUBLE_EQ(mtr(4, 0), -7.958682467368476); EXPECT_DOUBLE_EQ(mtr(4, 1), 51.71783583087824); EXPECT_DOUBLE_EQ(mtr(4, 2), -27.0093291175411); EXPECT_DOUBLE_EQ(mtr(5, 0), -83.09905041318346); EXPECT_DOUBLE_EQ(mtr(5, 1), -97.7984372019131); EXPECT_DOUBLE_EQ(mtr(5, 2), 42.95413233280735); EXPECT_DOUBLE_EQ(mtr(6, 0), -22.191719125506793); EXPECT_DOUBLE_EQ(mtr(6, 1), -21.276052450577225); EXPECT_DOUBLE_EQ(mtr(6, 2), -72.61359152573652); EXPECT_DOUBLE_EQ(mtr(7, 0), -2.2844026553076873); EXPECT_DOUBLE_EQ(mtr(7, 1), -38.9853136735308); EXPECT_DOUBLE_EQ(mtr(7, 2), 78.95917814822454); EXPECT_DOUBLE_EQ(mtr(8, 0), -85.89049887253955); EXPECT_DOUBLE_EQ(mtr(8, 1), -83.47696130822689); EXPECT_DOUBLE_EQ(mtr(8, 2), -83.12124753315223); EXPECT_DOUBLE_EQ(mtr(9, 0), 7.359151344016439); EXPECT_DOUBLE_EQ(mtr(9, 1), 3.197398523431062); EXPECT_DOUBLE_EQ(mtr(9, 2), 74.1286028999458); EXPECT_DOUBLE_EQ(mtr(10, 0), -12.836173824817394); EXPECT_DOUBLE_EQ(mtr(10, 1), -81.03476411018644); EXPECT_DOUBLE_EQ(mtr(10, 2), -87.09605709830836); + Matrix mtc = m.transpose(); + EXPECT_DOUBLE_EQ(mtc(0, 0), -44.385915446696366); EXPECT_DOUBLE_EQ(mtc(0, 1), 60.864624834962456); EXPECT_DOUBLE_EQ(mtc(0, 2), 78.17495315633076); EXPECT_DOUBLE_EQ(mtc(1, 0), 28.793505461441015); EXPECT_DOUBLE_EQ(mtc(1, 1), 55.31797716120735); EXPECT_DOUBLE_EQ(mtc(1, 2), -81.81693970564498); EXPECT_DOUBLE_EQ(mtc(2, 0), 71.2114986465838); EXPECT_DOUBLE_EQ(mtc(2, 1), 54.86505134841502); EXPECT_DOUBLE_EQ(mtc(2, 2), -30.34183030075195); EXPECT_DOUBLE_EQ(mtc(3, 0), 51.14773880111491); EXPECT_DOUBLE_EQ(mtc(3, 1), 1.2088001265842365); EXPECT_DOUBLE_EQ(mtc(3, 2), -15.609525205781651); EXPECT_DOUBLE_EQ(mtc(4, 0), -7.958682467368476); EXPECT_DOUBLE_EQ(mtc(4, 1), 51.71783583087824); EXPECT_DOUBLE_EQ(mtc(4, 2), -27.0093291175411); EXPECT_DOUBLE_EQ(mtc(5, 0), -83.09905041318346); EXPECT_DOUBLE_EQ(mtc(5, 1), -97.7984372019131); EXPECT_DOUBLE_EQ(mtc(5, 2), 42.95413233280735); EXPECT_DOUBLE_EQ(mtc(6, 0), -22.191719125506793); EXPECT_DOUBLE_EQ(mtc(6, 1), -21.276052450577225); EXPECT_DOUBLE_EQ(mtc(6, 2), -72.61359152573652); EXPECT_DOUBLE_EQ(mtc(7, 0), -2.2844026553076873); EXPECT_DOUBLE_EQ(mtc(7, 1), -38.9853136735308); EXPECT_DOUBLE_EQ(mtc(7, 2), 78.95917814822454); EXPECT_DOUBLE_EQ(mtc(8, 0), -85.89049887253955); EXPECT_DOUBLE_EQ(mtc(8, 1), -83.47696130822689); EXPECT_DOUBLE_EQ(mtc(8, 2), -83.12124753315223); EXPECT_DOUBLE_EQ(mtc(9, 0), 7.359151344016439); EXPECT_DOUBLE_EQ(mtc(9, 1), 3.197398523431062); EXPECT_DOUBLE_EQ(mtc(9, 2), 74.1286028999458); EXPECT_DOUBLE_EQ(mtc(10, 0), -12.836173824817394); EXPECT_DOUBLE_EQ(mtc(10, 1), -81.03476411018644); EXPECT_DOUBLE_EQ(mtc(10, 2), -87.09605709830836); + } +} + +TEST(TestLabo1a, AffectationBySubMatrix) +{ + { + Matrix m; + m.setIdentity(); + EXPECT_DOUBLE_EQ(m(0, 0), 1); EXPECT_DOUBLE_EQ(m(0, 1), 0); EXPECT_DOUBLE_EQ(m(0, 2), 0); EXPECT_DOUBLE_EQ(m(0, 3), 0); EXPECT_DOUBLE_EQ(m(1, 0), 0); EXPECT_DOUBLE_EQ(m(1, 1), 1); EXPECT_DOUBLE_EQ(m(1, 2), 0); EXPECT_DOUBLE_EQ(m(1, 3), 0); EXPECT_DOUBLE_EQ(m(2, 0), 0); EXPECT_DOUBLE_EQ(m(2, 1), 0); EXPECT_DOUBLE_EQ(m(2, 2), 1); EXPECT_DOUBLE_EQ(m(2, 3), 0); EXPECT_DOUBLE_EQ(m(3, 0), 0); EXPECT_DOUBLE_EQ(m(3, 1), 0); EXPECT_DOUBLE_EQ(m(3, 2), 0); EXPECT_DOUBLE_EQ(m(3, 3), 1); + Matrix c; + c(0, 0) = 1.0; c(1, 0) = 2.0; c(2, 0) = 3.0; c(3, 0) = 4.0; + m.block(0, 0, 4, 1) = c; + m.block(0, 1, 4, 1) = c; + m.block(0, 2, 4, 1) = c; + m.block(0, 3, 4, 1) = c; + EXPECT_DOUBLE_EQ(m(0, 0), 1); EXPECT_DOUBLE_EQ(m(0, 1), 1); EXPECT_DOUBLE_EQ(m(0, 2), 1); EXPECT_DOUBLE_EQ(m(0, 3), 1); EXPECT_DOUBLE_EQ(m(1, 0), 2); EXPECT_DOUBLE_EQ(m(1, 1), 2); EXPECT_DOUBLE_EQ(m(1, 2), 2); EXPECT_DOUBLE_EQ(m(1, 3), 2); EXPECT_DOUBLE_EQ(m(2, 0), 3); EXPECT_DOUBLE_EQ(m(2, 1), 3); EXPECT_DOUBLE_EQ(m(2, 2), 3); EXPECT_DOUBLE_EQ(m(2, 3), 3); EXPECT_DOUBLE_EQ(m(3, 0), 4); EXPECT_DOUBLE_EQ(m(3, 1), 4); EXPECT_DOUBLE_EQ(m(3, 2), 4); EXPECT_DOUBLE_EQ(m(3, 3), 4); + Matrix b; + b(0, 0) = 0.0; b(1, 0) = 1.0; b(0, 1) = 2.0; b(1, 1) = 3.0; + m.block(0, 0, 2, 2) = b; + m.block(2, 0, 2, 2) = b; + m.block(0, 2, 2, 2) = b; + m.block(2, 2, 2, 2) = b; + EXPECT_DOUBLE_EQ(m(0, 0), 0); EXPECT_DOUBLE_EQ(m(0, 1), 2); EXPECT_DOUBLE_EQ(m(0, 2), 0); EXPECT_DOUBLE_EQ(m(0, 3), 2); EXPECT_DOUBLE_EQ(m(1, 0), 1); EXPECT_DOUBLE_EQ(m(1, 1), 3); EXPECT_DOUBLE_EQ(m(1, 2), 1); EXPECT_DOUBLE_EQ(m(1, 3), 3); EXPECT_DOUBLE_EQ(m(2, 0), 0); EXPECT_DOUBLE_EQ(m(2, 1), 2); EXPECT_DOUBLE_EQ(m(2, 2), 0); EXPECT_DOUBLE_EQ(m(2, 3), 2); EXPECT_DOUBLE_EQ(m(3, 0), 1); EXPECT_DOUBLE_EQ(m(3, 1), 3); EXPECT_DOUBLE_EQ(m(3, 2), 1); EXPECT_DOUBLE_EQ(m(3, 3), 3); + } + { + Matrix m; + m.setIdentity(); + EXPECT_DOUBLE_EQ(m(0, 0), 1); EXPECT_DOUBLE_EQ(m(0, 1), 0); EXPECT_DOUBLE_EQ(m(0, 2), 0); EXPECT_DOUBLE_EQ(m(0, 3), 0); EXPECT_DOUBLE_EQ(m(1, 0), 0); EXPECT_DOUBLE_EQ(m(1, 1), 1); EXPECT_DOUBLE_EQ(m(1, 2), 0); EXPECT_DOUBLE_EQ(m(1, 3), 0); EXPECT_DOUBLE_EQ(m(2, 0), 0); EXPECT_DOUBLE_EQ(m(2, 1), 0); EXPECT_DOUBLE_EQ(m(2, 2), 1); EXPECT_DOUBLE_EQ(m(2, 3), 0); EXPECT_DOUBLE_EQ(m(3, 0), 0); EXPECT_DOUBLE_EQ(m(3, 1), 0); EXPECT_DOUBLE_EQ(m(3, 2), 0); EXPECT_DOUBLE_EQ(m(3, 3), 1); + Matrix c; + c(0, 0) = 1.0; c(1, 0) = 2.0; c(2, 0) = 3.0; c(3, 0) = 4.0; + m.block(0, 0, 4, 1) = c; + m.block(0, 1, 4, 1) = c; + m.block(0, 2, 4, 1) = c; + m.block(0, 3, 4, 1) = c; + EXPECT_DOUBLE_EQ(m(0, 0), 1); EXPECT_DOUBLE_EQ(m(0, 1), 1); EXPECT_DOUBLE_EQ(m(0, 2), 1); EXPECT_DOUBLE_EQ(m(0, 3), 1); EXPECT_DOUBLE_EQ(m(1, 0), 2); EXPECT_DOUBLE_EQ(m(1, 1), 2); EXPECT_DOUBLE_EQ(m(1, 2), 2); EXPECT_DOUBLE_EQ(m(1, 3), 2); EXPECT_DOUBLE_EQ(m(2, 0), 3); EXPECT_DOUBLE_EQ(m(2, 1), 3); EXPECT_DOUBLE_EQ(m(2, 2), 3); EXPECT_DOUBLE_EQ(m(2, 3), 3); EXPECT_DOUBLE_EQ(m(3, 0), 4); EXPECT_DOUBLE_EQ(m(3, 1), 4); EXPECT_DOUBLE_EQ(m(3, 2), 4); EXPECT_DOUBLE_EQ(m(3, 3), 4); + Matrix b; + b(0, 0) = 0.0; b(1, 0) = 1.0; b(0, 1) = 2.0; b(1, 1) = 3.0; + m.block(0, 0, 2, 2) = b; + m.block(2, 0, 2, 2) = b; + m.block(0, 2, 2, 2) = b; + m.block(2, 2, 2, 2) = b; + EXPECT_DOUBLE_EQ(m(0, 0), 0); EXPECT_DOUBLE_EQ(m(0, 1), 2); EXPECT_DOUBLE_EQ(m(0, 2), 0); EXPECT_DOUBLE_EQ(m(0, 3), 2); EXPECT_DOUBLE_EQ(m(1, 0), 1); EXPECT_DOUBLE_EQ(m(1, 1), 3); EXPECT_DOUBLE_EQ(m(1, 2), 1); EXPECT_DOUBLE_EQ(m(1, 3), 3); EXPECT_DOUBLE_EQ(m(2, 0), 0); EXPECT_DOUBLE_EQ(m(2, 1), 2); EXPECT_DOUBLE_EQ(m(2, 2), 0); EXPECT_DOUBLE_EQ(m(2, 3), 2); EXPECT_DOUBLE_EQ(m(3, 0), 1); EXPECT_DOUBLE_EQ(m(3, 1), 3); EXPECT_DOUBLE_EQ(m(3, 2), 1); EXPECT_DOUBLE_EQ(m(3, 3), 3); + } +} diff --git a/labo01/tests/Tests1b.cpp b/labo01/tests/Tests1b.cpp new file mode 100644 index 0000000..b625751 --- /dev/null +++ b/labo01/tests/Tests1b.cpp @@ -0,0 +1,801 @@ +/** + * @file Tests1b.cpp + * + * @brief Tests unitaires de la partie 1b + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" +#include "Math3D.h" +#include "Operators.h" + +#include +#include + +using namespace gti320; + +namespace +{ + /** + * Multiplication matrice * vecteur, utilisant une implémentation naive + */ + template + static inline Vector<_Scalar, Dynamic> naiveMatrixMult(const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& A, const Vector<_Scalar, Dynamic>& v) + { + assert(A.cols() == v.rows()); + + Vector<_Scalar, Dynamic> b(A.rows()); + assert(b.rows() == A.rows()); + + for (int i = 0; i < A.rows(); ++i) { + b(i) = 0.0; + for (int j = 0; j < A.cols(); ++j) { + b(i) += A(i, j) * v(j); + } + } + + return b; + } + + /** + * Addition matrice + matrice, utilisant une implémentation naive + */ + template + static inline Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage> naiveMatrixAddition(const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& A, const Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage>& B) + { + assert(A.cols() == B.cols() && A.rows() == B.rows()); + + Matrix<_Scalar, Dynamic, Dynamic, ColumnStorage> C(A.rows(), A.cols()); + assert(C.rows() == A.rows() && C.cols() == A.cols()); + for (int i = 0; i < C.rows(); ++i) { + for (int j = 0; j < C.cols(); ++j) { + C(i, j) = A(i, j) + B(i, j); + } + } + return C; + } + + /** + * Multiplication matrice * matrice, utilisant une implémentation naive. + */ + template + static inline Matrix<_Scalar, Dynamic, Dynamic, _Storage> naiveMatrixMult(const Matrix<_Scalar, Dynamic, Dynamic, _Storage>& A, const Matrix<_Scalar, Dynamic, Dynamic, _Storage>& B) + { + assert(A.cols() == B.rows()); + Matrix<_Scalar, Dynamic, Dynamic> product(A.rows(), B.cols()); + for (int i = 0; i < A.rows(); ++i) + { + for (int j = 0; j < B.cols(); ++j) + { + for (int k = 0; k < A.cols(); ++k) + { + product(i, j) += A(i, k) * B(k, j); + } + } + } + return product; + } +} + +/** + * Test pour les opérateurs d'arithmétique matricielle. + */ +TEST(TestLabo1b, MatrixMatrixOperators) +{ + // Opérations arithmétiques avec matrices à taille dynamique + { + // Test : matrice identité + Matrix A(6, 6); + A.setIdentity(); + EXPECT_DOUBLE_EQ(A(0, 0), 1.0); + EXPECT_DOUBLE_EQ(A(1, 1), 1.0); + EXPECT_DOUBLE_EQ(A(2, 2), 1.0); + EXPECT_DOUBLE_EQ(A(3, 3), 1.0); + EXPECT_DOUBLE_EQ(A(4, 4), 1.0); + EXPECT_DOUBLE_EQ(A(5, 5), 1.0); + EXPECT_DOUBLE_EQ(A(0, 1), 0.0); + EXPECT_DOUBLE_EQ(A(1, 0), 0.0); + + // Test : produit scalaire * matrice + const double alpha = 2.5; + Matrix B = alpha * A; + EXPECT_DOUBLE_EQ(B(0, 0), alpha); + EXPECT_DOUBLE_EQ(B(1, 1), alpha); + EXPECT_DOUBLE_EQ(B(2, 2), alpha); + EXPECT_DOUBLE_EQ(B(3, 3), alpha); + EXPECT_DOUBLE_EQ(B(4, 4), alpha); + EXPECT_DOUBLE_EQ(B(5, 5), alpha); + EXPECT_DOUBLE_EQ(B(0, 1), 0.0); + EXPECT_DOUBLE_EQ(B(1, 0), 0.0); + + // Test : produit matrice * matrice + Matrix C = A * B; + EXPECT_DOUBLE_EQ(C(0, 0), A(0, 0) * B(0, 0)); + EXPECT_DOUBLE_EQ(C(1, 1), A(1, 1) * B(1, 1)); + EXPECT_DOUBLE_EQ(C(2, 2), A(2, 2) * B(2, 2)); + EXPECT_DOUBLE_EQ(C(3, 3), A(3, 3) * B(3, 3)); + EXPECT_DOUBLE_EQ(C(4, 4), A(4, 4) * B(4, 4)); + EXPECT_DOUBLE_EQ(C(5, 5), A(5, 5) * B(5, 5)); + EXPECT_DOUBLE_EQ(C(0, 1), 0.0); + EXPECT_DOUBLE_EQ(C(2, 3), 0.0); + + // Test : addition matrice * matrice + Matrix A_plus_B = A + B; + EXPECT_DOUBLE_EQ(A_plus_B(0, 0), A(0, 0) + B(0, 0)); + EXPECT_DOUBLE_EQ(A_plus_B(1, 1), A(1, 1) + B(1, 1)); + EXPECT_DOUBLE_EQ(A_plus_B(2, 2), A(2, 2) + B(2, 2)); + EXPECT_DOUBLE_EQ(A_plus_B(3, 3), A(3, 3) + B(3, 3)); + EXPECT_DOUBLE_EQ(A_plus_B(4, 4), A(4, 4) + B(4, 4)); + EXPECT_DOUBLE_EQ(A_plus_B(5, 5), A(5, 5) + B(5, 5)); + EXPECT_DOUBLE_EQ(A_plus_B(0, 1), 0.0); + EXPECT_DOUBLE_EQ(A_plus_B(2, 3), 0.0); + } + + // Opérations arithmétique avec matrices à stockage par lignes et par + // colonnes. + { + // Création d'un matrice à stockage par lignes + Matrix A(5, 5); + A(0, 0) = 0.8147; A(0, 1) = 0.0975; A(0, 2) = 0.1576; A(0, 3) = 0.1419; A(0, 4) = 0.6557; + A(1, 0) = 0.9058; A(1, 1) = 0.2785; A(1, 2) = 0.9706; A(1, 3) = 0.4218; A(1, 4) = 0.0357; + A(2, 0) = 0.1270; A(2, 1) = 0.5469; A(2, 2) = 0.9572; A(2, 3) = 0.9157; A(2, 4) = 0.8491; + A(3, 0) = 0.9134; A(3, 1) = 0.9575; A(3, 2) = 0.4854; A(3, 3) = 0.7922; A(3, 4) = 0.9340; + A(4, 0) = 0.6324; A(4, 1) = 0.9649; A(4, 2) = 0.8003; A(4, 3) = 0.9595; A(4, 4) = 0.6787; + + // Test : transposée (le résultat est une matrice à stockage par + // colonnes) + Matrix B = A.transpose(); + + // Test : multiplication matrix(ligne) * matrice(colonne) + // Note : teste seulement la première et la dernière colonne + const auto C = A * B; + EXPECT_NEAR(C(0, 0), 1.14815820000000, 1e-3); EXPECT_NEAR(C(0, 4), 1.31659795000000, 1e-3); + EXPECT_NEAR(C(1, 0), 1.00133748000000, 1e-3); EXPECT_NEAR(C(1, 4), 2.04727044000000, 1e-3); + EXPECT_NEAR(C(2, 0), 0.99433707000000, 1e-3); EXPECT_NEAR(C(2, 4), 2.82896409000000, 1e-3); + EXPECT_NEAR(C(3, 0), 1.63883925000000, 1e-3); EXPECT_NEAR(C(3, 4), 3.28401323000000, 1e-3); + EXPECT_NEAR(C(4, 0), 1.31659795000000, 1e-3); EXPECT_NEAR(C(4, 4), 3.35271580000000, 1e-3); + + + // Test : multiplication matrice(colonne) * matrice(ligne) + // Note : teste seulement la première et la dernière colonne + const auto C2 = B * A; + EXPECT_NEAR(C2(0, 0), 2.73456805000000, 1e-3); EXPECT_NEAR(C2(0, 4), 1.95669703000000, 1e-3); + EXPECT_NEAR(C2(1, 0), 1.88593811000000, 1e-3); EXPECT_NEAR(C2(1, 4), 2.08742862000000, 1e-3); + EXPECT_NEAR(C2(2, 0), 2.07860468000000, 1e-3); EXPECT_NEAR(C2(2, 4), 1.94727447000000, 1e-3); + EXPECT_NEAR(C2(3, 0), 1.94434955000000, 1e-3); EXPECT_NEAR(C2(3, 4), 2.27675041000000, 1e-3); + EXPECT_NEAR(C2(4, 0), 1.95669703000000, 1e-3); EXPECT_NEAR(C2(4, 4), 2.48517748000000, 1e-3); + + // Test : addition matrice(ligne) + matrice(ligne) + // Note : teste seulement la première et la dernière colonne + const auto A_plus_A = A + A; + EXPECT_DOUBLE_EQ(A_plus_A(0, 0), A(0, 0) + A(0, 0)); EXPECT_DOUBLE_EQ(A_plus_A(0, 4), A(0, 4) + A(0, 4)); + EXPECT_DOUBLE_EQ(A_plus_A(1, 0), A(1, 0) + A(1, 0)); EXPECT_DOUBLE_EQ(A_plus_A(1, 4), A(1, 4) + A(1, 4)); + EXPECT_DOUBLE_EQ(A_plus_A(2, 0), A(2, 0) + A(2, 0)); EXPECT_DOUBLE_EQ(A_plus_A(2, 4), A(2, 4) + A(2, 4)); + EXPECT_DOUBLE_EQ(A_plus_A(3, 0), A(3, 0) + A(3, 0)); EXPECT_DOUBLE_EQ(A_plus_A(3, 4), A(3, 4) + A(3, 4)); + EXPECT_DOUBLE_EQ(A_plus_A(4, 0), A(4, 0) + A(4, 0)); EXPECT_DOUBLE_EQ(A_plus_A(4, 4), A(4, 4) + A(4, 4)); + + // Test : addition matrice(colonne) + matrice(colonne) + // Note : teste seulement la première et la dernière colonne + const auto B_plus_B = B + B; + EXPECT_DOUBLE_EQ(B_plus_B(0, 0), B(0, 0) + B(0, 0)); EXPECT_DOUBLE_EQ(B_plus_B(0, 4), B(0, 4) + B(0, 4)); + EXPECT_DOUBLE_EQ(B_plus_B(1, 0), B(1, 0) + B(1, 0)); EXPECT_DOUBLE_EQ(B_plus_B(1, 4), B(1, 4) + B(1, 4)); + EXPECT_DOUBLE_EQ(B_plus_B(2, 0), B(2, 0) + B(2, 0)); EXPECT_DOUBLE_EQ(B_plus_B(2, 4), B(2, 4) + B(2, 4)); + EXPECT_DOUBLE_EQ(B_plus_B(3, 0), B(3, 0) + B(3, 0)); EXPECT_DOUBLE_EQ(B_plus_B(3, 4), B(3, 4) + B(3, 4)); + EXPECT_DOUBLE_EQ(B_plus_B(4, 0), B(4, 0) + B(4, 0)); EXPECT_DOUBLE_EQ(B_plus_B(4, 4), B(4, 4) + B(4, 4)); + + } +} + +/** + * Test pour la multiplication matrice * vecteur + */ +TEST(TestLabo1b, MatrixVectorOperators) +{ + // Vecteur à taille dynamique + Vector v(5); + v(0) = 1.0; + v(1) = 2.0; + v(2) = 4.0; + v(3) = 8.0; + v(4) = 16.0; + + // Test : multiplication par la matrice identité + { + Matrix M(5, 5); + M.setIdentity(); + + const auto b = M * v; + EXPECT_DOUBLE_EQ(b(0), 1.0); + EXPECT_DOUBLE_EQ(b(1), 2.0); + EXPECT_DOUBLE_EQ(b(2), 4.0); + EXPECT_DOUBLE_EQ(b(3), 8.0); + EXPECT_DOUBLE_EQ(b(4), 16.0); + } + + // Test : multiplication par une matrice à taille dynamique avec stockage par ligne. + { + Matrix M(5, 5); + M.setIdentity(); + M = 2.0 * M; + + Vector b2 = M * v; + EXPECT_DOUBLE_EQ(b2(0), 2.0); + EXPECT_DOUBLE_EQ(b2(1), 4.0); + EXPECT_DOUBLE_EQ(b2(2), 8.0); + EXPECT_DOUBLE_EQ(b2(3), 16.0); + EXPECT_DOUBLE_EQ(b2(4), 32.0); + } + // Test : autres + { + Vector u; u(0) = 89.63885274026418; u(1) = 33.98267508829284; u(2) = 58.18085749457168; + Matrix m33; + m33(0, 0) = -37.761291293282206; m33(0, 1) = -58.77833883088219; m33(0, 2) = -80.31292383738193; m33(1, 0) = 82.42200051847567; m33(1, 1) = -21.616077216647483; m33(1, 2) = -81.41765352024458; m33(2, 0) = -1.826095889555674; m33(2, 1) = -72.65845670305742; m33(2, 2) = -68.43559055076148; + Matrix m44; + m44(0, 0) = -0.6810804556978075; m44(0, 1) = -0.3717461369121619; m44(0, 2) = -0.6308202775413543; m44(0, 3) = 65.25663257716863; m44(1, 0) = -0.7322085856273928; m44(1, 1) = 0.3457881173505905; m44(1, 2) = 0.5867718168356992; m44(1, 3) = -72.82746334890318; m44(2, 0) = 0.0; m44(2, 1) = 0.8615308396047228; m44(2, 2) = -0.5077052416609282; m44(2, 3) = -50.951590508183095; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), -10054.998796995307, 1e-3); + EXPECT_NEAR(v(1), 1916.692541293076, 1e-3); + EXPECT_NEAR(v(2), -6614.459208480986, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -45.129230953732865, 1e-3); + EXPECT_NEAR(w(1), -92.57210823264782, 1e-3); + EXPECT_NEAR(w(2), -51.21319422167322, 1e-3); + } + { + Vector u; u(0) = 21.26102327359945; u(1) = -63.632003812151375; u(2) = 21.749676556807557; + Matrix m33; + m33(0, 0) = -72.46587508929531; m33(0, 1) = 26.74413795088728; m33(0, 2) = 66.40155978725781; m33(1, 0) = 30.554539344667063; m33(1, 1) = 34.707428553000256; m33(1, 2) = -78.73225643210714; m33(2, 0) = 29.88002386285075; m33(2, 1) = 84.40743250651678; m33(2, 2) = 89.33116036637102; + Matrix m44; + m44(0, 0) = -0.8156253236747055; m44(0, 1) = 0.0; m44(0, 2) = 0.5785804450381398; m44(0, 3) = -36.44550865077372; m44(1, 0) = -0.4886547783002762; m44(1, 1) = 0.5354367269787551; m44(1, 2) = -0.6888570381774334; m44(1, 3) = 26.24571159164249; m44(2, 0) = -0.3097932197851331; m44(2, 1) = -0.8445753438280554; m44(2, 2) = -0.43671575374937205; m44(2, 3) = 58.09911341828064; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), -1798.269296618443, 1e-3); + EXPECT_NEAR(v(1), -3271.2835658593685, 1e-3); + EXPECT_NEAR(v(2), -2792.8103398519333, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -41.2026000982854, 1e-3); + EXPECT_NEAR(w(1), -33.19691864907287, 1e-3); + EXPECT_NEAR(w(2), 95.75618766923024, 1e-3); + } + { + Vector u; u(0) = 60.89920397428068; u(1) = 41.99263628824008; u(2) = 2.8397811977043403; + Matrix m33; + m33(0, 0) = 37.756340946034896; m33(0, 1) = 34.695096214807364; m33(0, 2) = 71.82563147437446; m33(1, 0) = 74.91874228380777; m33(1, 1) = 11.371524438829937; m33(1, 2) = 22.662878030996694; m33(2, 0) = -33.183135422386044; m33(2, 1) = -48.81237469926953; m33(2, 2) = 77.28631280104915; + Matrix m44; + m44(0, 0) = 0.09071108841607319; m44(0, 1) = 0.15875989354807826; m44(0, 2) = -0.9831412892555038; m44(0, 3) = -20.28034322391565; m44(1, 0) = 0.8682639927927074; m44(1, 1) = -0.49610244790735053; m44(1, 2) = 0.0; m44(1, 3) = -65.91591665493024; m44(2, 0) = -0.487738800238444; m44(2, 1) = -0.8536261812883538; m44(2, 2) = -0.18284749208295362; m44(2, 3) = -28.08938117342305; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), 3960.2387427031354, 1e-3); + EXPECT_NEAR(v(1), 5104.369672559086, 1e-3); + EXPECT_NEAR(v(2), -3851.1106117734685, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -10.881269828726621, 1e-3); + EXPECT_NEAR(w(1), -33.87198031100272, 1e-3); + EXPECT_NEAR(w(2), -94.15754648234068, 1e-3); + } + { + Vector u; u(0) = 5.188467455547638; u(1) = 18.80451508110363; u(2) = -21.656727889135595; + Matrix m33; + m33(0, 0) = 87.9457818703861; m33(0, 1) = 73.05874068692381; m33(0, 2) = 39.940251688233246; m33(1, 0) = 75.10237717805055; m33(1, 1) = 72.18489393198146; m33(1, 2) = 99.55423077694917; m33(2, 0) = -23.406607601688265; m33(2, 1) = 36.642344803461384; m33(2, 2) = 59.655570064408465; + Matrix m44; + m44(0, 0) = 0.17067228277067772; m44(0, 1) = -0.6737686724718157; m44(0, 2) = -0.7189622715340582; m44(0, 3) = -18.335201879756795; m44(1, 0) = -0.9693828421385298; m44(1, 1) = -0.24555428191629253; m44(1, 2) = 0.0; m44(1, 3) = 29.845708309352148; m44(2, 0) = -0.1765442643114522; m44(2, 1) = 0.6969496901700587; m44(2, 2) = -0.6950491005034012; m44(2, 3) = -31.894796135192152; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), 965.1628555052321, 1e-3); + EXPECT_NEAR(v(1), -408.9507197542059, 1e-3); + EXPECT_NEAR(v(2), -724.347344278602, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -14.549197180540624, 1e-3); + EXPECT_NEAR(w(1), 20.198567783425617, 1e-3); + EXPECT_NEAR(w(2), -4.652500106271733, 1e-3); + } + { + Vector u; u(0) = 37.47349664672282; u(1) = -60.74514266373965; u(2) = -40.46471876369226; + Matrix m33; + m33(0, 0) = -18.595918421354753; m33(0, 1) = -63.34971612297557; m33(0, 2) = 51.78315639657973; m33(1, 0) = 60.68830258069576; m33(1, 1) = -63.44130757420927; m33(1, 2) = 0.1227343978225548; m33(2, 0) = 69.14823593166864; m33(2, 1) = 49.45675635266332; m33(2, 2) = 81.76280170074256; + Matrix m44; + m44(0, 0) = -0.250151688477416; m44(0, 1) = -0.2581347286114716; m44(0, 2) = -0.9331616122819132; m44(0, 3) = 15.902624286413442; m44(1, 0) = -0.7181238873483027; m44(1, 1) = 0.6959152839389017; m44(1, 2) = 0.0; m44(1, 3) = -12.358184768214258; m44(2, 0) = 0.6494014283720508; m44(2, 1) = 0.6701256445360971; m44(2, 2) = -0.3594570980846258; m44(2, 3) = -95.12313555065694; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), 1055.9425967082998, 1e-3); + EXPECT_NEAR(v(1), 6122.987769732011, 1e-3); + EXPECT_NEAR(v(2), -3721.5403091682488, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), 59.969118945113756, 1e-3); + EXPECT_NEAR(w(1), -81.54227105743792, 1e-3); + EXPECT_NEAR(w(2), -96.94934080054827, 1e-3); + } + { + Vector u; u(0) = -18.242981648343232; u(1) = 56.21809486615007; u(2) = 68.42388784251386; + Matrix m33; + m33(0, 0) = 72.32617531563085; m33(0, 1) = 16.921578626504015; m33(0, 2) = -27.34080821434577; m33(1, 0) = 75.31926937290174; m33(1, 1) = -81.4337114340538; m33(1, 2) = 49.516021610363254; m33(2, 0) = 40.651084247784695; m33(2, 1) = -19.615350275581747; m33(2, 2) = 96.61096468197644; + Matrix m44; + m44(0, 0) = 0.8628144975844739; m44(0, 1) = -0.39604187777629973; m44(0, 2) = 0.3141687027784186; m44(0, 3) = -15.592609294116613; m44(1, 0) = -0.5055206650158348; m44(1, 1) = -0.6759578736217757; m44(1, 2) = 0.5362180622943203; m44(1, 3) = 10.857285613068584; m44(2, 0) = 0.0; m44(2, 1) = -0.6214754895699024; m44(2, 2) = -0.7834336065448367; m44(2, 3) = -95.09026591014809; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), -2238.9105712501655, 1e-3); + EXPECT_NEAR(v(1), -2564.0174545638056, 1e-3); + EXPECT_NEAR(v(2), 4766.163205213616, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -32.1009941127323, 1e-3); + EXPECT_NEAR(w(1), 18.768550516577342, 1e-3); + EXPECT_NEAR(w(2), -183.634007166056, 1e-3); + } + { + Vector u; u(0) = -59.27939726364973; u(1) = 96.57872437189005; u(2) = -50.71931054476342; + Matrix m33; + m33(0, 0) = -53.51188145034156; m33(0, 1) = -39.773533094835024; m33(0, 2) = -81.91533947789623; m33(1, 0) = -48.98656664587613; m33(1, 1) = -30.35481126192778; m33(1, 2) = -24.41812181189411; m33(2, 0) = 50.987332445586844; m33(2, 1) = -15.614790715203753; m33(2, 2) = 1.953005394977339; + Matrix m44; + m44(0, 0) = -0.9781360701985449; m44(0, 1) = 0.0; m44(0, 2) = -0.20796593032645286; m44(0, 3) = 31.079492180635583; m44(1, 0) = 0.17988007252338098; m44(1, 1) = 0.5018585333987298; m44(1, 2) = -0.846038516832336; m44(1, 3) = 89.95140758767585; m44(2, 0) = 0.10436947679053606; m44(2, 1) = -0.8649497167205016; m44(2, 2) = -0.4908859336542387; m44(2, 3) = -66.61272043333199; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), 3485.5645301169448, 1e-3); + EXPECT_NEAR(v(1), 1210.7354976539962, 1e-3); + EXPECT_NEAR(v(2), -4629.6099911875845, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), 99.6106974667983, 1e-3); + EXPECT_NEAR(w(1), 170.66757254759543, 1e-3); + EXPECT_NEAR(w(2), -131.4380242858257, 1e-3); + } + { + Vector u; u(0) = -33.64679408120854; u(1) = 57.74585710730173; u(2) = -38.78100535372986; + Matrix m33; + m33(0, 0) = -48.76215910463826; m33(0, 1) = -17.88064937607517; m33(0, 2) = -10.666843689761578; m33(1, 0) = 54.129177432133815; m33(1, 1) = -50.3409670888066; m33(1, 2) = 67.92880818886752; m33(2, 0) = -36.14536761608753; m33(2, 1) = 92.53432169416001; m33(2, 2) = 68.69365938680332; + Matrix m44; + m44(0, 0) = 0.4751126538005149; m44(0, 1) = 0.5241078534879362; m44(0, 2) = -0.7068089728568109; m44(0, 3) = 7.21266115268952; m44(1, 0) = -0.7408885299063788; m44(1, 1) = 0.671628011813954; m44(1, 2) = 0.0; m44(1, 3) = -99.71424185587028; m44(2, 0) = 0.4747127051720829; m44(2, 1) = 0.5236666608245202; m44(2, 2) = 0.7074044641427562; m44(2, 3) = -11.057694172067542; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), 1021.8278247323343, 1e-3); + EXPECT_NEAR(v(1), -7362.603053042772, 1e-3); + EXPECT_NEAR(v(2), 3895.640286793221, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), 48.90246330164035, 1e-3); + EXPECT_NEAR(w(1), -36.001982853511294, 1e-3); + EXPECT_NEAR(w(2), -24.22453095406812, 1e-3); + } + { + Vector u; u(0) = 15.282052878141911; u(1) = -2.259998336973041; u(2) = 91.08586195638563; + Matrix m33; + m33(0, 0) = -88.39582865245377; m33(0, 1) = -64.58071224128338; m33(0, 2) = -4.675696828923634; m33(1, 0) = -86.1584474938788; m33(1, 1) = -34.543435043656444; m33(1, 2) = -62.495745585883625; m33(2, 0) = -59.183456388092395; m33(2, 1) = -57.14307430989349; m33(2, 2) = 44.41751022537625; + Matrix m44; + m44(0, 0) = 0.44386855289227883; m44(0, 1) = 0.5950916475208161; m44(0, 2) = 0.6699601770286612; m44(0, 3) = -72.72024311218823; m44(1, 0) = -0.8960919080949868; m44(1, 1) = 0.29477162558569525; m44(1, 2) = 0.33185686823727545; m44(1, 3) = 15.476209050615353; m44(2, 0) = 0.0; m44(2, 1) = -0.7476467212531113; m44(2, 2) = 0.6640966648007446; m44(2, 3) = 99.8824543736142; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), -1630.8073013173835, 1e-3); + EXPECT_NEAR(v(1), -6931.088700045262, 1e-3); + EXPECT_NEAR(v(2), 3270.5057477108207, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -6.258026348579378, 1e-3); + EXPECT_NEAR(w(1), 31.343370633361097, 1e-3); + EXPECT_NEAR(w(2), 162.0619518560263, 1e-3); + } + { + Vector u; u(0) = -45.53190350588168; u(1) = 98.18869916536156; u(2) = 82.67567746788419; + Matrix m33; + m33(0, 0) = -51.297389589304785; m33(0, 1) = -66.59459838930371; m33(0, 2) = 27.56805306675247; m33(1, 0) = 96.48690448918092; m33(1, 1) = 9.10079699500524; m33(1, 2) = 83.88487605323621; m33(2, 0) = 41.570057963368356; m33(2, 1) = 24.52264689542079; m33(2, 2) = -76.44940699537474; + Matrix m44; + m44(0, 0) = 0.774965095070908; m44(0, 1) = 0.0; m44(0, 2) = 0.6320040359220331; m44(0, 3) = -94.78257020280037; m44(1, 0) = -0.5539089538751407; m44(1, 1) = 0.4815245168438749; m44(1, 2) = 0.6792046896887713; m44(1, 3) = 63.87247725975902; m44(2, 0) = -0.3043254380407359; m44(2, 1) = -0.8764326212997054; m44(2, 2) = 0.3731646929748866; m44(2, 3) = -95.85244653326883; m44(3, 0) = 0.0; m44(3, 1) = 0.0; m44(3, 2) = 0.0; m44(3, 3) = 1.0; + Vector v = m33 * u; + EXPECT_NEAR(v(0), -1923.9617306372265, 1e-3); + EXPECT_NEAR(v(1), 3435.6019505357876, 1e-3); + EXPECT_NEAR(v(2), -5805.423584529748, 1e-3); + Vector w = m44 * u; + EXPECT_NEAR(w(0), -77.81684429970429, 1e-3); + EXPECT_NEAR(w(1), 192.52698008315832, 1e-3); + EXPECT_NEAR(w(2), -137.20006524672516, 1e-3); + } +} + +/** + * Opérateurs d'arithmétique vectorielle + */ +TEST(TestLabo1b, VectorOperators) +{ + Vector v(5); + v(0) = 0.1; + v(1) = 0.2; + v(2) = 0.4; + v(3) = 0.8; + v(4) = 1.6; + + // Test : multiplication scalaire * vecteur + const double alpha = 4.0; + const auto v2 = alpha * v; + EXPECT_DOUBLE_EQ(v2(0), alpha * v(0)); + EXPECT_DOUBLE_EQ(v2(1), alpha * v(1)); + EXPECT_DOUBLE_EQ(v2(2), alpha * v(2)); + EXPECT_DOUBLE_EQ(v2(3), alpha * v(3)); + EXPECT_DOUBLE_EQ(v2(4), alpha * v(4)); + + // Test : addition vecteur + vecteur + const auto v3 = v + v2; + EXPECT_DOUBLE_EQ(v3(0), v(0) + v2(0)); + EXPECT_DOUBLE_EQ(v3(1), v(1) + v2(1)); + EXPECT_DOUBLE_EQ(v3(2), v(2) + v2(2)); + EXPECT_DOUBLE_EQ(v3(3), v(3) + v2(3)); + EXPECT_DOUBLE_EQ(v3(4), v(4) + v2(4)); +} + +/** + * Mathématiques 3D + */ +TEST(TestLabo1b, Math3D) +{ + // Test : norme d'un vecteur de dimension 3 + Vector3d v; + v.setZero(); + v(1) = 2.0; + EXPECT_EQ(v.rows(), 3); + EXPECT_EQ(v.cols(), 1); + EXPECT_DOUBLE_EQ(v(0), 0.0); + EXPECT_DOUBLE_EQ(v(1), 2.0); + EXPECT_DOUBLE_EQ(v(2), 0.0); + EXPECT_DOUBLE_EQ(v.norm(), 2.0); + + // Test : calcul de la norme d'un deuxième vecteur 3D + Vector3d v2; + v2(0) = 4.0; + v2(1) = 2.0; + v2(2) = 5.0; + EXPECT_EQ(v2.rows(), 3); + EXPECT_EQ(v2.cols(), 1); + EXPECT_DOUBLE_EQ(v2(0), 4.0); + EXPECT_DOUBLE_EQ(v2(1), 2.0); + EXPECT_DOUBLE_EQ(v2(2), 5.0); + EXPECT_DOUBLE_EQ(v2.norm(), 6.7082039324993690892275210061938); + + // Test : produit scalaire + EXPECT_DOUBLE_EQ(v.dot(v2), 4.0); + + // Test : matrice identité 4x4 + Matrix4d M; + M.setIdentity(); + EXPECT_DOUBLE_EQ(M(0, 0), 1.0); + EXPECT_DOUBLE_EQ(M(0, 1), 0.0); + EXPECT_DOUBLE_EQ(M(0, 2), 0.0); + EXPECT_DOUBLE_EQ(M(1, 1), 1.0); + EXPECT_DOUBLE_EQ(M(1, 0), 0.0); + EXPECT_DOUBLE_EQ(M(1, 2), 0.0); + EXPECT_DOUBLE_EQ(M(2, 0), 0.0); + EXPECT_DOUBLE_EQ(M(2, 1), 0.0); + EXPECT_DOUBLE_EQ(M(2, 2), 1.0); + + // Test : création d'une matrice de rotation de 45 degrés autour de l'axe des x + const auto Rx = makeRotation(M_PI / 4.0, 0, 0); + EXPECT_NEAR(Rx(0, 0), 1, 1e-3); EXPECT_NEAR(Rx(0, 1), 0, 1e-3); EXPECT_NEAR(Rx(0, 2), 0, 1e-3); + EXPECT_NEAR(Rx(1, 0), 0, 1e-3); EXPECT_NEAR(Rx(1, 1), 0.7071, 1e-3); EXPECT_NEAR(Rx(1, 2), -0.7071, 1e-3); + EXPECT_NEAR(Rx(2, 0), 0, 1e-3); EXPECT_NEAR(Rx(2, 1), 0.7071, 1e-3); EXPECT_NEAR(Rx(2, 2), 0.7071, 1e-3); + + // Test : création d'une matrice de rotation de 45 degrés autour de l'axe des y + const auto Ry = makeRotation(0, M_PI / 4.0, 0); + EXPECT_NEAR(Ry(0, 0), 0.7071, 1e-3); EXPECT_NEAR(Ry(0, 1), 0, 1e-3); EXPECT_NEAR(Ry(0, 2), 0.7071, 1e-3); + EXPECT_NEAR(Ry(1, 0), 0, 1e-3); EXPECT_NEAR(Ry(1, 1), 1, 1e-3); EXPECT_NEAR(Ry(1, 2), 0, 1e-3); + EXPECT_NEAR(Ry(2, 0), -0.7071, 1e-3); EXPECT_NEAR(Ry(2, 1), 0, 1e-3); EXPECT_NEAR(Ry(2, 2), 0.7071, 1e-3); + + // Test : création d'une matrice de rotation de 45 degrés autour de l'axe des z + const auto Rz = makeRotation(0, 0, M_PI / 4.0); + EXPECT_NEAR(Rz(0, 0), 0.7071, 1e-3); EXPECT_NEAR(Rz(0, 1), -0.7071, 1e-3); EXPECT_NEAR(Rz(0, 2), 0, 1e-3); + EXPECT_NEAR(Rz(1, 0), 0.7071, 1e-3); EXPECT_NEAR(Rz(1, 1), 0.7071, 1e-3); EXPECT_NEAR(Rz(1, 2), 0, 1e-3); + EXPECT_NEAR(Rz(2, 0), 0, 1e-3); EXPECT_NEAR(Rz(2, 1), 0, 1e-3); EXPECT_NEAR(Rz(2, 2), 1, 1e-3); + + // Test : création d'une matrice de rotation quelconque. + const auto Rxyz = makeRotation(M_PI / 3.0, -M_PI / 6.0, M_PI / 4.0); + EXPECT_NEAR(Rxyz(0, 0), 0.6124, 1e-3); EXPECT_NEAR(Rxyz(0, 1), -0.6597, 1e-3); EXPECT_NEAR(Rxyz(0, 2), 0.4356, 1e-3); + EXPECT_NEAR(Rxyz(1, 0), 0.6124, 1e-3); EXPECT_NEAR(Rxyz(1, 1), 0.0474, 1e-3); EXPECT_NEAR(Rxyz(1, 2), -0.7891, 1e-3); + EXPECT_NEAR(Rxyz(2, 0), 0.5, 1e-3); EXPECT_NEAR(Rxyz(2, 1), 0.75, 1e-3); EXPECT_NEAR(Rxyz(2, 2), 0.4330, 1e-3); + + // Test : création d'une transformation homogène via la sous-matrice 3x3 en + // utilisant la fonction `block` + M.block(0, 0, 3, 3) = Rxyz; + M(0, 3) = -0.1; + M(1, 3) = 1.0; + M(2, 3) = 2.1; + + // Test : calcule l'inverse de la matrice M et vérifie que M^(-1) * M * v = v + const Matrix4d Minv = M.inverse(); + const Vector3d v3 = Minv * (M * v2); + EXPECT_DOUBLE_EQ(v3(0), v2(0)); + EXPECT_DOUBLE_EQ(v3(1), v2(1)); + EXPECT_DOUBLE_EQ(v3(2), v2(2)); + + // Test : translation d'un vecteur 3D effectuée avec une matrice 4x4 en coordonnées homogènes + Matrix4d T; + T.setIdentity(); + T(0, 3) = 1.2; + T(1, 3) = 2.5; + T(2, 3) = -4.0; + const Vector3d t = T * v3; + EXPECT_DOUBLE_EQ(t(0), v3(0) + 1.2); + EXPECT_DOUBLE_EQ(t(1), v3(1) + 2.5); + EXPECT_DOUBLE_EQ(t(2), v3(2) - 4.0); + + // Test : inverse d'un matrice de rotation + const Matrix3d Rinv = Rxyz.inverse(); + const Matrix3d RT = Rxyz.transpose(); + EXPECT_DOUBLE_EQ(Rinv(0, 0), RT(0, 0)); + EXPECT_DOUBLE_EQ(Rinv(1, 1), RT(1, 1)); + EXPECT_DOUBLE_EQ(Rinv(0, 2), RT(0, 2)); +} + +TEST(TestLabo1b, RigidTransformInverse) { + { + Matrix m; + m(0, 0) = -0.7899179842354741; m(0, 1) = 0.5558875173441905; m(0, 2) = 0.2588795979645317; m(0, 3) = 63.53646575655944; m(1, 0) = -0.6132125065435026; m(1, 1) = -0.7160740240561843; m(1, 2) = -0.3334792555626483; m(1, 3) = 46.40415080808421; m(2, 0) = 0.0; m(2, 1) = -0.4221694684991984; m(2, 2) = 0.9065169275127214; m(2, 3) = 37.91755407005138; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.7899179842354742, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.6132125065435026, 1e-3); + EXPECT_NEAR(mi(0, 2), 5.0321798256853854e-17, 1e-3); + EXPECT_NEAR(mi(0, 3), 78.64420258691568, 1e-3); + EXPECT_NEAR(mi(1, 0), 0.5558875173441905, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.7160740240561843, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.42216946849919834, 1e-3); + EXPECT_NEAR(mi(1, 3), 13.917312440360101, 1e-3); + EXPECT_NEAR(mi(2, 0), 0.25887959796453164, 1e-3); + EXPECT_NEAR(mi(2, 1), -0.33347925556264824, 1e-3); + EXPECT_NEAR(mi(2, 2), 0.9065169275127212, 1e-3); + EXPECT_NEAR(mi(2, 3), -35.34637765902901, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = 0.6589112893907124; m(0, 1) = -0.32720889915223983; m(0, 2) = 0.6773258071482646; m(0, 3) = -47.579657162583366; m(1, 0) = -0.7522206542720485; m(1, 1) = -0.2866202043457096; m(1, 2) = 0.5933067888937011; m(1, 3) = 30.029355381737275; m(2, 0) = 0.0; m(2, 1) = -0.9004350030826229; m(2, 2) = -0.4349905806147956; m(2, 3) = 80.66547089822612; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), 0.6589112893907124, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.7522206542720486, 1e-3); + EXPECT_NEAR(mi(0, 2), 5.551115123125783e-17, 1e-3); + EXPECT_NEAR(mi(0, 3), 53.939474602384124, 1e-3); + EXPECT_NEAR(mi(1, 0), -0.3272088991522398, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.28662020434570956, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.9004350030826228, 1e-3); + EXPECT_NEAR(mi(1, 3), 65.67254627057903, 1e-3); + EXPECT_NEAR(mi(2, 0), 0.6773258071482645, 1e-3); + EXPECT_NEAR(mi(2, 1), 0.5933067888937011, 1e-3); + EXPECT_NEAR(mi(2, 2), -0.43499058061479545, 1e-3); + EXPECT_NEAR(mi(2, 3), 49.49902929898342, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.12921677297502387; m(0, 1) = 0.0; m(0, 2) = -0.9916163701663668; m(0, 3) = -85.67624239250289; m(1, 0) = 0.5536164401240612; m(1, 1) = -0.8296411663169171; m(1, 2) = -0.07214133611645579; m(1, 3) = -80.61895745285052; m(2, 0) = -0.8226857618837724; m(2, 1) = -0.5582969954713223; m(2, 2) = 0.1072035542387071; m(2, 3) = -59.16846832515195; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.12921677297502387, 1e-3); + EXPECT_NEAR(mi(0, 1), 0.5536164401240611, 1e-3); + EXPECT_NEAR(mi(0, 2), -0.8226857618837723, 1e-3); + EXPECT_NEAR(mi(0, 3), -15.115883774598393, 1e-3); + EXPECT_NEAR(mi(1, 0), -0.0, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.829641166316917, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.5582969954713222, 1e-3); + EXPECT_NEAR(mi(1, 3), -99.91838398100924, 1e-3); + EXPECT_NEAR(mi(2, 0), -0.991616370166367, 1e-3); + EXPECT_NEAR(mi(2, 1), -0.07214133611645579, 1e-3); + EXPECT_NEAR(mi(2, 2), 0.10720355423870709, 1e-3); + EXPECT_NEAR(mi(2, 3), -84.43085369439521, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = 0.6178488588834932; m(0, 1) = 0.656563779114608; m(0, 2) = 0.4326508887441579; m(0, 3) = -3.573389719025613; m(1, 0) = -0.7862968825935693; m(1, 1) = 0.5159084191865928; m(1, 2) = 0.33996428553015007; m(1, 3) = 9.98340634305292; m(2, 0) = 0.0; m(2, 1) = -0.5502385909468138; m(2, 2) = 0.8350074808244923; m(2, 3) = 57.03623931292819; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), 0.6178488588834931, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.7862968825935694, 1e-3); + EXPECT_NEAR(mi(0, 2), -0.0, 1e-3); + EXPECT_NEAR(mi(0, 3), 10.057736045453359, 1e-3); + EXPECT_NEAR(mi(1, 0), 0.656563779114608, 1e-3); + EXPECT_NEAR(mi(1, 1), 0.5159084191865929, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.5502385909468138, 1e-3); + EXPECT_NEAR(mi(1, 3), 28.57917482608178, 1e-3); + EXPECT_NEAR(mi(2, 0), 0.4326508887441579, 1e-3); + EXPECT_NEAR(mi(2, 1), 0.33996428553015007, 1e-3); + EXPECT_NEAR(mi(2, 2), 0.8350074808244924, 1e-3); + EXPECT_NEAR(mi(2, 3), -49.473657871198526, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.30532791727234754; m(0, 1) = 0.42993321248800975; m(0, 2) = -0.8496659906892062; m(0, 3) = -4.900019523419871; m(1, 0) = -0.9522472698486095; m(1, 1) = -0.13785349298616878; m(1, 2) = 0.272436325656807; m(1, 3) = 61.254180348498465; m(2, 0) = 0.0; m(2, 1) = 0.8922745358191345; m(2, 2) = 0.45149324771113447; m(2, 3) = 41.98722428204593; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.3053279172723474, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.9522472698486094, 1e-3); + EXPECT_NEAR(mi(0, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(0, 3), 56.83301324799237, 1e-3); + EXPECT_NEAR(mi(1, 0), 0.42993321248800975, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.13785349298616878, 1e-3); + EXPECT_NEAR(mi(1, 2), 0.8922745358191346, 1e-3); + EXPECT_NEAR(mi(1, 3), -26.91334720059331, 1e-3); + EXPECT_NEAR(mi(2, 0), -0.8496659906892063, 1e-3); + EXPECT_NEAR(mi(2, 1), 0.27243632565680703, 1e-3); + EXPECT_NEAR(mi(2, 2), 0.4514932477111345, 1e-3); + EXPECT_NEAR(mi(2, 3), -39.80819202150404, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.8426665329724763; m(0, 1) = -0.13329457405486883; m(0, 2) = 0.5216758291656588; m(0, 3) = 54.75958681320196; m(1, 0) = -0.5384358032376251; m(1, 1) = 0.20860959822407732; m(1, 2) = -0.81643672217793; m(1, 3) = 91.96965943681118; m(2, 0) = 0.0; m(2, 1) = -0.9688728461755547; m(2, 2) = -0.24755889792871488; m(2, 3) = 99.00199341303772; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.8426665329724762, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.5384358032376252, 1e-3); + EXPECT_NEAR(mi(0, 2), -2.7755575615628914e-17, 1e-3); + EXPECT_NEAR(mi(0, 3), 95.66382861923651, 1e-3); + EXPECT_NEAR(mi(1, 0), -0.13329457405486886, 1e-3); + EXPECT_NEAR(mi(1, 1), 0.20860959822407737, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.9688728461755547, 1e-3); + EXPECT_NEAR(mi(1, 3), 84.03374523091135, 1e-3); + EXPECT_NEAR(mi(2, 0), 0.5216758291656588, 1e-3); + EXPECT_NEAR(mi(2, 1), -0.8164367221779302, 1e-3); + EXPECT_NEAR(mi(2, 2), -0.2475588979287149, 1e-3); + EXPECT_NEAR(mi(2, 3), 71.02947881694217, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.7135830808790772; m(0, 1) = 0.0; m(0, 2) = -0.7005706150582712; m(0, 3) = 46.98894352455778; m(1, 0) = 0.5815768734392242; m(1, 1) = 0.5575439866421585; m(1, 2) = -0.5923791380862643; m(1, 3) = -32.31315706340996; m(2, 0) = 0.39059893364393755; m(2, 1) = -0.8301473983330724; m(2, 2) = -0.39785395571371457; m(2, 3) = 7.702713412699751; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.7135830808790772, 1e-3); + EXPECT_NEAR(mi(0, 1), 0.581576873439224, 1e-3); + EXPECT_NEAR(mi(0, 2), 0.39059893364393744, 1e-3); + EXPECT_NEAR(mi(0, 3), 49.314428298230084, 1e-3); + EXPECT_NEAR(mi(1, 0), -5.551115123125783e-17, 1e-3); + EXPECT_NEAR(mi(1, 1), 0.5575439866421584, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.8301473983330723, 1e-3); + EXPECT_NEAR(mi(1, 3), 24.41039390978577, 1e-3); + EXPECT_NEAR(mi(2, 0), -0.7005706150582711, 1e-3); + EXPECT_NEAR(mi(2, 1), -0.5923791380862641, 1e-3); + EXPECT_NEAR(mi(2, 2), -0.3978539557137144, 1e-3); + EXPECT_NEAR(mi(2, 3), 16.841987936840617, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = 0.655199358191179; m(0, 1) = -0.7015590749923188; m(0, 2) = 0.2802296653136303; m(0, 3) = -24.378695814492147; m(1, 0) = -0.7554560219005917; m(1, 1) = -0.6084550818878111; m(1, 2) = 0.24304035117451178; m(1, 3) = 36.943036725120294; m(2, 0) = 0.0; m(2, 1) = -0.3709410702804682; m(2, 2) = -0.928656407063011; m(2, 3) = -32.64950630748629; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), 0.6551993581911789, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.7554560219005915, 1e-3); + EXPECT_NEAR(mi(0, 2), 5.1550786254351327e-17, 1e-3); + EXPECT_NEAR(mi(0, 3), 43.88174541248007, 1e-3); + EXPECT_NEAR(mi(1, 0), -0.7015590749923187, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.6084550818878111, 1e-3); + EXPECT_NEAR(mi(1, 2), -0.37094107028046824, 1e-3); + EXPECT_NEAR(mi(1, 3), -6.735959663194609, 1e-3); + EXPECT_NEAR(mi(2, 0), 0.28022966531363025, 1e-3); + EXPECT_NEAR(mi(2, 1), 0.24304035117451175, 1e-3); + EXPECT_NEAR(mi(2, 2), -0.9286564070630109, 1e-3); + EXPECT_NEAR(mi(2, 3), -32.467188070139514, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.12316316348384228; m(0, 1) = 0.47851608243384774; m(0, 2) = -0.8693981792095123; m(0, 3) = -97.68194268706864; m(1, 0) = -0.9684362001788849; m(1, 1) = -0.24926156178416892; m(1, 2) = 0.0; m(1, 3) = -93.30408292578261; m(2, 0) = -0.2167075479620758; m(2, 1) = 0.8419566691161013; m(2, 2) = 0.4941121390809829; m(2, 3) = -48.17348057895294; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.12316316348384225, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.9684362001788847, 1e-3); + EXPECT_NEAR(mi(0, 2), -0.2167075479620758, 1e-3); + EXPECT_NEAR(mi(0, 3), -112.82942545947078, 1e-3); + EXPECT_NEAR(mi(1, 0), 0.47851608243384763, 1e-3); + EXPECT_NEAR(mi(1, 1), -0.2492615617841688, 1e-3); + EXPECT_NEAR(mi(1, 2), 0.8419566691161011, 1e-3); + EXPECT_NEAR(mi(1, 3), 64.04524235620795, 1e-3); + EXPECT_NEAR(mi(2, 0), -0.8693981792095123, 1e-3); + EXPECT_NEAR(mi(2, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(2, 2), 0.49411213908098284, 1e-3); + EXPECT_NEAR(mi(2, 3), -61.12140157794279, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } + { + Matrix m; + m(0, 0) = -0.8820615884895145; m(0, 1) = -0.11346792289034995; m(0, 2) = -0.45726620757093356; m(0, 3) = -48.8253349197771; m(1, 0) = -0.12758811649101956; m(1, 1) = 0.9918272392560481; m(1, 2) = 0.0; m(1, 3) = 50.033634014775515; m(2, 0) = 0.4535290802601621; m(2, 1) = 0.058341734158967; m(2, 2) = -0.8893298687290875; m(2, 3) = 92.22065810812657; m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0; + Matrix mi = m.inverse(); + EXPECT_NEAR(mi(0, 0), -0.8820615884895142, 1e-3); + EXPECT_NEAR(mi(0, 1), -0.12758811649101953, 1e-3); + EXPECT_NEAR(mi(0, 2), 0.453529080260162, 1e-3); + EXPECT_NEAR(mi(0, 3), -78.50800560549041, 1e-3); + EXPECT_NEAR(mi(1, 0), -0.11346792289034992, 1e-3); + EXPECT_NEAR(mi(1, 1), 0.991827239256048, 1e-3); + EXPECT_NEAR(mi(1, 2), 0.05834173415896697, 1e-3); + EXPECT_NEAR(mi(1, 3), -60.545143551904374, 1e-3); + EXPECT_NEAR(mi(2, 0), -0.45726620757093345, 1e-3); + EXPECT_NEAR(mi(2, 1), 6.120531779240618e-18, 1e-3); + EXPECT_NEAR(mi(2, 2), -0.8893298687290875, 1e-3); + EXPECT_NEAR(mi(2, 3), 59.68841003726312, 1e-3); + EXPECT_NEAR(mi(3, 0), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 1), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 2), 0.0, 1e-3); + EXPECT_NEAR(mi(3, 3), 1.0, 1e-3); + } +} + +/** + * Test des performance de la multiplication matrice * vecteur + * pour de grandes dimensions. + */ +TEST(TestLabo1b, PerformanceMatrixVector) +{ + Matrix A(16384, 16384); // grande matrice avec stockage colonne + Vector v(16384); // grand vecteur + + using namespace std::chrono; + // Test : multiplication avec l'algorithme naif. + high_resolution_clock::time_point t = high_resolution_clock::now(); + naiveMatrixMult(A, v); + const duration naive_t = duration_cast>(high_resolution_clock::now() - t); + + // Test : multiplication avec l'implémentation spécifique pour les matrices avec + // stockage par colonnes. + t = high_resolution_clock::now(); + A* v; + const duration optimal_t = duration_cast>(high_resolution_clock::now() - t); + + EXPECT_TRUE(optimal_t < 0.4 * naive_t) + << "Naive time: " << duration_cast(naive_t).count() << " ms, " + << "optimized time: " << duration_cast(optimal_t).count() << " ms"; +} + +/** + * Test des performances de l'addition matrice + matrice + * pour de grandes dimensions. + */ +TEST(TestLabo1b, PerformanceLargeMatrixMatrix) +{ + // deux grandes matrices à stockage par colonnes + Matrix A(16384, 16384); + Matrix B(16384, 16384); + + using namespace std::chrono; + high_resolution_clock::time_point t = high_resolution_clock::now(); + // Test : addition avec l'algorithme naif + naiveMatrixAddition(A, B); + const duration naive_t = duration_cast>(high_resolution_clock::now() - t); + + // Test : addition avec l'implémentation spécifique pour les matrices à + // stockage par colonnes. + t = high_resolution_clock::now(); + A + B; + const duration optimal_t = duration_cast>(high_resolution_clock::now() - t); + + EXPECT_TRUE(optimal_t < 0.4 * naive_t); +} + +/** + * Test pour la matrice à taille fixe 4D + */ +TEST(TestLabo1b, Matrix4x4SizeTest) +{ + Matrix4d M; + + EXPECT_EQ(M.cols(), 4); + EXPECT_EQ(M.rows(), 4); +} + +/** + * Test pour la matrice à taille fixe 3D + */ +TEST(TestLabo1b, Matrix3x3SizeTest) +{ + Matrix3d M; + + EXPECT_EQ(M.cols(), 3); + EXPECT_EQ(M.rows(), 3); +} diff --git a/labo01/tests/TestsSupplementaire1a.cpp b/labo01/tests/TestsSupplementaire1a.cpp new file mode 100644 index 0000000..23a2c46 --- /dev/null +++ b/labo01/tests/TestsSupplementaire1a.cpp @@ -0,0 +1,54 @@ +/** + * @file TestsSupplementaire1a.cpp + * + * @brief Tests unitaires supplémentaires de la partie 1a + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" + +#include + +using namespace gti320; + +TEST(TestLabo1a, Supplementaires) +{ + // TODO vos propres tests ici + + // TEST 1 + // + + // TEST 2 + // + + // TEST 3 + // + + // TEST 4 + // + + // TEST 5 + // + + // TEST 6 + // + + // TEST 7 + // + + // TEST 8 + // + + // TEST 9 + // + + // TEST 10 + // + + EXPECT_TRUE(false); +} diff --git a/labo01/tests/TestsSupplementaire1b.cpp b/labo01/tests/TestsSupplementaire1b.cpp new file mode 100644 index 0000000..0da8450 --- /dev/null +++ b/labo01/tests/TestsSupplementaire1b.cpp @@ -0,0 +1,56 @@ +/** + * @file TestsSupplementaire1b.cpp + * + * @brief Tests unitaires supplémentaires de la partie 1b + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "Matrix.h" +#include "Vector.h" +#include "Math3D.h" +#include "Operators.h" + +#include + +using namespace gti320; + +TEST(TestLabo1b, Supplementaires) +{ + // TODO vos propres tests ici + + // TEST 1 + // + + // TEST 2 + // + + // TEST 3 + // + + // TEST 4 + // + + // TEST 5 + // + + // TEST 6 + // + + // TEST 7 + // + + // TEST 8 + // + + // TEST 9 + // + + // TEST 10 + // + + EXPECT_TRUE(false); +} diff --git a/labo_ik/Armature.cpp b/labo_ik/Armature.cpp new file mode 100644 index 0000000..d3afa80 --- /dev/null +++ b/labo_ik/Armature.cpp @@ -0,0 +1,74 @@ +#pragma once + +#include "Armature.h" + +using namespace gti320; + +// Constructor +// +Link::Link(Link* _parent, const Vector3f& _eulerAng, const Vector3f& _trans) : + parent(_parent), eulerAng(_eulerAng), trans(_trans) +{ + if (parent != nullptr) + { + parent->enfants.push_back(this); + } + M.setIdentity(); +} + +void Link::forward() +{ + // TODO Create a rotation matrix from the Euler angles + // of the current link. + + // TODO Create a local 4D rigid transformation matrix from the + // 3D rotation matrix and translation of the current link. + + // TODO Update the global transformation for the link using the + // parent's rigid transformation matrix and the local transformation. + // Hint : the parent matrix should be post-multiplied. + // Hint : the root does not have a parent. You must consider this case. + + // TODO Update the transformation of child links + // by recursion. + +} + + +Armature::Armature() : links(), root(nullptr) +{ + +} + +Armature::~Armature() +{ + for (Link* l : links) + { + delete l; + } +} + +void Armature::updateKinematics() +{ + assert(root != nullptr); + root->forward(); +} + +void Armature::pack(Vector& theta) +{ + // TODO Collect the Euler angles of each link and put them + // into the dense vector @a theta + +} + +void Armature::unpack(const Vector& theta) +{ + const int numLinks = links.size(); + assert(theta.size() == 3 * numLinks); + + // TODO Extract the Euler angles contained in the + // dense vector @a theta and update the angles + // for each link in the armature. + // + +} diff --git a/labo_ik/Armature.h b/labo_ik/Armature.h new file mode 100644 index 0000000..38f602c --- /dev/null +++ b/labo_ik/Armature.h @@ -0,0 +1,64 @@ +#pragma once + +#include "Math3D.h" +#include + +namespace gti320 +{ + class Link + { + public: + // Constructor. + // @a _parent = the parent link + // @a _eulerAng = the initial rotation + // @a _trans = the position relative to the parent + // + Link(Link* _parent, const Vector3f& _eulerAng, const Vector3f& _trans); + + // Return true if this link is the root, false otherwise. + // + inline bool isRoot() const { return (parent == nullptr); } + + // Return true if this link is an endEffector, false otherwise. + // + inline bool isEndEffector() const { return (enfants.size() == 0); } + + // Compute the forward kinematics. + // + void forward(); + + Vector3f eulerAng; // Euler angles giving rotation relative to the parent. + Vector3f trans; // Translation giving position relative to the parent. + Matrix4f M; // Global rigid transformation of the link, computed in forward(). + Link* parent; // Parent of this link (if the root, nullptr) + std::vector enfants; // Child links. + }; + + class Armature + { + public: + // Constructor. + // + Armature(); + + // Destructor. + // + ~Armature(); + + // Forward kinematics to update the global transforms of all links. + // + void updateKinematics(); + + // Extract the Euler angles of all links and put them in the dense vector @a theta. + // + void pack(Vector& theta); + + // Update the Euler angles of all links on the armature from the vector @a theta. + // + void unpack(const Vector& theta); + + std::vector links; // All of the articulated links that make-up the armature. + Link* root; // The root link. + }; +} + diff --git a/labo_ik/CMakeLists.txt b/labo_ik/CMakeLists.txt new file mode 100644 index 0000000..3ed646b --- /dev/null +++ b/labo_ik/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.15) + +project(labo_ik) + +# Setup language requirements +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +#-------------------------------------------------- +# Sous MAC, OpenGL est Deprecated, mais toujours +# fonctionnel, on veut éviter tous les warnings +# durant la compilation. +#-------------------------------------------------- +if (APPLE) + add_definitions( -DGL_SILENCE_DEPRECATION ) +endif() + +add_definitions(${NANOGUI_EXTRA_DEFS}) +include_directories(${nanogui_SRC_DIR}/include) +include_directories(${NANOGUI_EXTRA_INCS}) +include_directories(${PROJECT_SOURCE_DIR}/../labo01/src ${COMMON_INCLUDES}) + +find_package(OpenGL REQUIRED) + +# Add .cpp and .h files +set(HEADERS IKApplication.h IKGLCanvas.h LinkUI.h TargetUI.h Armature.h IKSolver.h SVD.h) +set(SOURCE main.cpp IKApplication.cpp IKGLCanvas.cpp LinkUI.cpp TargetUI.cpp Armature.cpp IKSolver.cpp) +add_executable(labo_ik ${SOURCE} ${HEADERS}) + +target_link_libraries(labo_ik nanogui opengl32 ${NANOGUI_EXTRA_LIBS}) + +if(MSVC) + set_property(TARGET labo_ik PROPERTY VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/labo_ik) +endif() \ No newline at end of file diff --git a/labo_ik/IKApplication.cpp b/labo_ik/IKApplication.cpp new file mode 100644 index 0000000..c7fb27c --- /dev/null +++ b/labo_ik/IKApplication.cpp @@ -0,0 +1,189 @@ +#include "IKApplication.h" +#include "IKGLCanvas.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _USE_MATH_DEFINES +#include + +#include "IKSolver.h" + +using namespace nanogui; + +namespace +{ + // Random number generator. + // Returns a random value such that _min <= val <= _max + // + template + static inline _Scalar rand(_Scalar _min, _Scalar _max) + { + static std::random_device rdev; + static std::default_random_engine re(rdev()); + + // Using uniform distribution (recommended since C++11) + typedef typename std::conditional< + std::is_floating_point<_Scalar>::value, + std::uniform_real_distribution<_Scalar>, + std::uniform_int_distribution<_Scalar>>::type dist_type; + dist_type uni(_min, _max); + return static_cast<_Scalar>(uni(re)); + } + +} + +IKApplication::IKApplication() : Screen(Vector2i(1280, 720), "GTI320 Labo sur la cinematique inverse"), +m_targetPos() +{ + m_armature = std::make_unique(); + m_ikSolver = std::make_unique(m_armature.get(), m_targetPos); + + initializeTarget(); + initializeArmature(); + + m_window = new Window(this, "Cinematique inverse"); + m_window->set_position(Vector2i(8, 8)); + m_window->set_layout(new GroupLayout()); + + m_canvas = std::make_unique(this); + m_canvas->set_background_color({ 255, 255, 255, 255 }); + m_canvas->set_size({ 1080, 600 }); + + Window* controls = new Window(this, "Controls"); + controls->set_position(Vector2i(1020, 10)); + controls->set_layout(new GroupLayout()); + + Widget* tools = new Widget(controls); + tools->set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle, 0, 5)); + + m_targetUI = std::make_unique(tools, m_targetPos); + + const int numLinks = m_armature->links.size(); + for (int i = 0; i < numLinks; ++i) + { + gti320::Link* link = m_armature->links[i]; + if (!link->isEndEffector()) + { + m_linkUIArr.push_back(new LinkUI(m_armature->links[i], i, tools)); + } + } + + Button* solveButton = new Button(tools, "IK solve"); + solveButton->set_callback([this] + { + ikSolve(); + }); + + Button* resetButton = new Button(tools, "Reset"); + resetButton->set_callback([this] + { + reset(); + }); + + perform_layout(); + reset(); +} + +bool IKApplication::keyboard_event(int key, int scancode, int action, int modifiers) +{ + if (Screen::keyboard_event(key, scancode, action, modifiers)) + return true; + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + set_visible(false); + return true; + } + return false; +} + +void IKApplication::draw(NVGcontext* ctx) +{ + assert(m_armature->root != nullptr); + + m_armature->updateKinematics(); + + // Draw the user interface + Screen::draw(ctx); +} + +void IKApplication::reset() +{ + // Reset all joints to zero angle + // + for (gti320::Link* l : m_armature->links) + { + l->eulerAng.setZero(); + } + + // Update the armature + // + m_armature->updateKinematics(); + + // Update UI + // + for (LinkUI* ui : m_linkUIArr) + { + ui->onArmatureChanged(); + } +} + +void IKApplication::ikSolve() +{ + m_ikSolver->solve(); + for (LinkUI* ui : m_linkUIArr) + { + ui->onArmatureChanged(); + } +} + +void IKApplication::initializeArmature() +{ + // Initialize the armature + // + gti320::Vector3f angs; + angs.setZero(); + gti320::Vector3f t; + + // Root + t.setZero(); + gti320::Link* link0 = new gti320::Link(nullptr, angs, t); + + // First joint + t(1) = 1.5f; + gti320::Link* link1 = new gti320::Link(link0, angs, t); + + // Second joint + t(1) = 0.75f; + gti320::Link* link2 = new gti320::Link(link1, angs, t); + + // End-effector + t(1) = 0.25f; + gti320::Link* link3 = new gti320::Link(link2, angs, t); + + m_armature->links.push_back(link0); + m_armature->links.push_back(link1); + m_armature->links.push_back(link2); + m_armature->links.push_back(link3); + m_armature->root = link0; +} + +void IKApplication::initializeTarget() +{ + m_targetPos(0) = 1.0f; + m_targetPos(1) = 1.0f; + m_targetPos(2) = 0.0f; +} diff --git a/labo_ik/IKApplication.h b/labo_ik/IKApplication.h new file mode 100644 index 0000000..1bc20dd --- /dev/null +++ b/labo_ik/IKApplication.h @@ -0,0 +1,64 @@ +#pragma once + +/** + * @file IKApplication.h + * + * @brief Application class for labo 2. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Armature.h" +#include "LinkUI.h" +#include "TargetUI.h" +#include "IKSolver.h" +#include "Math3D.h" + +class IKGLCanvas; + +// Iterative closest point algorithm +// +class IKApplication : public nanogui::Screen +{ +public: + IKApplication(); + + virtual bool keyboard_event(int key, int scancode, int action, int modifiers) override; + + virtual void draw(NVGcontext *ctx) override; + + nanogui::Window* getWindow() { return m_window.get(); } + + gti320::Armature* getArmature() const { return m_armature.get(); } + + const gti320::Vector3f& getTargetPos() const { return m_targetPos; } + +private: + + // Reset the source transform and the initial transform. + // + void reset(); + void ikSolve(); + void initializeArmature(); + void initializeTarget(); + + std::unique_ptr m_ikSolver; + std::unique_ptr m_canvas; + nanogui::ref m_window; + + std::vector m_linkUIArr; + std::unique_ptr m_targetUI; + std::unique_ptr m_armature; + gti320::Vector3f m_targetPos; +}; \ No newline at end of file diff --git a/labo_ik/IKGLCanvas.cpp b/labo_ik/IKGLCanvas.cpp new file mode 100644 index 0000000..2e09f69 --- /dev/null +++ b/labo_ik/IKGLCanvas.cpp @@ -0,0 +1,372 @@ +#include "IKGLCanvas.h" + +#include "IKApplication.h" +#include "Armature.h" + +#include +#include + +using namespace nanogui; + +namespace +{ + static int numCubeVerts, numSphereVerts; + static std::vector cubeVerts, sphereVerts; + static std::vector cubeNormals, sphereNormals; + + static float axesVerts[] = { + 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, + }; + + static float axesColors[] = { + 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + }; + + // Load OBJ file + int loadFile(const std::string& filename, std::vector& _verts, std::vector& _normals) + { + // Open the input file + std::ifstream fs(filename, std::ifstream::in); + if (!fs.is_open()) + { + std::cout << "Error: Failed to open file " << filename << " for reading!" << std::endl; + return false; + } + + // Read file - first pass count the vertices + std::string line; + unsigned int vertCount = 0; + unsigned int triCount = 0; + while (std::getline(fs, line)) + { + if (line[0] == 'v' && line[1] == ' ') ++vertCount; + else if (line[0] == 'f' && line[1] == ' ') ++triCount; + } + + _verts.resize(triCount * 9); + _normals.resize(triCount * 9); + + std::vector v, vn; + + // Read file - first pass count the vertices + int vertIndex = 0; + int normalIndex = 0; + fs.clear(); + fs.seekg(std::ios::beg); + while (std::getline(fs, line)) + { + if (line[0] == 'v' && line[1] == ' ') + { + // Vertex! Add it to the list. + float x, y, z; + std::stringstream ss(line.substr(2)); + ss >> x >> y >> z; + v.push_back(Vector3f(x, y, z)); + } + else if (line[0] == 'v' && line[1] == 'n') + { + // Normal! Add it to the list. + float x, y, z; + std::stringstream ss(line.substr(3)); + ss >> x >> y >> z; + vn.push_back(Vector3f(x, y, z)); + } + else if (line[0] == 'f' && line[1] == ' ') + { + std::stringstream ss(line.substr(2)); + std::string tok; + + // First tuple + for (int k = 0; k < 3; ++k) + { + if (std::getline(ss, tok, '/')) + { + const int i = std::stoi(tok); + memcpy(&_verts[3 * vertIndex++], v[i - 1].v, sizeof(Vector3f::v)); + } + std::getline(ss, tok, '/'); + if (std::getline(ss, tok, ' ')) + { + const int i = std::stoi(tok); + memcpy(&_normals[3 * normalIndex++], vn[i - 1].v, sizeof(Vector3f::v)); + } + } + } + } + + fs.close(); + return vertIndex; + } + + static inline Matrix3f computeNormalMatrix(const Matrix4f& m) + { + Matrix3f n; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + n.m[j][i] = m.m[j][i]; + } + } + return n; + } + + static inline Vector3f transformPoint(const Matrix4f& A, const Vector3f& p) + { + Vector3f p2(0, 0, 0); + for (int j = 0; j < 3; ++j) + { + for (int i = 0; i < 3; ++i) + { + p2.v[j] += A.m[j][i] * p.v[i]; + } + } + + p2.v[0] += A.m[3][0]; + p2.v[1] += A.m[3][1]; + p2.v[2] += A.m[3][2]; + return p2; + } + + static inline void computeVectorRotation(const Vector3f& a, const Vector3f& b, Vector3f& axis, float& theta) + { + const Vector3f v1 = (nanogui::squared_norm(a) > 1e-4f) ? nanogui::normalize(a) : Vector3f(0.0f, 0.0f, 1.0f); + const Vector3f v2 = (nanogui::squared_norm(b) > 1e-4f) ? nanogui::normalize(b) : Vector3f(0.0f, 0.0f, 1.0f); + const float dp = std::min(1.0f, std::max(-1.0f, nanogui::dot(v1, v2))); + theta = std::acos(dp); + if (theta < 1e-4f) + { + axis.v[0] = 1.0f; axis.v[1] = 0.0f; axis.v[2] = 0.0f; + } + else + { + axis = nanogui::normalize(nanogui::cross(v1, v2)); + } + } +} + +IKGLCanvas::IKGLCanvas(IKApplication* _app) : Canvas(_app->getWindow()), m_app(_app) +{ + resetCamera(); + + // A simple shader to draw triangle meshes with normals. + m_shader = new Shader(render_pass(), + // Shader name + "draw_link", + // Vertex shader + R"(#version 410 + uniform mat4 mvMatrix; + uniform mat4 projMatrix; + uniform mat3 normalMatrix; + in vec3 position; + in vec3 normal; + out vec3 fPosition; + out vec3 fNormal; + void main() { + vec4 vEyeCoord = mvMatrix * vec4(position, 1.0); + gl_Position = projMatrix * vEyeCoord; + fPosition = vEyeCoord.xyz; + fNormal = normalMatrix * normal; + })", + + // Fragment shader + R"(#version 410 + uniform vec4 Kd; + in vec3 fPosition; + in vec3 fNormal; + out vec4 fColor; + void + main() + { + vec3 normal = normalize(fNormal); + vec3 LightDirection = normalize(-fPosition); + vec3 viewDirection = normalize(-fPosition); + float diffuse = max(0.0, dot(normal, LightDirection)); + fColor = Kd * (diffuse + 0.1); + })", Shader::BlendMode::AlphaBlend + ); + + + // A simple shader to draw triangle meshes with normals. + m_lineShader = new Shader(render_pass(), + // Shader name + "draw_lines", + // Vertex shader + R"(#version 410 + uniform mat4 mvMatrix; + uniform mat4 projMatrix; + in vec3 position; + in vec3 color; + out vec3 fColor; + void main() { + gl_Position = projMatrix * mvMatrix * vec4(position, 1.0); + fColor = color; + })", + + // Fragment shader + R"(#version 410 + in vec3 fColor; + out vec4 outColor; + void + main() + { + outColor = vec4(fColor, 1.0); + })" + ); + + // Load cube from OBJ file. + // + numCubeVerts = loadFile("cube.obj", cubeVerts, cubeNormals); + numSphereVerts = loadFile("sphere.obj", sphereVerts, sphereNormals); + + m_shader->set_buffer("position", VariableType::Float32, { (unsigned int)numCubeVerts, 3 }, cubeVerts.data()); + m_shader->set_buffer("normal", VariableType::Float32, { (unsigned int)numCubeVerts, 3 }, cubeNormals.data()); + + m_lineShader->set_buffer("position", VariableType::Float32, { 6, 3 }, axesVerts); + m_lineShader->set_buffer("color", VariableType::Float32, { 6, 3 }, axesColors); +} + +void IKGLCanvas::draw_contents() +{ + static const Vector3f zplus(0.0f, 0.0f, 1.0f); + Vector3f axis; + float theta; + float length; + gti320::Armature* armature = m_app->getArmature(); + + { + const float fov = 1.57f; + const float n = 0.2f; + const float f = 20.0f; + const float aspect = (float)width() / (float)height(); + const Matrix4f projMat = Matrix4f::perspective(fov / 2.0f, n, f, aspect); + + const Vector3f p = transformPoint(Matrix4f::rotate(Vector3f(1.0f, 0.0f, 0.0f), phi[1]) * Matrix4f::rotate(Vector3f(0, 1, 0), phi[0]), Vector3f(0, 0, dist)); + const Matrix4f viewMat = Matrix4f::look_at(p, Vector3f(0, 1.0f, 0), Vector3f(0, 1, 0)); + + // Draw the joint axes. + // + m_lineShader->set_uniform("projMatrix", projMat); + m_lineShader->set_buffer("position", VariableType::Float32, { 6, 3 }, axesVerts); + for (gti320::Link* l : armature->links) + { + if (l->isEndEffector()) + continue; + + Matrix4f linkM; + memcpy(linkM.m, l->M.data(), sizeof(Matrix4f::m)); + + Matrix4f modelMat = linkM; + const Matrix4f mvMat = viewMat * modelMat; + m_lineShader->set_uniform("mvMatrix", mvMat); + + m_lineShader->begin(); + m_lineShader->draw_array(Shader::PrimitiveType::Line, 0, 6, false); + m_lineShader->end(); + } + + m_shader->set_uniform("projMatrix", projMat); + + // Draw the armature. + // + m_shader->set_uniform("Kd", Vector4f(0.0f, 0.0f, 0.8f, 0.6f)); + m_shader->set_buffer("position", VariableType::Float32, { (unsigned int)numCubeVerts, 3 }, cubeVerts.data()); + m_shader->set_buffer("normal", VariableType::Float32, { (unsigned int)numCubeVerts, 3 }, cubeNormals.data()); + + // Draw the armature links. + // + for (gti320::Link* l : armature->links) + { + Matrix4f linkM, parentM; + if (l->parent) + { + memcpy(parentM.m, l->parent->M.data(), sizeof(parentM.m)); + + // Compute orientation of the link + // in parent reference frame + Vector3f trans; + memcpy(trans.v, l->trans.data(), sizeof(trans.v)); + computeVectorRotation(zplus, trans, axis, theta); + + // Compute length of the link + length = nanogui::norm(trans); + + Matrix4f modelMat = parentM * Matrix4f::rotate(axis, theta) * Matrix4f::scale(Vector3f(0.16f, 0.16f, length)) * Matrix4f::translate(0.5f * zplus); + const Matrix4f mvMat = viewMat * modelMat; + const Matrix3f normalMat = computeNormalMatrix(mvMat); + m_shader->set_uniform("mvMatrix", mvMat); + m_shader->set_uniform("normalMatrix", normalMat); + + m_shader->begin(); + m_shader->draw_array(Shader::PrimitiveType::Triangle, 0, 3 * (unsigned int)numCubeVerts, false); + m_shader->end(); + } + } + + m_shader->set_uniform("Kd", Vector4f(0.8f, 0.1f, 0.1f, 0.8f)); + m_shader->set_buffer("position", VariableType::Float32, { (unsigned int)numSphereVerts, 3 }, sphereVerts.data()); + m_shader->set_buffer("normal", VariableType::Float32, { (unsigned int)numSphereVerts, 3 }, sphereNormals.data()); + + // Draw the armature joints. + for (gti320::Link* l : armature->links) + { + if (l->isEndEffector()) + continue; + + Matrix4f linkM; + memcpy(linkM.m, l->M.data(), sizeof(Matrix4f::m)); + + Matrix4f modelMat = linkM; + const Matrix4f mvMat = viewMat * modelMat; + const Matrix3f normalMat = computeNormalMatrix(mvMat); + m_shader->set_uniform("mvMatrix", mvMat); + m_shader->set_uniform("normalMatrix", normalMat); + + m_shader->begin(); + m_shader->draw_array(Shader::PrimitiveType::Triangle, 0, 3 * (unsigned int)numSphereVerts, false); + m_shader->end(); + } + + m_shader->set_uniform("Kd", Vector4f(0.1f, 0.8f, 0.1f, 1.0f)); + + // Draw the target. + { + const gti320::Vector3f& t = m_app->getTargetPos(); + Matrix4f modelMat = Matrix4f::translate(nanogui::Vector3f(t(0), t(1), t(2))); + const Matrix4f mvMat = viewMat * modelMat; + const Matrix3f normalMat = computeNormalMatrix(mvMat); + m_shader->set_uniform("mvMatrix", mvMat); + m_shader->set_uniform("normalMatrix", normalMat); + + m_shader->begin(); + m_shader->draw_array(Shader::PrimitiveType::Triangle, 0, 3 * (unsigned int)numSphereVerts, false); + m_shader->end(); + } + + } + +} + +bool IKGLCanvas::mouse_drag_event(const Vector2i& p, const Vector2i& rel, int button, int modifiers) +{ + phi[0] = std::max(-1.57f, std::min(1.57f, phi[0] + 0.01f * (float)rel.x())); + phi[1] = std::max(-1.57f, std::min(1.57f, phi[1] - 0.01f * (float)rel.y())); + + return true; +} + +bool IKGLCanvas::scroll_event(const Vector2i& p, const Vector2f& rel) +{ + dist = std::max(2.0f, std::min(8.0f, dist - 0.1f * (float)rel.y())); + return false; +} + +void IKGLCanvas::resetCamera() +{ + phi[0] = phi[1] = 0.0f; + dist = 4.0f; +} diff --git a/labo_ik/IKGLCanvas.h b/labo_ik/IKGLCanvas.h new file mode 100644 index 0000000..a93d786 --- /dev/null +++ b/labo_ik/IKGLCanvas.h @@ -0,0 +1,45 @@ +#pragma once + +/** + * @file IKGLCanvas.h + * + * @brief Canvas class for drawing OpenGL scenes. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include +#include +#include + +class IKApplication; + +// An OpenGL canvas class to draw point clouds +// +class IKGLCanvas : public nanogui::Canvas +{ +public: + IKGLCanvas(IKApplication* _app); + + virtual void draw_contents() override; + + virtual bool mouse_drag_event(const nanogui::Vector2i& p, const nanogui::Vector2i& rel, int button, int modifiers) override; + + virtual bool scroll_event(const nanogui::Vector2i& p, const nanogui::Vector2f& rel) override; + + void resetCamera(); + +private: + + nanogui::ref m_shader; + nanogui::ref m_lineShader; + IKApplication* m_app; + + // Camera parameters + float phi[2]; + float dist; + +}; diff --git a/labo_ik/IKSolver.cpp b/labo_ik/IKSolver.cpp new file mode 100644 index 0000000..045faca --- /dev/null +++ b/labo_ik/IKSolver.cpp @@ -0,0 +1,59 @@ +#pragma once + +#include "IKSolver.h" +#include "Armature.h" +#include "SVD.h" + +using namespace gti320; + +namespace +{ +} + +IKSolver::IKSolver(Armature* _armature, Vector3f& _targetPos) : m_armature(_armature), m_targetPos(_targetPos), m_J() +{ +} + + +float IKSolver::getError(Vector3f& dx) const +{ + // TODO Compute the error between the current end effector + // position and the target position + dx.setZero(); + return FLT_MAX; +} + +void IKSolver::solve() +{ + const int numLinks = m_armature->links.size(); + const int dim = 3 * (numLinks); + m_J.resize(3, dim); + + // We assume that the last link is the "end effector" + // + Link* endEffector = m_armature->links[numLinks - 1]; + + // TODO Juild the Jacobian matrix m_J. + // Each column corresponds to a separate + + // TODO Compute the error between the current end effector + // position and the target position by calling getError() + // + + // TODO Compute the change in the joint angles by solving: + // df/dtheta * delta_theta = delta_x + // where df/dtheta is the Jacobian matrix. + // + // + + // TODO Perform gradient descent method with line search + // to move the end effector toward the target position. + // + // Hint: use the Armature::unpack() and Armature::pack() functions + // to set and get the joint angles of the armature. + // + // Hint: whenever you change the joint angles, you must also call + // armature->updateKinematics() to compute the global position. + // + +} diff --git a/labo_ik/IKSolver.h b/labo_ik/IKSolver.h new file mode 100644 index 0000000..713c8ac --- /dev/null +++ b/labo_ik/IKSolver.h @@ -0,0 +1,42 @@ + #pragma once + +#include "Math3D.h" + +namespace gti320 +{ + class Armature; + + typedef Matrix Jacobianf; + + + // An inverse kinematics solver for a simple armature. + // + class IKSolver + { + public: + // Constructor. + // @a _armature = The armature (see class Armature). + // @a _targetPos = A reference to the target position of the end effector. + // + IKSolver(Armature* _armature, Vector3f& _targetPos); + + // Execute one solver step. + // A gradient descent method with line search is used. + // Euler angles of the armature links are automatically computed and updated. + // + void solve(); + + // Return the error as the distance between the end effector and the target position. + // The displacement vector @a _dx is updated with the value: + // _dx = m_targetPos - f(theta) + // + float getError(Vector3f& _dx) const; + + private: + Armature* m_armature; // The armature. + Vector3f& m_targetPos; // The target position of the end effector. + Jacobianf m_J; // The end effector Jacobian. + }; + +} + diff --git a/labo_ik/LinkUI.cpp b/labo_ik/LinkUI.cpp new file mode 100644 index 0000000..691ff94 --- /dev/null +++ b/labo_ik/LinkUI.cpp @@ -0,0 +1,77 @@ +#include "LinkUI.h" + +LinkUI::LinkUI(gti320::Link* _link, int _id, nanogui::Widget* _parent) : link(_link), id(_id) +{ + panel = new nanogui::Widget(_parent); + panel->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5)); + + init(); +} + +void LinkUI::init() +{ + static char buf[64]; + static const auto rotateMinMax = std::make_pair(-1.57f, 1.57f); + static const std::string baseName = "link "; + + // Rotate X + panelRotateX = new nanogui::Widget(panel); + panelRotateX->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelRotateX = new nanogui::Label(panelRotateX, baseName + itoa(id, buf, 10) + " (X): "); + sliderRotateX = new nanogui::Slider(panelRotateX); + sliderRotateX->set_range(rotateMinMax); + textboxRotateX = new nanogui::TextBox(panelRotateX); + sliderRotateX->set_callback([this](float value) + { + link->eulerAng(0) = value; + onSlidersChanged(); + }); + + // Rotate Y + panelRotateY = new nanogui::Widget(panel); + panelRotateY->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelRotateY = new nanogui::Label(panelRotateY, baseName + itoa(id, buf, 10) + " (Y): "); + sliderRotateY = new nanogui::Slider(panelRotateY); + sliderRotateY->set_range(rotateMinMax); + textboxRotateY = new nanogui::TextBox(panelRotateY); + sliderRotateY->set_callback([this](float value) + { + link->eulerAng(1) = value; + onSlidersChanged(); + }); + + // Rotate Z + panelRotateZ = new nanogui::Widget(panel); + panelRotateZ->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelRotateZ = new nanogui::Label(panelRotateZ, baseName + itoa(id, buf, 10) + " (Z): "); + sliderRotateZ = new nanogui::Slider(panelRotateZ); + sliderRotateZ->set_range(rotateMinMax); + textboxRotateZ = new nanogui::TextBox(panelRotateZ); + sliderRotateZ->set_callback([this](float value) + { + link->eulerAng(2) = value; + onSlidersChanged(); + }); + + onSlidersChanged(); +} + +void LinkUI::onSlidersChanged() +{ + static char buf[64]; + snprintf(buf, sizeof(buf), "%3.3f", link->eulerAng(0)); + textboxRotateX->set_value(buf); + snprintf(buf, sizeof(buf), "%3.3f", link->eulerAng(1)); + textboxRotateY->set_value(buf); + snprintf(buf, sizeof(buf), "%3.3f", link->eulerAng(2)); + textboxRotateZ->set_value(buf); +} + +void LinkUI::onArmatureChanged() +{ + sliderRotateX->set_value(link->eulerAng(0)); + sliderRotateY->set_value(link->eulerAng(1)); + sliderRotateZ->set_value(link->eulerAng(2)); + + onSlidersChanged(); +} diff --git a/labo_ik/LinkUI.h b/labo_ik/LinkUI.h new file mode 100644 index 0000000..c199ecf --- /dev/null +++ b/labo_ik/LinkUI.h @@ -0,0 +1,43 @@ +#pragma once + +/** + * @file LinkUI.h + * + * @brief User interface for armature links. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Armature.h" +#include "Math3D.h" + + // Link UI + // +class LinkUI +{ +public: + + LinkUI(gti320::Link* _link, int _id, nanogui::Widget* _parent); + + void onArmatureChanged(); + +private: + + void init(); + + void onSlidersChanged(); + + gti320::Link* link; + int id; + nanogui::ref panel, panelRotateX, panelRotateY, panelRotateZ; + nanogui::ref textboxRotateX, textboxRotateY, textboxRotateZ; + nanogui::ref labelRotateX, labelRotateY, labelRotateZ; + nanogui::ref sliderRotateX, sliderRotateY, sliderRotateZ; +}; diff --git a/labo_ik/SVD.h b/labo_ik/SVD.h new file mode 100644 index 0000000..9597bab --- /dev/null +++ b/labo_ik/SVD.h @@ -0,0 +1,372 @@ +#pragma once + +/** + * @file SVD.hpp + * + * @brief Singular value decomposition. + * + */ + +#include "Matrix.h" +#include "Math3D.h" +#include "Operators.h" + +#include +#include +#include +#include + +namespace gti320 +{ + // + // An implementation of SVD from "Numerical Recipes in C". + // http://numerical.recipes/webnotes/nr3web2.pdf + // + template + static inline _Scalar sign(const _Scalar a, const _Scalar b) + { + return (b > 0.0) ? std::abs(a) : -std::abs(a); + } + + template + static inline _Scalar sq(const _Scalar a) + { + return (a * a); + } + + // calculates sqrt( a^2 + b^2 ) + template + static inline _Scalar pythag(_Scalar a, _Scalar b) + { + return std::sqrt(a * a + b * b); + } + + template + class SVD + { + public: + + explicit SVD(const Matrix<_Scalar, _Rows, _Cols, _Storage>& _A) : + m_U(_A), m_V(_A.cols(), _A.cols()), m_S(_A.cols()) + { + } + + const Matrix<_Scalar, _Rows, _Cols>& getU() const { return m_U; } + + const Matrix<_Scalar, _Cols, _Cols>& getV() const { return m_V; } + + const Vector<_Scalar, _Cols>& getSigma() const { return m_S; } + + void decompose() + { + bool flag; + int i, its, j, jj, k, l, nm; + _Scalar anorm, c, f, g, h, s, scale, x, y, z; + + const int ncols = m_U.cols(); + const int nrows = m_U.rows(); + Vector<_Scalar> rv1(ncols); + + // Householder reduction to bidiagonal form + // + g = scale = anorm = 0.0; + for (i = 0; i < ncols; ++i) + { + l = i + 1; + rv1(i) = scale * g; + g = s = scale = 0.0; + if (i < nrows) + { + for (k = i; k < nrows; ++k) + { + scale += std::abs(m_U(k, i)); + } + + if (scale != 0.0) + { + for (k = i; k < nrows; ++k) + { + m_U(k, i) /= scale; + s += m_U(k, i) * m_U(k, i); + } + f = m_U(i, i); + g = -sign(std::sqrt(s), f); + h = f * g - s; + m_U(i, i) = f - g; + for (j = l; j < ncols; ++j) + { + for (s = 0.0, k = i; k < nrows; ++k) + s += m_U(k, i) * m_U(k, j); + f = s / h; + for (k = i; k < nrows; ++k) + m_U(k, j) += f * m_U(k, i); + } + for (k = i; k < nrows; ++k) + m_U(k, i) *= scale; + } + } + m_S(i) = scale * g; + g = s = scale = 0.0; + if (i < nrows && i != ncols - 1) + { + for (k = l; k < ncols; ++k) + scale += std::abs(m_U(i, k)); + + if (scale) + { + for (k = l; k < ncols; ++k) + { + m_U(i, k) /= scale; + s += m_U(i, k) * m_U(i, k); + } + f = m_U(i, l); + g = -sign(std::sqrt(s), f); + h = f * g - s; + m_U(i, l) = f - g; + for (k = l; k < ncols; ++k) + { + rv1(k) = m_U(i, k) / h; + } + for (j = l; j < nrows; ++j) + { + for (s = 0.0, k = l; k < ncols; ++k) + s += m_U(j, k) * m_U(i, k); + for (k = l; k < ncols; ++k) + m_U(j, k) += s * rv1(k); + } + for (k = l; k < ncols; ++k) + m_U(i, k) *= scale; + } + } + const _Scalar tmp = (std::abs(m_S(i)) + std::abs(rv1(i))); + anorm = std::max(anorm, tmp); + } + + // Accumulation of right-hand transformations + // + for (i = ncols - 1; i >= 0; --i) + { + if (i < ncols - 1) + { + if (g) { + for (j = l; j < ncols; ++j) + m_V(j, i) = (m_U(i, j) / m_U(i, l)) / g; // double division to avoid possible underflow + + for (j = l; j < ncols; ++j) + { + for (s = 0.0, k = l; k < ncols; ++k) + s += m_U(i, k) * m_V(k, j); + for (k = l; k < ncols; ++k) + m_V(k, j) += s * m_V(k, i); + } + } + for (j = l; j < ncols; ++j) + m_V(i, j) = m_V(j, i) = 0.0; + } + m_V(i, i) = 1.0; + g = rv1(i); + l = i; + } + + // Accumulation of left-hand transformations + // + for (i = std::min(nrows, ncols) - 1; i >= 0; --i) + { + l = i + 1; + g = m_S(i); + for (j = l; j < ncols; ++j) + m_U(i, j) = 0.0; + if (g) + { + g = 1.0 / g; + for (j = l; j < ncols; ++j) + { + for (s = 0.0, k = l; k < nrows; ++k) + s += m_U(k, i) * m_U(k, j); + f = (s / m_U(i, i)) * g; + for (k = i; k < nrows; ++k) + m_U(k, j) += f * m_U(k, i); + } + for (j = i; j < nrows; ++j) + m_U(j, i) *= g; + } + else + for (j = i; j < nrows; ++j) + m_U(j, i) = 0.0; + m_U(i, i) = m_U(i, i) + 1.0; + } + + // Diagonalization of the bidiagonal form. + // Loops over singular values using iterations. + // + for (k = ncols - 1; k >= 0; --k) + { + // Max iterations: 30 + for (its = 0; its < 30; ++its) + { + flag = true; + for (l = k; l >= 0; --l) // Test for splitting + { + nm = l - 1; + if ((std::abs(rv1(l)) + anorm) == anorm) + { + flag = false; + break; + } + if (std::abs(m_S(nm) + anorm) == anorm) + break; + } + + if (flag) + { // Cancellation of rv1(l) if l > 0 + c = 0.0; + s = 1.0; + for (i = l; i <= k; ++i) + { + f = s * rv1(i); + rv1(i) = c * rv1(i); + if ((std::abs(f) + anorm) == anorm) + break; + + g = m_S(i); + h = pythag(f, g); + m_S(i) = h; + h = 1.0 / h; + c = g * h; + s = -f * h; + for (j = 0; j < nrows; ++j) + { + y = m_U(j, nm); + z = m_U(j, i); + m_U(j, nm) = y * c + z * s; + m_U(j, i) = z * c - y * s; + } + } + } + z = m_S(k); + if (l == k) // Convergence. + { + if (z < 0.0) // Compute non-negative singular values + { + m_S(k) = -z; + for (j = 0; j < ncols; ++j) + { + m_V(j, k) = -m_V(j, k); // Reverse bases direction + } + } + break; + } + + // Assertion when max iterations reached without convergence + assert(its < 29); + + x = m_S(l); // Shift from bottom 2-by-2 minor + nm = k - 1; + y = m_S(nm); + g = rv1(nm); + h = rv1(k); + f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y); + g = pythag(f, (_Scalar)1.0); + f = ((x - z) * (x + z) + h * ((y / (f + sign(g, f))) - h)) / x; + c = s = 1.0; // Next QR transformation + for (j = l; j <= nm; ++j) + { + i = j + 1; + g = rv1(i); + y = m_S(i); + h = s * g; + g = c * g; + z = pythag(f, h); + rv1(j) = z; + c = f / z; + s = h / z; + f = x * c + g * s; + g = g * c - x * s; + h = y * s; + y *= c; + for (jj = 0; jj < ncols; ++jj) + { + x = m_V(jj, j); + z = m_V(jj, i); + m_V(jj, j) = x * c + z * s; + m_V(jj, i) = z * c - x * s; + } + z = pythag(f, h); + m_S(j) = z; // Rotation can be arbitrary if z == 0 + if (z != 0.0) + { + z = 1.0 / z; + c = f * z; + s = h * z; + } + f = c * g + s * y; + x = c * y - s * g; + for (jj = 0; jj < nrows; ++jj) + { + y = m_U(jj, j); + z = m_U(jj, i); + m_U(jj, j) = y * c + z * s; + m_U(jj, i) = z * c - y * s; + } + } + rv1(l) = 0.0; + rv1(k) = f; + m_S(k) = x; + } + } + + reorder(); + } + + private: + + void reorder() { + int s, inc = 1; + _Scalar sw; + + const int ncols = m_U.cols(); + const int nrows = m_U.rows(); + Vector<_Scalar> su(nrows), sv(ncols); + do { inc *= 3; inc++; } while (inc <= ncols); // Sort using Shell’s sort. + + do { + inc /= 3; + for (int i = inc; i < ncols; ++i) { + sw = m_S(i); + for (int k = 0; k < nrows; ++k) su(k) = m_U(k, i); + for (int k = 0; k < ncols; ++k) sv(k) = m_V(k, i); + int j = i; + while (m_S(j - inc) < sw) { + m_S(j) = m_S(j - inc); + for (int k = 0; k < nrows; ++k) m_U(k, j) = m_U(k, j - inc); + for (int k = 0; k < ncols; ++k) m_V(k, j) = m_V(k, j - inc); + j -= inc; + if (j < inc) break; + } + m_S(j) = sw; + for (int k = 0; k < nrows; ++k) m_U(k, j) = su(k); + for (int k = 0; k < ncols; ++k) m_V(k, j) = sv(k); + } + } while (inc > 1); + + for (int k = 0; k < ncols; ++k) + { + // Flip signs. + s = 0; + for (int i = 0; i < nrows; ++i) if (m_U(i, k) < 0.0) ++s; + for (int j = 0; j < ncols; ++j) if (m_V(j, k) < 0.0) ++s; + if (s > (nrows + ncols) / 2) + { + for (int i = 0; i < nrows; ++i) m_U(i, k) = -m_U(i, k); + for (int j = 0; j < ncols; ++j) m_V(j, k) = -m_V(j, k); + } + } + } + + + Matrix<_Scalar, _Rows, _Cols, _Storage> m_U; + Matrix<_Scalar, _Cols, _Cols> m_V; + Vector<_Scalar, _Cols> m_S; + }; + +} \ No newline at end of file diff --git a/labo_ik/TargetUI.cpp b/labo_ik/TargetUI.cpp new file mode 100644 index 0000000..102618d --- /dev/null +++ b/labo_ik/TargetUI.cpp @@ -0,0 +1,66 @@ +#include "TargetUI.h" + +TargetUI::TargetUI(nanogui::Widget* _parent, gti320::Vector3f& _target) : target(_target) +{ + panel = new nanogui::Widget(_parent); + panel->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Middle, 0, 5)); + + init(); +} + +void TargetUI::init() +{ + static const auto translateMinMax = std::make_pair(-4.0f, 4.0f); + + // Translate X + panelTranslateX = new nanogui::Widget(panel); + panelTranslateX->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelTranslateX = new nanogui::Label(panelTranslateX, "Target X : "); + sliderTranslateX = new nanogui::Slider(panelTranslateX); + sliderTranslateX->set_range(translateMinMax); + textboxTranslateX = new nanogui::TextBox(panelTranslateX); + sliderTranslateX->set_callback([this](float value) + { + target(0) = value; + onSlidersChanged(); + }); + + // Rotate Y + panelTranslateY = new nanogui::Widget(panel); + panelTranslateY->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelTranslateY = new nanogui::Label(panelTranslateY, "Target Y : "); + sliderTranslateY = new nanogui::Slider(panelTranslateY); + sliderTranslateY->set_range(translateMinMax); + textboxTranslateY = new nanogui::TextBox(panelTranslateY); + sliderTranslateY->set_callback([this](float value) + { + target(1) = value; + onSlidersChanged(); + }); + + // Rotate Z + panelTranslateZ = new nanogui::Widget(panel); + panelTranslateZ->set_layout(new nanogui::BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0, 20)); + labelTranslateZ = new nanogui::Label(panelTranslateZ, "Target Z : "); + sliderTranslateZ = new nanogui::Slider(panelTranslateZ); + sliderTranslateZ->set_range(translateMinMax); + textboxTranslateZ = new nanogui::TextBox(panelTranslateZ); + sliderTranslateZ->set_callback([this](float value) + { + target(2) = value; + onSlidersChanged(); + }); + + onSlidersChanged(); +} + +void TargetUI::onSlidersChanged() +{ + static char buf[64]; + snprintf(buf, sizeof(buf), "%3.3f", target(0)); + textboxTranslateX->set_value(buf); + snprintf(buf, sizeof(buf), "%3.3f", target(1)); + textboxTranslateY->set_value(buf); + snprintf(buf, sizeof(buf), "%3.3f", target(2)); + textboxTranslateZ->set_value(buf); +} diff --git a/labo_ik/TargetUI.h b/labo_ik/TargetUI.h new file mode 100644 index 0000000..6181122 --- /dev/null +++ b/labo_ik/TargetUI.h @@ -0,0 +1,41 @@ +#pragma once + +/** + * @file TargetUI.h + * + * @brief User interface for end-effector target. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Armature.h" +#include "Math3D.h" + + + // Target UI + // +class TargetUI +{ +public: + + TargetUI(nanogui::Widget* _parent, gti320::Vector3f& _target); + +private: + + void init(); + + void onSlidersChanged(); + + nanogui::ref panel, panelTranslateX, panelTranslateY, panelTranslateZ; + nanogui::ref textboxTranslateX, textboxTranslateY, textboxTranslateZ; + nanogui::ref labelTranslateX, labelTranslateY, labelTranslateZ; + nanogui::ref sliderTranslateX, sliderTranslateY, sliderTranslateZ; + gti320::Vector3f& target; +}; diff --git a/labo_ik/cube.obj b/labo_ik/cube.obj new file mode 100644 index 0000000..1037783 --- /dev/null +++ b/labo_ik/cube.obj @@ -0,0 +1,58 @@ +# Blender v3.0.1 OBJ File: '' +# www.blender.org +o Cube +v 0.500000 0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 0.500000 -0.500000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +s off +f 35//1 28//1 21//1 +f 26//2 13//2 30//2 +f 23//3 9//3 12//3 +f 16//4 14//4 10//4 +f 20//5 31//5 17//5 +f 33//6 18//6 11//6 +f 34//1 24//1 27//1 +f 29//2 7//2 15//2 +f 25//3 36//3 6//3 +f 19//4 32//4 8//4 +f 1//5 3//5 4//5 +f 5//6 22//6 2//6 diff --git a/labo_ik/main.cpp b/labo_ik/main.cpp new file mode 100644 index 0000000..e7ee20f --- /dev/null +++ b/labo_ik/main.cpp @@ -0,0 +1,42 @@ +/** + * @file main.cpp + * + * @brief GTI320 Labo 2 - creates a NanoGUI application. + * + * Nom: + * Code permanent : + * Email : + * + */ + +#include "IKApplication.h" + +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif +#if defined(_WIN32) +# pragma warning(push) +# pragma warning(disable: 4457 4456 4005 4312) +#endif + +#if defined(_WIN32) +# pragma warning(pop) +#endif +#if defined(_WIN32) +# if defined(APIENTRY) +# undef APIENTRY +# endif +# include +#endif + +int main(int argc, char** argv) +{ + nanogui::init(); + nanogui::ref app = new IKApplication(); + app->draw_all(); + app->set_visible(true); + nanogui::mainloop(); + nanogui::shutdown(); + + return 0; +} \ No newline at end of file diff --git a/labo_ik/sphere.obj b/labo_ik/sphere.obj new file mode 100644 index 0000000..bfab8b1 --- /dev/null +++ b/labo_ik/sphere.obj @@ -0,0 +1,1928 @@ +# Blender v3.0.1 OBJ File: '' +# www.blender.org +o Sphere +v 0.000000 0.122598 -0.024386 +v 0.000000 0.115485 -0.047835 +v 0.000000 0.103934 -0.069446 +v 0.000000 0.088388 -0.088388 +v 0.000000 0.069446 -0.103934 +v 0.000000 0.047835 -0.115485 +v 0.000000 0.024386 -0.122598 +v 0.000000 -0.069446 -0.103934 +v 0.000000 -0.088388 -0.088388 +v 0.000000 -0.103934 -0.069446 +v 0.004758 0.122598 -0.023918 +v 0.009332 0.115485 -0.046916 +v 0.013548 0.103934 -0.068112 +v 0.017244 0.088388 -0.086690 +v 0.020276 0.069446 -0.101937 +v 0.022530 0.047835 -0.113266 +v 0.023918 0.024386 -0.120243 +v 0.024386 -0.000000 -0.122598 +v 0.023918 -0.024386 -0.120243 +v 0.022530 -0.047835 -0.113266 +v 0.020276 -0.069446 -0.101937 +v 0.017244 -0.088388 -0.086690 +v 0.013548 -0.103934 -0.068112 +v 0.009332 -0.115485 -0.046916 +v 0.004758 -0.122598 -0.023918 +v 0.009332 0.122598 -0.022530 +v 0.018306 0.115485 -0.044194 +v 0.026576 0.103934 -0.064160 +v 0.033825 0.088388 -0.081660 +v 0.039774 0.069446 -0.096022 +v 0.044194 0.047835 -0.106694 +v 0.046916 0.024386 -0.113266 +v 0.047835 -0.000000 -0.115485 +v 0.046916 -0.024386 -0.113266 +v 0.044194 -0.047835 -0.106694 +v 0.039774 -0.069446 -0.096022 +v 0.033825 -0.088388 -0.081660 +v 0.026576 -0.103934 -0.064160 +v 0.018306 -0.115485 -0.044194 +v 0.009332 -0.122598 -0.022530 +v 0.013548 0.122598 -0.020276 +v 0.026576 0.115485 -0.039774 +v 0.038582 0.103934 -0.057743 +v 0.049106 0.088388 -0.073492 +v 0.057743 0.069446 -0.086418 +v 0.064160 0.047835 -0.096022 +v 0.068112 0.024386 -0.101937 +v 0.069446 -0.000000 -0.103934 +v 0.068112 -0.024386 -0.101937 +v 0.064160 -0.047835 -0.096022 +v 0.057743 -0.069446 -0.086418 +v 0.049106 -0.088388 -0.073492 +v 0.038582 -0.103934 -0.057743 +v 0.026576 -0.115485 -0.039774 +v 0.013548 -0.122598 -0.020276 +v 0.017244 0.122598 -0.017244 +v 0.033825 0.115485 -0.033825 +v 0.049106 0.103934 -0.049106 +v 0.062500 0.088388 -0.062500 +v 0.073492 0.069446 -0.073492 +v 0.081660 0.047835 -0.081660 +v 0.086690 0.024386 -0.086690 +v 0.088388 -0.000000 -0.088388 +v 0.086690 -0.024386 -0.086690 +v 0.081660 -0.047835 -0.081660 +v 0.073492 -0.069446 -0.073492 +v 0.062500 -0.088388 -0.062500 +v 0.049106 -0.103934 -0.049106 +v 0.033825 -0.115485 -0.033825 +v 0.017244 -0.122598 -0.017244 +v 0.020276 0.122598 -0.013548 +v 0.039774 0.115485 -0.026576 +v 0.057743 0.103934 -0.038582 +v 0.073492 0.088388 -0.049106 +v 0.086418 0.069446 -0.057743 +v 0.096022 0.047835 -0.064160 +v 0.101937 0.024386 -0.068112 +v 0.103934 -0.000000 -0.069446 +v 0.101937 -0.024386 -0.068112 +v 0.096022 -0.047835 -0.064160 +v 0.086418 -0.069446 -0.057743 +v 0.073492 -0.088388 -0.049106 +v 0.057743 -0.103934 -0.038582 +v 0.039774 -0.115485 -0.026576 +v 0.020276 -0.122598 -0.013548 +v 0.022530 0.122598 -0.009332 +v 0.044194 0.115485 -0.018306 +v 0.064160 0.103934 -0.026576 +v 0.081660 0.088388 -0.033825 +v 0.096022 0.069446 -0.039774 +v 0.106694 0.047835 -0.044194 +v 0.113266 0.024386 -0.046916 +v 0.115485 -0.000000 -0.047835 +v 0.113266 -0.024386 -0.046916 +v 0.106694 -0.047835 -0.044194 +v 0.096022 -0.069446 -0.039774 +v 0.081660 -0.088388 -0.033825 +v 0.064160 -0.103934 -0.026576 +v 0.044194 -0.115485 -0.018306 +v 0.022530 -0.122598 -0.009332 +v 0.023918 0.122598 -0.004758 +v 0.046916 0.115485 -0.009332 +v 0.068112 0.103934 -0.013548 +v 0.086690 0.088388 -0.017244 +v 0.101937 0.069446 -0.020276 +v 0.113266 0.047835 -0.022530 +v 0.120243 0.024386 -0.023918 +v 0.122598 -0.000000 -0.024386 +v 0.120243 -0.024386 -0.023918 +v 0.113266 -0.047835 -0.022530 +v 0.101937 -0.069446 -0.020276 +v 0.086690 -0.088388 -0.017244 +v 0.068112 -0.103934 -0.013548 +v 0.046916 -0.115485 -0.009332 +v 0.023918 -0.122598 -0.004758 +v 0.024386 0.122598 0.000000 +v 0.047835 0.115485 0.000000 +v 0.069446 0.103934 0.000000 +v 0.088388 0.088388 0.000000 +v 0.103934 0.069446 0.000000 +v 0.115485 0.047835 0.000000 +v 0.122598 0.024386 0.000000 +v 0.125000 -0.000000 0.000000 +v 0.122598 -0.024386 0.000000 +v 0.115485 -0.047835 0.000000 +v 0.103934 -0.069446 0.000000 +v 0.088388 -0.088388 0.000000 +v 0.069446 -0.103934 0.000000 +v 0.047835 -0.115485 0.000000 +v 0.024386 -0.122598 0.000000 +v 0.023918 0.122598 0.004758 +v 0.046916 0.115485 0.009332 +v 0.068112 0.103934 0.013548 +v 0.086690 0.088388 0.017244 +v 0.101937 0.069446 0.020276 +v 0.113266 0.047835 0.022530 +v 0.120243 0.024386 0.023918 +v 0.122598 -0.000000 0.024386 +v 0.120243 -0.024386 0.023918 +v 0.113266 -0.047835 0.022530 +v 0.101937 -0.069446 0.020276 +v 0.086690 -0.088388 0.017244 +v 0.068112 -0.103934 0.013548 +v 0.046916 -0.115485 0.009332 +v 0.023918 -0.122598 0.004758 +v 0.022530 0.122598 0.009332 +v 0.044194 0.115485 0.018306 +v 0.064160 0.103934 0.026576 +v 0.081660 0.088388 0.033825 +v 0.096022 0.069446 0.039774 +v 0.106694 0.047835 0.044194 +v 0.113266 0.024386 0.046916 +v 0.115485 -0.000000 0.047835 +v 0.113266 -0.024386 0.046916 +v 0.106694 -0.047835 0.044194 +v 0.096022 -0.069446 0.039774 +v 0.081660 -0.088388 0.033825 +v 0.064160 -0.103934 0.026576 +v 0.044194 -0.115485 0.018306 +v 0.022530 -0.122598 0.009332 +v 0.020276 0.122598 0.013548 +v 0.039774 0.115485 0.026576 +v 0.057742 0.103934 0.038582 +v 0.073492 0.088388 0.049106 +v 0.086418 0.069446 0.057743 +v 0.096022 0.047835 0.064160 +v 0.101937 0.024386 0.068112 +v 0.103934 -0.000000 0.069446 +v 0.101937 -0.024386 0.068112 +v 0.096022 -0.047835 0.064160 +v 0.086418 -0.069446 0.057743 +v 0.073492 -0.088388 0.049106 +v 0.057742 -0.103934 0.038582 +v 0.039774 -0.115485 0.026576 +v 0.020276 -0.122598 0.013548 +v 0.017244 0.122598 0.017244 +v 0.033825 0.115485 0.033825 +v 0.049106 0.103934 0.049106 +v 0.062500 0.088388 0.062500 +v 0.073492 0.069446 0.073492 +v 0.081660 0.047835 0.081660 +v 0.086690 0.024386 0.086690 +v 0.088388 -0.000000 0.088388 +v 0.086690 -0.024386 0.086690 +v 0.081660 -0.047835 0.081660 +v 0.073492 -0.069446 0.073492 +v 0.062500 -0.088388 0.062500 +v 0.049106 -0.103934 0.049106 +v 0.033825 -0.115485 0.033825 +v 0.017244 -0.122598 0.017244 +v 0.013548 0.122598 0.020276 +v 0.026576 0.115485 0.039774 +v 0.038582 0.103934 0.057743 +v 0.049106 0.088388 0.073492 +v 0.057742 0.069446 0.086418 +v 0.064160 0.047835 0.096022 +v 0.068112 0.024386 0.101937 +v 0.069446 -0.000000 0.103934 +v 0.068112 -0.024386 0.101937 +v 0.064160 -0.047835 0.096022 +v 0.057742 -0.069446 0.086418 +v 0.049106 -0.088388 0.073492 +v 0.038582 -0.103934 0.057743 +v 0.026576 -0.115485 0.039774 +v 0.013548 -0.122598 0.020276 +v 0.009332 0.122598 0.022530 +v 0.018306 0.115485 0.044194 +v 0.026576 0.103934 0.064160 +v 0.033825 0.088388 0.081660 +v 0.039774 0.069446 0.096022 +v 0.044194 0.047835 0.106694 +v 0.046916 0.024386 0.113266 +v 0.047835 -0.000000 0.115485 +v 0.046916 -0.024386 0.113266 +v 0.044194 -0.047835 0.106694 +v 0.039774 -0.069446 0.096022 +v 0.033825 -0.088388 0.081660 +v 0.026576 -0.103934 0.064160 +v 0.018306 -0.115485 0.044194 +v 0.009332 -0.122598 0.022530 +v 0.004758 0.122598 0.023918 +v 0.009332 0.115485 0.046916 +v 0.013548 0.103934 0.068112 +v 0.017244 0.088388 0.086690 +v 0.020276 0.069446 0.101937 +v 0.022530 0.047835 0.113266 +v 0.023918 0.024386 0.120243 +v 0.024386 -0.000000 0.122598 +v 0.023918 -0.024386 0.120243 +v 0.022530 -0.047835 0.113266 +v 0.020276 -0.069446 0.101937 +v 0.017244 -0.088388 0.086690 +v 0.013548 -0.103934 0.068112 +v 0.009332 -0.115485 0.046916 +v 0.004758 -0.122598 0.023918 +v 0.000000 0.122598 0.024386 +v -0.000000 0.115485 0.047835 +v -0.000000 0.103934 0.069446 +v 0.000000 0.088388 0.088388 +v -0.000000 0.069446 0.103934 +v 0.000000 0.047835 0.115485 +v -0.000000 0.024386 0.122598 +v -0.000000 -0.000000 0.125000 +v -0.000000 -0.024386 0.122598 +v -0.000000 -0.047835 0.115485 +v -0.000000 -0.069446 0.103934 +v 0.000000 -0.088388 0.088388 +v -0.000000 -0.103934 0.069446 +v 0.000000 -0.115485 0.047835 +v -0.000000 -0.122598 0.024386 +v -0.004758 0.122598 0.023918 +v -0.009332 0.115485 0.046916 +v -0.013548 0.103934 0.068112 +v -0.017244 0.088388 0.086690 +v -0.020276 0.069446 0.101937 +v -0.022530 0.047835 0.113266 +v -0.023918 0.024386 0.120243 +v -0.024386 -0.000000 0.122598 +v -0.023918 -0.024386 0.120243 +v -0.022530 -0.047835 0.113266 +v -0.020276 -0.069446 0.101937 +v -0.017244 -0.088388 0.086690 +v -0.013548 -0.103934 0.068112 +v -0.009332 -0.115485 0.046916 +v -0.004758 -0.122598 0.023918 +v -0.009332 0.122598 0.022530 +v -0.018306 0.115485 0.044194 +v -0.026576 0.103934 0.064160 +v -0.033825 0.088388 0.081660 +v -0.039774 0.069446 0.096022 +v -0.044194 0.047835 0.106694 +v -0.046916 0.024386 0.113266 +v -0.047835 -0.000000 0.115485 +v -0.046916 -0.024386 0.113266 +v -0.044194 -0.047835 0.106694 +v -0.039774 -0.069446 0.096022 +v -0.033825 -0.088388 0.081660 +v -0.026576 -0.103934 0.064160 +v -0.018306 -0.115485 0.044194 +v -0.009332 -0.122598 0.022530 +v -0.013548 0.122598 0.020276 +v -0.026576 0.115485 0.039774 +v -0.038582 0.103934 0.057743 +v -0.049106 0.088388 0.073492 +v -0.057742 0.069446 0.086418 +v -0.064160 0.047835 0.096022 +v -0.068112 0.024386 0.101937 +v -0.069446 -0.000000 0.103934 +v -0.068112 -0.024386 0.101937 +v -0.064160 -0.047835 0.096022 +v -0.057742 -0.069446 0.086418 +v -0.049106 -0.088388 0.073492 +v -0.038582 -0.103934 0.057743 +v -0.026576 -0.115485 0.039774 +v -0.013548 -0.122598 0.020276 +v -0.017244 0.122598 0.017244 +v -0.033825 0.115485 0.033825 +v -0.049106 0.103934 0.049106 +v -0.062500 0.088388 0.062500 +v -0.073492 0.069446 0.073492 +v -0.081660 0.047835 0.081660 +v -0.086690 0.024386 0.086690 +v -0.088388 -0.000000 0.088388 +v -0.086690 -0.024386 0.086690 +v -0.081660 -0.047835 0.081660 +v -0.073492 -0.069446 0.073492 +v -0.062500 -0.088388 0.062500 +v -0.049106 -0.103934 0.049106 +v -0.033825 -0.115485 0.033825 +v -0.017244 -0.122598 0.017244 +v -0.020276 0.122598 0.013548 +v -0.039774 0.115485 0.026576 +v -0.057742 0.103934 0.038582 +v -0.073492 0.088388 0.049106 +v -0.086418 0.069446 0.057743 +v -0.096022 0.047835 0.064160 +v -0.101937 0.024386 0.068112 +v -0.103934 -0.000000 0.069446 +v -0.101937 -0.024386 0.068112 +v -0.096022 -0.047835 0.064160 +v -0.086418 -0.069446 0.057743 +v -0.073492 -0.088388 0.049106 +v -0.057742 -0.103934 0.038582 +v -0.039774 -0.115485 0.026576 +v -0.020276 -0.122598 0.013548 +v -0.000000 0.125000 0.000000 +v -0.022530 0.122598 0.009332 +v -0.044194 0.115485 0.018306 +v -0.064160 0.103934 0.026576 +v -0.081660 0.088388 0.033825 +v -0.096022 0.069446 0.039774 +v -0.106694 0.047835 0.044194 +v -0.113266 0.024386 0.046916 +v -0.115485 -0.000000 0.047835 +v -0.113266 -0.024386 0.046916 +v -0.106694 -0.047835 0.044194 +v -0.096022 -0.069446 0.039774 +v -0.081660 -0.088388 0.033825 +v -0.064160 -0.103934 0.026576 +v -0.044194 -0.115485 0.018306 +v -0.022530 -0.122598 0.009332 +v -0.023918 0.122598 0.004758 +v -0.046916 0.115485 0.009332 +v -0.068112 0.103934 0.013548 +v -0.086690 0.088388 0.017244 +v -0.101937 0.069446 0.020276 +v -0.113266 0.047835 0.022530 +v -0.120242 0.024386 0.023918 +v -0.122598 -0.000000 0.024386 +v -0.120242 -0.024386 0.023918 +v -0.113266 -0.047835 0.022530 +v -0.101937 -0.069446 0.020276 +v -0.086690 -0.088388 0.017244 +v -0.068112 -0.103934 0.013548 +v -0.046916 -0.115485 0.009332 +v -0.023918 -0.122598 0.004758 +v -0.024386 0.122598 0.000000 +v -0.047835 0.115485 0.000000 +v -0.069446 0.103934 -0.000000 +v -0.088388 0.088388 0.000000 +v -0.103934 0.069446 0.000000 +v -0.115485 0.047835 0.000000 +v -0.122598 0.024386 -0.000000 +v -0.125000 -0.000000 -0.000000 +v -0.122598 -0.024386 -0.000000 +v -0.115485 -0.047835 -0.000000 +v -0.103934 -0.069446 0.000000 +v -0.088388 -0.088388 0.000000 +v -0.069446 -0.103934 -0.000000 +v -0.047835 -0.115485 0.000000 +v -0.024386 -0.122598 0.000000 +v -0.023918 0.122598 -0.004758 +v -0.046916 0.115485 -0.009332 +v -0.068112 0.103934 -0.013548 +v -0.086690 0.088388 -0.017244 +v -0.101937 0.069446 -0.020276 +v -0.113266 0.047835 -0.022530 +v -0.120242 0.024386 -0.023918 +v -0.122598 -0.000000 -0.024386 +v -0.120242 -0.024386 -0.023918 +v -0.113266 -0.047835 -0.022530 +v -0.101937 -0.069446 -0.020276 +v -0.086690 -0.088388 -0.017244 +v -0.068112 -0.103934 -0.013548 +v -0.046916 -0.115485 -0.009332 +v -0.023918 -0.122598 -0.004758 +v -0.022530 0.122598 -0.009332 +v -0.044194 0.115485 -0.018306 +v -0.064160 0.103934 -0.026576 +v -0.081660 0.088388 -0.033825 +v -0.096022 0.069446 -0.039774 +v -0.106694 0.047835 -0.044194 +v -0.113266 0.024386 -0.046916 +v -0.115485 -0.000000 -0.047835 +v -0.113266 -0.024386 -0.046916 +v -0.106694 -0.047835 -0.044194 +v -0.096022 -0.069446 -0.039774 +v -0.081660 -0.088388 -0.033825 +v -0.064160 -0.103934 -0.026576 +v -0.044194 -0.115485 -0.018306 +v -0.022530 -0.122598 -0.009332 +v -0.020276 0.122598 -0.013548 +v -0.039774 0.115485 -0.026576 +v -0.057742 0.103934 -0.038582 +v -0.073492 0.088388 -0.049106 +v -0.086418 0.069446 -0.057742 +v -0.096022 0.047835 -0.064160 +v -0.101937 0.024386 -0.068112 +v -0.103934 -0.000000 -0.069446 +v -0.101937 -0.024386 -0.068112 +v -0.096022 -0.047835 -0.064160 +v -0.086418 -0.069446 -0.057742 +v -0.073492 -0.088388 -0.049106 +v -0.057742 -0.103934 -0.038582 +v -0.039774 -0.115485 -0.026576 +v -0.020276 -0.122598 -0.013548 +v -0.017244 0.122598 -0.017244 +v -0.033825 0.115485 -0.033825 +v -0.049106 0.103934 -0.049106 +v -0.062500 0.088388 -0.062500 +v -0.073492 0.069446 -0.073492 +v -0.081660 0.047835 -0.081660 +v -0.086690 0.024386 -0.086690 +v -0.088388 -0.000000 -0.088388 +v -0.086690 -0.024386 -0.086690 +v -0.081660 -0.047835 -0.081660 +v -0.073492 -0.069446 -0.073492 +v -0.062500 -0.088388 -0.062500 +v -0.049106 -0.103934 -0.049106 +v -0.033825 -0.115485 -0.033825 +v -0.017244 -0.122598 -0.017244 +v -0.013548 0.122598 -0.020276 +v -0.026576 0.115485 -0.039774 +v -0.038582 0.103934 -0.057742 +v -0.049106 0.088388 -0.073492 +v -0.057742 0.069446 -0.086418 +v -0.064160 0.047835 -0.096022 +v -0.068112 0.024386 -0.101937 +v -0.069446 -0.000000 -0.103934 +v -0.068112 -0.024386 -0.101937 +v -0.064160 -0.047835 -0.096022 +v -0.057742 -0.069446 -0.086418 +v -0.049106 -0.088388 -0.073492 +v -0.038582 -0.103934 -0.057742 +v -0.026576 -0.115485 -0.039774 +v -0.013548 -0.122598 -0.020276 +v -0.009332 0.122598 -0.022530 +v -0.018306 0.115485 -0.044194 +v -0.026576 0.103934 -0.064160 +v -0.033825 0.088388 -0.081660 +v -0.039774 0.069446 -0.096022 +v -0.044194 0.047835 -0.106694 +v -0.046916 0.024386 -0.113266 +v -0.047835 -0.000000 -0.115485 +v -0.046916 -0.024386 -0.113266 +v -0.044194 -0.047835 -0.106694 +v -0.039774 -0.069446 -0.096022 +v -0.033825 -0.088388 -0.081660 +v -0.026576 -0.103934 -0.064160 +v -0.018306 -0.115485 -0.044194 +v -0.009332 -0.122598 -0.022530 +v -0.004758 0.122598 -0.023918 +v -0.009332 0.115485 -0.046916 +v -0.013548 0.103934 -0.068112 +v -0.017244 0.088388 -0.086690 +v -0.020276 0.069446 -0.101937 +v -0.022530 0.047835 -0.113266 +v -0.023918 0.024386 -0.120243 +v -0.024386 -0.000000 -0.122598 +v -0.023918 -0.024386 -0.120243 +v -0.022530 -0.047835 -0.113266 +v -0.020276 -0.069446 -0.101937 +v -0.017244 -0.088388 -0.086690 +v -0.013548 -0.103934 -0.068112 +v -0.009332 -0.115485 -0.046916 +v -0.004758 -0.122598 -0.023918 +v 0.000000 -0.000000 -0.125000 +v 0.000000 -0.024386 -0.122598 +v 0.000000 -0.047835 -0.115485 +v 0.000000 -0.115485 -0.047835 +v 0.000000 -0.122598 -0.024386 +v 0.000000 -0.125000 0.000000 +vn 0.0000 0.9796 -0.2010 +vn 0.0757 0.9217 -0.3804 +vn 0.0000 0.9217 -0.3879 +vn 0.0000 -0.1939 -0.9810 +vn 0.1804 -0.3805 -0.9070 +vn 0.0000 -0.3805 -0.9247 +vn 0.1092 0.8286 -0.5490 +vn 0.0000 0.8286 -0.5598 +vn 0.1626 -0.5528 -0.8173 +vn 0.0000 -0.5528 -0.8333 +vn 0.1385 0.7040 -0.6965 +vn 0.0000 0.7040 -0.7101 +vn 0.0000 -0.7040 -0.7101 +vn 0.1385 -0.7040 -0.6965 +vn 0.1626 0.5528 -0.8173 +vn 0.0000 0.5528 -0.8333 +vn 0.1092 -0.8286 -0.5490 +vn 0.0000 -0.8286 -0.5598 +vn 0.1804 0.3805 -0.9070 +vn 0.0000 0.3805 -0.9247 +vn 0.0757 -0.9217 -0.3804 +vn 0.0000 -0.9217 -0.3879 +vn 0.1914 0.1939 -0.9622 +vn 0.0000 0.1939 -0.9810 +vn 0.0392 -0.9796 -0.1971 +vn 0.0000 -0.9796 -0.2010 +vn 0.0000 0.0000 -1.0000 +vn 0.1951 0.0000 -0.9808 +vn 0.0000 1.0000 0.0000 +vn 0.0392 0.9796 -0.1971 +vn 0.0000 -1.0000 0.0000 +vn 0.1914 -0.1939 -0.9622 +vn 0.0769 0.9796 -0.1856 +vn 0.0769 -0.9796 -0.1856 +vn 0.3754 -0.1939 -0.9063 +vn 0.1484 0.9217 -0.3583 +vn 0.3539 -0.3805 -0.8544 +vn 0.2142 0.8286 -0.5171 +vn 0.3189 -0.5528 -0.7699 +vn 0.2717 0.7040 -0.6561 +vn 0.2717 -0.7040 -0.6561 +vn 0.3189 0.5528 -0.7699 +vn 0.2142 -0.8286 -0.5171 +vn 0.3539 0.3805 -0.8544 +vn 0.1484 -0.9217 -0.3583 +vn 0.3754 0.1939 -0.9063 +vn 0.3827 0.0000 -0.9239 +vn 0.4630 0.5528 -0.6929 +vn 0.3110 -0.8286 -0.4654 +vn 0.5137 0.3805 -0.7689 +vn 0.2155 -0.9217 -0.3225 +vn 0.5450 0.1939 -0.8157 +vn 0.1116 -0.9796 -0.1671 +vn 0.5556 0.0000 -0.8314 +vn 0.1116 0.9796 -0.1671 +vn 0.5450 -0.1939 -0.8157 +vn 0.2155 0.9217 -0.3225 +vn 0.5137 -0.3805 -0.7689 +vn 0.3110 0.8286 -0.4654 +vn 0.4630 -0.5528 -0.6929 +vn 0.3945 0.7040 -0.5904 +vn 0.3945 -0.7040 -0.5904 +vn 0.6937 -0.1939 -0.6937 +vn 0.2743 0.9217 -0.2743 +vn 0.6539 -0.3805 -0.6539 +vn 0.3958 0.8286 -0.3958 +vn 0.5893 -0.5528 -0.5893 +vn 0.5021 0.7040 -0.5021 +vn 0.5021 -0.7040 -0.5021 +vn 0.5893 0.5528 -0.5893 +vn 0.3958 -0.8286 -0.3958 +vn 0.6539 0.3805 -0.6539 +vn 0.2743 -0.9217 -0.2743 +vn 0.6937 0.1939 -0.6937 +vn 0.1421 -0.9796 -0.1421 +vn 0.7071 0.0000 -0.7071 +vn 0.1421 0.9796 -0.1421 +vn 0.5904 -0.7040 -0.3945 +vn 0.4654 -0.8286 -0.3110 +vn 0.7689 0.3805 -0.5137 +vn 0.3225 -0.9217 -0.2155 +vn 0.8157 0.1939 -0.5450 +vn 0.1671 -0.9796 -0.1116 +vn 0.8314 0.0000 -0.5556 +vn 0.1671 0.9796 -0.1116 +vn 0.8157 -0.1939 -0.5450 +vn 0.3225 0.9217 -0.2155 +vn 0.7689 -0.3805 -0.5137 +vn 0.4654 0.8286 -0.3110 +vn 0.6929 -0.5528 -0.4630 +vn 0.5904 0.7040 -0.3945 +vn 0.6929 0.5528 -0.4630 +vn 0.3583 0.9217 -0.1484 +vn 0.8544 -0.3805 -0.3539 +vn 0.5171 0.8286 -0.2142 +vn 0.7699 -0.5528 -0.3189 +vn 0.6561 0.7040 -0.2717 +vn 0.6561 -0.7040 -0.2717 +vn 0.7699 0.5528 -0.3189 +vn 0.5171 -0.8286 -0.2142 +vn 0.8544 0.3805 -0.3539 +vn 0.3583 -0.9217 -0.1484 +vn 0.9063 0.1939 -0.3754 +vn 0.1856 -0.9796 -0.0769 +vn 0.9239 0.0000 -0.3827 +vn 0.1856 0.9796 -0.0769 +vn 0.9063 -0.1939 -0.3754 +vn 0.9070 0.3805 -0.1804 +vn 0.5490 -0.8286 -0.1092 +vn 0.3804 -0.9217 -0.0757 +vn 0.9622 0.1939 -0.1914 +vn 0.1971 -0.9796 -0.0392 +vn 0.9808 0.0000 -0.1951 +vn 0.1971 0.9796 -0.0392 +vn 0.9622 -0.1939 -0.1914 +vn 0.3804 0.9217 -0.0757 +vn 0.9070 -0.3805 -0.1804 +vn 0.5490 0.8286 -0.1092 +vn 0.8173 -0.5528 -0.1626 +vn 0.6965 0.7040 -0.1385 +vn 0.6965 -0.7040 -0.1385 +vn 0.8173 0.5528 -0.1626 +vn 0.9810 -0.1939 0.0000 +vn 0.9247 -0.3805 0.0000 +vn 0.5598 0.8286 0.0000 +vn 0.8333 -0.5528 0.0000 +vn 0.7101 0.7040 0.0000 +vn 0.7101 -0.7040 0.0000 +vn 0.8333 0.5528 0.0000 +vn 0.5598 -0.8286 0.0000 +vn 0.9247 0.3805 0.0000 +vn 0.3879 -0.9217 0.0000 +vn 0.9810 0.1939 0.0000 +vn 0.2010 -0.9796 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.2010 0.9796 0.0000 +vn 0.3879 0.9217 0.0000 +vn 0.3804 -0.9217 0.0757 +vn 0.9070 0.3805 0.1804 +vn 0.9622 0.1939 0.1914 +vn 0.1971 -0.9796 0.0392 +vn 0.9808 0.0000 0.1951 +vn 0.1971 0.9796 0.0392 +vn 0.9622 -0.1939 0.1914 +vn 0.3804 0.9217 0.0757 +vn 0.9070 -0.3805 0.1804 +vn 0.5490 0.8286 0.1092 +vn 0.8173 -0.5528 0.1626 +vn 0.6965 0.7040 0.1385 +vn 0.6965 -0.7040 0.1385 +vn 0.8173 0.5528 0.1626 +vn 0.5490 -0.8286 0.1092 +vn 0.7699 -0.5528 0.3189 +vn 0.6561 0.7040 0.2717 +vn 0.6561 -0.7040 0.2717 +vn 0.7699 0.5528 0.3189 +vn 0.5171 -0.8286 0.2142 +vn 0.8544 0.3805 0.3539 +vn 0.3583 -0.9217 0.1484 +vn 0.9063 0.1939 0.3754 +vn 0.1856 -0.9796 0.0769 +vn 0.9239 0.0000 0.3827 +vn 0.1856 0.9796 0.0769 +vn 0.9063 -0.1939 0.3754 +vn 0.3583 0.9217 0.1484 +vn 0.8544 -0.3805 0.3539 +vn 0.5171 0.8286 0.2142 +vn 0.3225 -0.9217 0.2155 +vn 0.1671 -0.9796 0.1116 +vn 0.8157 0.1939 0.5450 +vn 0.8314 0.0000 0.5556 +vn 0.1671 0.9796 0.1116 +vn 0.8157 -0.1939 0.5450 +vn 0.3225 0.9217 0.2155 +vn 0.7689 -0.3805 0.5137 +vn 0.4654 0.8286 0.3110 +vn 0.6929 -0.5528 0.4630 +vn 0.5904 0.7040 0.3945 +vn 0.5904 -0.7040 0.3945 +vn 0.6929 0.5528 0.4630 +vn 0.4654 -0.8286 0.3110 +vn 0.7689 0.3805 0.5137 +vn 0.5021 0.7040 0.5021 +vn 0.5893 -0.5528 0.5893 +vn 0.5021 -0.7040 0.5021 +vn 0.5893 0.5528 0.5893 +vn 0.3958 -0.8286 0.3958 +vn 0.6539 0.3805 0.6539 +vn 0.2743 -0.9217 0.2743 +vn 0.6937 0.1939 0.6937 +vn 0.1421 -0.9796 0.1421 +vn 0.7071 0.0000 0.7071 +vn 0.1421 0.9796 0.1421 +vn 0.6937 -0.1939 0.6937 +vn 0.2743 0.9217 0.2743 +vn 0.6539 -0.3805 0.6539 +vn 0.3958 0.8286 0.3958 +vn 0.5450 0.1939 0.8157 +vn 0.5556 0.0000 0.8314 +vn 0.1116 0.9796 0.1671 +vn 0.1116 -0.9796 0.1671 +vn 0.5450 -0.1939 0.8157 +vn 0.2155 0.9217 0.3225 +vn 0.5137 -0.3805 0.7689 +vn 0.3110 0.8286 0.4654 +vn 0.4630 -0.5528 0.6929 +vn 0.3945 0.7040 0.5904 +vn 0.3945 -0.7040 0.5904 +vn 0.4630 0.5528 0.6929 +vn 0.3110 -0.8286 0.4654 +vn 0.5137 0.3805 0.7689 +vn 0.2155 -0.9217 0.3225 +vn 0.2717 -0.7040 0.6561 +vn 0.2717 0.7040 0.6561 +vn 0.3189 0.5528 0.7699 +vn 0.2142 -0.8286 0.5171 +vn 0.3539 0.3805 0.8544 +vn 0.1484 -0.9217 0.3583 +vn 0.3754 0.1939 0.9063 +vn 0.0769 -0.9796 0.1856 +vn 0.3827 0.0000 0.9239 +vn 0.0769 0.9796 0.1856 +vn 0.3754 -0.1939 0.9063 +vn 0.1484 0.9217 0.3583 +vn 0.3539 -0.3805 0.8544 +vn 0.2142 0.8286 0.5171 +vn 0.3189 -0.5528 0.7699 +vn 0.0392 0.9796 0.1971 +vn 0.0392 -0.9796 0.1971 +vn 0.1914 -0.1939 0.9622 +vn 0.0757 0.9217 0.3804 +vn 0.1804 -0.3805 0.9070 +vn 0.1092 0.8286 0.5490 +vn 0.1626 -0.5528 0.8173 +vn 0.1385 0.7040 0.6965 +vn 0.1385 -0.7040 0.6965 +vn 0.1626 0.5528 0.8173 +vn 0.1092 -0.8286 0.5490 +vn 0.1804 0.3805 0.9070 +vn 0.0757 -0.9217 0.3804 +vn 0.1914 0.1939 0.9622 +vn 0.1951 0.0000 0.9808 +vn 0.0000 0.7040 0.7101 +vn 0.0000 0.5528 0.8333 +vn 0.0000 -0.7040 0.7101 +vn 0.0000 -0.8286 0.5598 +vn 0.0000 0.3805 0.9247 +vn 0.0000 -0.9217 0.3879 +vn 0.0000 0.1939 0.9810 +vn 0.0000 -0.9796 0.2010 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.9796 0.2010 +vn 0.0000 -0.1939 0.9810 +vn 0.0000 0.9217 0.3879 +vn 0.0000 -0.3805 0.9247 +vn 0.0000 0.8286 0.5598 +vn 0.0000 -0.5528 0.8333 +vn -0.1914 -0.1939 0.9622 +vn -0.0757 0.9217 0.3804 +vn -0.1804 -0.3805 0.9070 +vn -0.1092 0.8286 0.5490 +vn -0.1626 -0.5528 0.8173 +vn -0.1385 0.7040 0.6965 +vn -0.1385 -0.7040 0.6965 +vn -0.1626 0.5528 0.8173 +vn -0.1092 -0.8286 0.5490 +vn -0.1804 0.3805 0.9070 +vn -0.0757 -0.9217 0.3804 +vn -0.1914 0.1939 0.9622 +vn -0.0392 -0.9796 0.1971 +vn -0.1951 0.0000 0.9808 +vn -0.0392 0.9796 0.1971 +vn -0.2717 -0.7040 0.6561 +vn -0.2142 -0.8286 0.5171 +vn -0.3539 0.3805 0.8544 +vn -0.1484 -0.9217 0.3583 +vn -0.3754 0.1939 0.9063 +vn -0.0769 -0.9796 0.1856 +vn -0.3827 0.0000 0.9239 +vn -0.0769 0.9796 0.1856 +vn -0.3754 -0.1939 0.9063 +vn -0.1484 0.9217 0.3583 +vn -0.3539 -0.3805 0.8544 +vn -0.2142 0.8286 0.5171 +vn -0.3189 -0.5528 0.7699 +vn -0.2717 0.7040 0.6561 +vn -0.3189 0.5528 0.7699 +vn -0.5450 -0.1939 0.8157 +vn -0.5137 -0.3805 0.7689 +vn -0.3110 0.8286 0.4654 +vn -0.4630 -0.5528 0.6929 +vn -0.3945 0.7040 0.5904 +vn -0.3945 -0.7040 0.5904 +vn -0.4630 0.5528 0.6929 +vn -0.3110 -0.8286 0.4654 +vn -0.5137 0.3805 0.7689 +vn -0.2155 -0.9217 0.3225 +vn -0.5450 0.1939 0.8157 +vn -0.1116 -0.9796 0.1671 +vn -0.5556 0.0000 0.8314 +vn -0.1116 0.9796 0.1671 +vn -0.2155 0.9217 0.3225 +vn -0.2743 -0.9217 0.2743 +vn -0.6539 0.3805 0.6539 +vn -0.6937 0.1939 0.6937 +vn -0.1421 -0.9796 0.1421 +vn -0.7071 0.0000 0.7071 +vn -0.1421 0.9796 0.1421 +vn -0.6937 -0.1939 0.6937 +vn -0.2743 0.9217 0.2743 +vn -0.6539 -0.3805 0.6539 +vn -0.3958 0.8286 0.3958 +vn -0.5893 -0.5528 0.5893 +vn -0.5021 0.7040 0.5021 +vn -0.5021 -0.7040 0.5021 +vn -0.5893 0.5528 0.5893 +vn -0.3958 -0.8286 0.3958 +vn -0.3225 0.9217 0.2155 +vn -0.4654 0.8286 0.3110 +vn -0.6929 -0.5528 0.4630 +vn -0.5904 0.7040 0.3945 +vn -0.5904 -0.7040 0.3945 +vn -0.6929 0.5528 0.4630 +vn -0.4654 -0.8286 0.3110 +vn -0.7689 0.3805 0.5137 +vn -0.3225 -0.9217 0.2155 +vn -0.8157 0.1939 0.5450 +vn -0.1671 -0.9796 0.1116 +vn -0.8314 0.0000 0.5556 +vn -0.1671 0.9796 0.1116 +vn -0.8157 -0.1939 0.5450 +vn -0.7689 -0.3805 0.5137 +vn -0.8544 0.3805 0.3539 +vn -0.9063 0.1939 0.3754 +vn -0.1856 -0.9796 0.0769 +vn -0.9239 0.0000 0.3827 +vn -0.1856 0.9796 0.0769 +vn -0.9063 -0.1939 0.3754 +vn -0.3583 0.9217 0.1484 +vn -0.8544 -0.3805 0.3539 +vn -0.5171 0.8286 0.2142 +vn -0.7699 -0.5528 0.3189 +vn -0.6561 0.7040 0.2717 +vn -0.6561 -0.7040 0.2717 +vn -0.7699 0.5528 0.3189 +vn -0.5171 -0.8286 0.2142 +vn -0.3583 -0.9217 0.1484 +vn -0.8173 -0.5528 0.1626 +vn -0.6965 0.7040 0.1385 +vn -0.6965 -0.7040 0.1385 +vn -0.8173 0.5528 0.1626 +vn -0.5490 -0.8286 0.1092 +vn -0.9070 0.3805 0.1804 +vn -0.3804 -0.9217 0.0757 +vn -0.9622 0.1939 0.1914 +vn -0.1971 -0.9796 0.0392 +vn -0.9808 0.0000 0.1951 +vn -0.1971 0.9796 0.0392 +vn -0.9622 -0.1939 0.1914 +vn -0.3804 0.9217 0.0757 +vn -0.9070 -0.3805 0.1804 +vn -0.5490 0.8286 0.1092 +vn -0.3879 -0.9217 0.0000 +vn -0.2010 -0.9796 0.0000 +vn -0.9810 0.1939 0.0000 +vn -1.0000 0.0000 0.0000 +vn -0.2010 0.9796 0.0000 +vn -0.9810 -0.1939 0.0000 +vn -0.3879 0.9217 0.0000 +vn -0.9247 -0.3805 0.0000 +vn -0.5598 0.8286 0.0000 +vn -0.8333 -0.5528 0.0000 +vn -0.7101 0.7040 0.0000 +vn -0.7101 -0.7040 0.0000 +vn -0.8333 0.5528 0.0000 +vn -0.5598 -0.8286 0.0000 +vn -0.9247 0.3805 0.0000 +vn -0.6965 0.7040 -0.1385 +vn -0.8173 -0.5528 -0.1626 +vn -0.6965 -0.7040 -0.1385 +vn -0.8173 0.5528 -0.1626 +vn -0.5490 -0.8286 -0.1092 +vn -0.9070 0.3805 -0.1804 +vn -0.3804 -0.9217 -0.0757 +vn -0.9622 0.1939 -0.1914 +vn -0.1971 -0.9796 -0.0392 +vn -0.9808 0.0000 -0.1951 +vn -0.1971 0.9796 -0.0392 +vn -0.9622 -0.1939 -0.1914 +vn -0.3804 0.9217 -0.0757 +vn -0.9070 -0.3805 -0.1804 +vn -0.5490 0.8286 -0.1092 +vn -0.9063 0.1939 -0.3754 +vn -0.9239 0.0000 -0.3827 +vn -0.1856 0.9796 -0.0769 +vn -0.1856 -0.9796 -0.0769 +vn -0.9063 -0.1939 -0.3754 +vn -0.3583 0.9217 -0.1484 +vn -0.8544 -0.3805 -0.3539 +vn -0.5171 0.8286 -0.2142 +vn -0.7699 -0.5528 -0.3189 +vn -0.6561 0.7040 -0.2717 +vn -0.6561 -0.7040 -0.2717 +vn -0.7699 0.5528 -0.3189 +vn -0.5171 -0.8286 -0.2142 +vn -0.8544 0.3805 -0.3539 +vn -0.3583 -0.9217 -0.1484 +vn -0.5904 -0.7040 -0.3945 +vn -0.5904 0.7040 -0.3945 +vn -0.6929 0.5528 -0.4630 +vn -0.4654 -0.8286 -0.3110 +vn -0.7689 0.3805 -0.5137 +vn -0.3225 -0.9217 -0.2155 +vn -0.8157 0.1939 -0.5450 +vn -0.1671 -0.9796 -0.1116 +vn -0.8314 0.0000 -0.5556 +vn -0.1671 0.9796 -0.1116 +vn -0.8157 -0.1939 -0.5450 +vn -0.3225 0.9217 -0.2155 +vn -0.7689 -0.3805 -0.5137 +vn -0.4654 0.8286 -0.3110 +vn -0.6929 -0.5528 -0.4630 +vn -0.1421 -0.9796 -0.1421 +vn -0.6937 -0.1939 -0.6937 +vn -0.2743 0.9217 -0.2743 +vn -0.6539 -0.3805 -0.6539 +vn -0.3958 0.8286 -0.3958 +vn -0.5893 -0.5528 -0.5893 +vn -0.5021 0.7040 -0.5021 +vn -0.5021 -0.7040 -0.5021 +vn -0.5893 0.5528 -0.5893 +vn -0.3958 -0.8286 -0.3958 +vn -0.6539 0.3805 -0.6539 +vn -0.2743 -0.9217 -0.2743 +vn -0.6937 0.1939 -0.6937 +vn -0.7071 0.0000 -0.7071 +vn -0.1421 0.9796 -0.1421 +vn -0.3945 -0.7040 -0.5904 +vn -0.3110 -0.8286 -0.4654 +vn -0.4630 0.5528 -0.6929 +vn -0.5137 0.3805 -0.7689 +vn -0.2155 -0.9217 -0.3225 +vn -0.5450 0.1939 -0.8157 +vn -0.1116 -0.9796 -0.1671 +vn -0.5556 0.0000 -0.8314 +vn -0.1116 0.9796 -0.1671 +vn -0.5450 -0.1939 -0.8157 +vn -0.2155 0.9217 -0.3225 +vn -0.5137 -0.3805 -0.7689 +vn -0.3110 0.8286 -0.4654 +vn -0.4630 -0.5528 -0.6929 +vn -0.3945 0.7040 -0.5904 +vn -0.1484 0.9217 -0.3583 +vn -0.3539 -0.3805 -0.8544 +vn -0.2142 0.8286 -0.5171 +vn -0.3189 -0.5528 -0.7699 +vn -0.2717 0.7040 -0.6561 +vn -0.2717 -0.7040 -0.6561 +vn -0.3189 0.5528 -0.7699 +vn -0.2142 -0.8286 -0.5171 +vn -0.3539 0.3805 -0.8544 +vn -0.1484 -0.9217 -0.3583 +vn -0.3754 0.1939 -0.9063 +vn -0.0769 -0.9796 -0.1856 +vn -0.3827 0.0000 -0.9239 +vn -0.0769 0.9796 -0.1856 +vn -0.3754 -0.1939 -0.9063 +vn -0.1626 0.5528 -0.8173 +vn -0.1804 0.3805 -0.9070 +vn -0.0757 -0.9217 -0.3804 +vn -0.1914 0.1939 -0.9622 +vn -0.0392 -0.9796 -0.1971 +vn -0.1951 0.0000 -0.9808 +vn -0.0392 0.9796 -0.1971 +vn -0.1914 -0.1939 -0.9622 +vn -0.0757 0.9217 -0.3804 +vn -0.1804 -0.3805 -0.9070 +vn -0.1092 0.8286 -0.5490 +vn -0.1626 -0.5528 -0.8173 +vn -0.1385 0.7040 -0.6965 +vn -0.1385 -0.7040 -0.6965 +vn -0.1092 -0.8286 -0.5490 +s 1 +f 1//1 12//2 2//3 +f 478//4 20//5 479//6 +f 2//3 13//7 3//8 +f 479//6 21//9 8//10 +f 3//8 14//11 4//12 +f 9//13 21//9 22//14 +f 4//12 15//15 5//16 +f 9//13 23//17 10//18 +f 5//16 16//19 6//20 +f 10//18 24//21 480//22 +f 6//20 17//23 7//24 +f 480//22 25//25 481//26 +f 477//27 17//23 18//28 +f 1//1 326//29 11//30 +f 482//31 481//26 25//25 +f 477//27 19//32 478//4 +f 11//30 326//29 26//33 +f 482//31 25//25 40//34 +f 18//28 34//35 19//32 +f 11//30 27//36 12//2 +f 19//32 35//37 20//5 +f 12//2 28//38 13//7 +f 20//5 36//39 21//9 +f 13//7 29//40 14//11 +f 21//9 37//41 22//14 +f 15//15 29//40 30//42 +f 22//14 38//43 23//17 +f 15//15 31//44 16//19 +f 23//17 39//45 24//21 +f 17//23 31//44 32//46 +f 24//21 40//34 25//25 +f 18//28 32//46 33//47 +f 29//40 45//48 30//42 +f 37//41 53//49 38//43 +f 30//42 46//50 31//44 +f 38//43 54//51 39//45 +f 31//44 47//52 32//46 +f 39//45 55//53 40//34 +f 32//46 48//54 33//47 +f 26//33 326//29 41//55 +f 482//31 40//34 55//53 +f 33//47 49//56 34//35 +f 26//33 42//57 27//36 +f 34//35 50//58 35//37 +f 27//36 43//59 28//38 +f 36//39 50//58 51//60 +f 28//38 44//61 29//40 +f 36//39 52//62 37//41 +f 48//54 64//63 49//56 +f 41//55 57//64 42//57 +f 50//58 64//63 65//65 +f 43//59 57//64 58//66 +f 51//60 65//65 66//67 +f 43//59 59//68 44//61 +f 52//62 66//67 67//69 +f 44//61 60//70 45//48 +f 53//49 67//69 68//71 +f 45//48 61//72 46//50 +f 53//49 69//73 54//51 +f 46//50 62//74 47//52 +f 55//53 69//73 70//75 +f 48//54 62//74 63//76 +f 41//55 326//29 56//77 +f 482//31 55//53 70//75 +f 68//71 82//78 83//79 +f 60//70 76//80 61//72 +f 69//73 83//79 84//81 +f 61//72 77//82 62//74 +f 69//73 85//83 70//75 +f 63//76 77//82 78//84 +f 56//77 326//29 71//85 +f 482//31 70//75 85//83 +f 63//76 79//86 64//63 +f 57//64 71//85 72//87 +f 65//65 79//86 80//88 +f 57//64 73//89 58//66 +f 65//65 81//90 66//67 +f 58//66 74//91 59//68 +f 66//67 82//78 67//69 +f 60//70 74//91 75//92 +f 71//85 87//93 72//87 +f 79//86 95//94 80//88 +f 72//87 88//95 73//89 +f 80//88 96//96 81//90 +f 73//89 89//97 74//91 +f 81//90 97//98 82//78 +f 74//91 90//99 75//92 +f 83//79 97//98 98//100 +f 75//92 91//101 76//80 +f 84//81 98//100 99//102 +f 77//82 91//101 92//103 +f 85//83 99//102 100//104 +f 78//84 92//103 93//105 +f 71//85 326//29 86//106 +f 482//31 85//83 100//104 +f 78//84 94//107 79//86 +f 90//99 106//108 91//101 +f 99//102 113//109 114//110 +f 92//103 106//108 107//111 +f 99//102 115//112 100//104 +f 93//105 107//111 108//113 +f 86//106 326//29 101//114 +f 482//31 100//104 115//112 +f 93//105 109//115 94//107 +f 86//106 102//116 87//93 +f 95//94 109//115 110//117 +f 87//93 103//118 88//95 +f 95//94 111//119 96//96 +f 88//95 104//120 89//97 +f 96//96 112//121 97//98 +f 90//99 104//120 105//122 +f 98//100 112//121 113//109 +f 110//117 124//123 125//124 +f 102//116 118//125 103//118 +f 110//117 126//126 111//119 +f 103//118 119//127 104//120 +f 111//119 127//128 112//121 +f 105//122 119//127 120//129 +f 113//109 127//128 128//130 +f 105//122 121//131 106//108 +f 113//109 129//132 114//110 +f 107//111 121//131 122//133 +f 114//110 130//134 115//112 +f 108//113 122//133 123//135 +f 101//114 326//29 116//136 +f 482//31 115//112 130//134 +f 108//113 124//123 109//115 +f 102//116 116//136 117//137 +f 128//130 144//138 129//132 +f 122//133 136//139 137//140 +f 129//132 145//141 130//134 +f 123//135 137//140 138//142 +f 116//136 326//29 131//143 +f 482//31 130//134 145//141 +f 123//135 139//144 124//123 +f 117//137 131//143 132//145 +f 125//124 139//144 140//146 +f 118//125 132//145 133//147 +f 125//124 141//148 126//126 +f 118//125 134//149 119//127 +f 126//126 142//150 127//128 +f 120//129 134//149 135//151 +f 128//130 142//150 143//152 +f 120//129 136//139 121//131 +f 140//146 156//153 141//148 +f 133//147 149//154 134//149 +f 141//148 157//155 142//150 +f 134//149 150//156 135//151 +f 143//152 157//155 158//157 +f 135//151 151//158 136//139 +f 144//138 158//157 159//159 +f 137//140 151//158 152//160 +f 144//138 160//161 145//141 +f 138//142 152//160 153//162 +f 131//143 326//29 146//163 +f 482//31 145//141 160//161 +f 138//142 154//164 139//144 +f 131//143 147//165 132//145 +f 140//146 154//164 155//166 +f 133//147 147//165 148//167 +f 160//161 174//168 175//169 +f 153//162 167//170 168//171 +f 146//163 326//29 161//172 +f 482//31 160//161 175//169 +f 153//162 169//173 154//164 +f 147//165 161//172 162//174 +f 155//166 169//173 170//175 +f 147//165 163//176 148//167 +f 155//166 171//177 156//153 +f 148//167 164//178 149//154 +f 156//153 172//179 157//155 +f 149//154 165//180 150//156 +f 158//157 172//179 173//181 +f 150//156 166//182 151//158 +f 158//157 174//168 159//159 +f 152//160 166//182 167//170 +f 163//176 179//183 164//178 +f 172//179 186//184 187//185 +f 165//180 179//183 180//186 +f 172//179 188//187 173//181 +f 165//180 181//188 166//182 +f 173//181 189//189 174//168 +f 166//182 182//190 167//170 +f 174//168 190//191 175//169 +f 168//171 182//190 183//192 +f 161//172 326//29 176//193 +f 482//31 175//169 190//191 +f 168//171 184//194 169//173 +f 161//172 177//195 162//174 +f 169//173 185//196 170//175 +f 162//174 178//197 163//176 +f 170//175 186//184 171//177 +f 183//192 197//198 198//199 +f 176//193 326//29 191//200 +f 482//31 190//191 205//201 +f 183//192 199//202 184//194 +f 177//195 191//200 192//203 +f 184//194 200//204 185//196 +f 177//195 193//205 178//197 +f 185//196 201//206 186//184 +f 178//197 194//207 179//183 +f 186//184 202//208 187//185 +f 180//186 194//207 195//209 +f 188//187 202//208 203//210 +f 180//186 196//211 181//188 +f 189//189 203//210 204//212 +f 182//190 196//211 197//198 +f 189//189 205//201 190//191 +f 201//206 217//213 202//208 +f 195//209 209//214 210//215 +f 203//210 217//213 218//216 +f 195//209 211//217 196//211 +f 203//210 219//218 204//212 +f 197//198 211//217 212//219 +f 205//201 219//218 220//220 +f 198//199 212//219 213//221 +f 191//200 326//29 206//222 +f 482//31 205//201 220//220 +f 198//199 214//223 199//202 +f 191//200 207//224 192//203 +f 200//204 214//223 215//225 +f 192//203 208//226 193//205 +f 200//204 216//227 201//206 +f 193//205 209//214 194//207 +f 206//222 326//29 221//228 +f 482//31 220//220 235//229 +f 213//221 229//230 214//223 +f 206//222 222//231 207//224 +f 215//225 229//230 230//232 +f 208//226 222//231 223//233 +f 215//225 231//234 216//227 +f 208//226 224//235 209//214 +f 216//227 232//236 217//213 +f 210//215 224//235 225//237 +f 218//216 232//236 233//238 +f 210//215 226//239 211//217 +f 218//216 234//240 219//218 +f 212//219 226//239 227//241 +f 220//220 234//240 235//229 +f 213//221 227//241 228//242 +f 225//237 239//243 240//244 +f 233//238 247//245 248//246 +f 225//237 241//247 226//239 +f 233//238 249//248 234//240 +f 227//241 241//247 242//249 +f 235//229 249//248 250//250 +f 228//242 242//249 243//251 +f 221//228 326//29 236//252 +f 482//31 235//229 250//250 +f 228//242 244//253 229//230 +f 221//228 237//254 222//231 +f 230//232 244//253 245//255 +f 223//233 237//254 238//256 +f 230//232 246//257 231//234 +f 223//233 239//243 224//235 +f 231//234 247//245 232//236 +f 243//251 259//258 244//253 +f 236//252 252//259 237//254 +f 245//255 259//258 260//260 +f 237//254 253//261 238//256 +f 245//255 261//262 246//257 +f 238//256 254//263 239//243 +f 247//245 261//262 262//264 +f 240//244 254//263 255//265 +f 248//246 262//264 263//266 +f 240//244 256//267 241//247 +f 248//246 264//268 249//248 +f 242//249 256//267 257//269 +f 249//248 265//270 250//250 +f 243//251 257//269 258//271 +f 236//252 326//29 251//272 +f 482//31 250//250 265//270 +f 263//266 277//273 278//274 +f 255//265 271//275 256//267 +f 263//266 279//276 264//268 +f 257//269 271//275 272//277 +f 264//268 280//278 265//270 +f 258//271 272//277 273//279 +f 251//272 326//29 266//280 +f 482//31 265//270 280//278 +f 258//271 274//281 259//258 +f 251//272 267//282 252//259 +f 260//260 274//281 275//283 +f 252//259 268//284 253//261 +f 260//260 276//285 261//262 +f 253//261 269//286 254//263 +f 261//262 277//273 262//264 +f 255//265 269//286 270//287 +f 275//283 289//288 290//289 +f 267//282 283//290 268//284 +f 275//283 291//291 276//285 +f 268//284 284//292 269//286 +f 276//285 292//293 277//273 +f 270//287 284//292 285//294 +f 278//274 292//293 293//295 +f 271//275 285//294 286//296 +f 278//274 294//297 279//276 +f 272//277 286//296 287//298 +f 280//278 294//297 295//299 +f 273//279 287//298 288//300 +f 266//280 326//29 281//301 +f 482//31 280//278 295//299 +f 273//279 289//288 274//281 +f 266//280 282//302 267//282 +f 293//295 309//303 294//297 +f 287//298 301//304 302//305 +f 294//297 310//306 295//299 +f 288//300 302//305 303//307 +f 281//301 326//29 296//308 +f 482//31 295//299 310//306 +f 288//300 304//309 289//288 +f 281//301 297//310 282//302 +f 290//289 304//309 305//311 +f 282//302 298//312 283//290 +f 290//289 306//313 291//291 +f 283//290 299//314 284//292 +f 291//291 307//315 292//293 +f 284//292 300//316 285//294 +f 293//295 307//315 308//317 +f 286//296 300//316 301//304 +f 298//312 312//318 313//319 +f 305//311 321//320 306//313 +f 298//312 314//321 299//314 +f 306//313 322//322 307//315 +f 299//314 315//323 300//316 +f 308//317 322//322 323//324 +f 301//304 315//323 316//325 +f 309//303 323//324 324//326 +f 302//305 316//325 317//327 +f 309//303 325//328 310//306 +f 303//307 317//327 318//329 +f 296//308 326//29 311//330 +f 482//31 310//306 325//328 +f 303//307 319//331 304//309 +f 297//310 311//330 312//318 +f 305//311 319//331 320//332 +f 317//327 332//333 333//334 +f 324//326 341//335 325//328 +f 318//329 333//334 334//336 +f 311//330 326//29 327//337 +f 482//31 325//328 341//335 +f 318//329 335//338 319//331 +f 311//330 328//339 312//318 +f 320//332 335//338 336//340 +f 312//318 329//341 313//319 +f 320//332 337//342 321//320 +f 313//319 330//343 314//321 +f 321//320 338//344 322//322 +f 314//321 331//345 315//323 +f 323//324 338//344 339//346 +f 316//325 331//345 332//333 +f 323//324 340//347 324//326 +f 336//340 352//348 337//342 +f 329//341 345//349 330//343 +f 337//342 353//350 338//344 +f 330//343 346//351 331//345 +f 338//344 354//352 339//346 +f 332//333 346//351 347//353 +f 339//346 355//354 340//347 +f 333//334 347//353 348//355 +f 341//335 355//354 356//356 +f 334//336 348//355 349//357 +f 327//337 326//29 342//358 +f 482//31 341//335 356//356 +f 334//336 350//359 335//338 +f 327//337 343//360 328//339 +f 336//340 350//359 351//361 +f 328//339 344//362 329//341 +f 356//356 370//363 371//364 +f 349//357 363//365 364//366 +f 342//358 326//29 357//367 +f 482//31 356//356 371//364 +f 349//357 365//368 350//359 +f 342//358 358//369 343//360 +f 351//361 365//368 366//370 +f 343//360 359//371 344//362 +f 351//361 367//372 352//348 +f 344//362 360//373 345//349 +f 352//348 368//374 353//350 +f 346//351 360//373 361//375 +f 354//352 368//374 369//376 +f 347//353 361//375 362//377 +f 355//354 369//376 370//363 +f 348//355 362//377 363//365 +f 359//371 375//378 360//373 +f 368//374 382//379 383//380 +f 360//373 376//381 361//375 +f 369//376 383//380 384//382 +f 362//377 376//381 377//383 +f 370//363 384//382 385//384 +f 363//365 377//383 378//385 +f 371//364 385//384 386//386 +f 364//366 378//385 379//387 +f 357//367 326//29 372//388 +f 482//31 371//364 386//386 +f 364//366 380//389 365//368 +f 357//367 373//390 358//369 +f 366//370 380//389 381//391 +f 358//369 374//392 359//371 +f 366//370 382//379 367//372 +f 379//387 393//393 394//394 +f 372//388 326//29 387//395 +f 482//31 386//386 401//396 +f 379//387 395//397 380//389 +f 372//388 388//398 373//390 +f 381//391 395//397 396//399 +f 373//390 389//400 374//392 +f 381//391 397//401 382//379 +f 374//392 390//402 375//378 +f 382//379 398//403 383//380 +f 375//378 391//404 376//381 +f 384//382 398//403 399//405 +f 377//383 391//404 392//406 +f 384//382 400//407 385//384 +f 378//385 392//406 393//393 +f 385//384 401//396 386//386 +f 397//401 413//408 398//403 +f 391//404 405//409 406//410 +f 399//405 413//408 414//411 +f 392//406 406//410 407//412 +f 400//407 414//411 415//413 +f 393//393 407//412 408//414 +f 400//407 416//415 401//396 +f 394//394 408//414 409//416 +f 387//395 326//29 402//417 +f 482//31 401//396 416//415 +f 394//394 410//418 395//397 +f 387//395 403//419 388//398 +f 396//399 410//418 411//420 +f 388//398 404//421 389//400 +f 396//399 412//422 397//401 +f 389//400 405//409 390//402 +f 482//31 416//415 431//423 +f 409//416 425//424 410//418 +f 402//417 418//425 403//419 +f 410//418 426//426 411//420 +f 403//419 419//427 404//421 +f 411//420 427//428 412//422 +f 404//421 420//429 405//409 +f 412//422 428//430 413//408 +f 405//409 421//431 406//410 +f 414//411 428//430 429//432 +f 407//412 421//431 422//433 +f 414//411 430//434 415//413 +f 408//414 422//433 423//435 +f 416//415 430//434 431//423 +f 409//416 423//435 424//436 +f 402//417 326//29 417//437 +f 429//432 443//438 444//439 +f 422//433 436//440 437//441 +f 429//432 445//442 430//434 +f 423//435 437//441 438//443 +f 431//423 445//442 446//444 +f 424//436 438//443 439//445 +f 417//437 326//29 432//446 +f 482//31 431//423 446//444 +f 424//436 440//447 425//424 +f 417//437 433//448 418//425 +f 425//424 441//449 426//426 +f 419//427 433//448 434//450 +f 426//426 442//451 427//428 +f 419//427 435//452 420//429 +f 427//428 443//438 428//430 +f 420//429 436//440 421//431 +f 432//446 448//453 433//448 +f 440//447 456//454 441//449 +f 433//448 449//455 434//450 +f 441//449 457//456 442//451 +f 434//450 450//457 435//452 +f 442//451 458//458 443//438 +f 436//440 450//457 451//459 +f 444//439 458//458 459//460 +f 437//441 451//459 452//461 +f 444//439 460//462 445//442 +f 438//443 452//461 453//463 +f 445//442 461//464 446//444 +f 439//445 453//463 454//465 +f 432//446 326//29 447//466 +f 482//31 446//444 461//464 +f 439//445 455//467 440//447 +f 452//461 466//468 467//469 +f 459//460 475//470 460//462 +f 453//463 467//469 468//471 +f 460//462 476//472 461//464 +f 454//465 468//471 469//473 +f 447//466 326//29 462//474 +f 482//31 461//464 476//472 +f 454//465 470//475 455//467 +f 447//466 463//476 448//453 +f 455//467 471//477 456//454 +f 448//453 464//478 449//455 +f 456//454 472//479 457//456 +f 449//455 465//480 450//457 +f 457//456 473//481 458//458 +f 450//457 466//468 451//459 +f 459//460 473//481 474//482 +f 470//475 479//6 471//477 +f 464//478 2//3 3//8 +f 471//477 8//10 472//479 +f 465//480 3//8 4//12 +f 472//479 9//13 473//481 +f 466//468 4//12 5//16 +f 473//481 10//18 474//482 +f 467//469 5//16 6//20 +f 474//482 480//22 475//470 +f 468//471 6//20 7//24 +f 475//470 481//26 476//472 +f 469//473 7//24 477//27 +f 462//474 326//29 1//1 +f 482//31 476//472 481//26 +f 469//473 478//4 470//475 +f 463//476 1//1 2//3 +f 1//1 11//30 12//2 +f 478//4 19//32 20//5 +f 2//3 12//2 13//7 +f 479//6 20//5 21//9 +f 3//8 13//7 14//11 +f 9//13 8//10 21//9 +f 4//12 14//11 15//15 +f 9//13 22//14 23//17 +f 5//16 15//15 16//19 +f 10//18 23//17 24//21 +f 6//20 16//19 17//23 +f 480//22 24//21 25//25 +f 477//27 7//24 17//23 +f 477//27 18//28 19//32 +f 18//28 33//47 34//35 +f 11//30 26//33 27//36 +f 19//32 34//35 35//37 +f 12//2 27//36 28//38 +f 20//5 35//37 36//39 +f 13//7 28//38 29//40 +f 21//9 36//39 37//41 +f 15//15 14//11 29//40 +f 22//14 37//41 38//43 +f 15//15 30//42 31//44 +f 23//17 38//43 39//45 +f 17//23 16//19 31//44 +f 24//21 39//45 40//34 +f 18//28 17//23 32//46 +f 29//40 44//61 45//48 +f 37//41 52//62 53//49 +f 30//42 45//48 46//50 +f 38//43 53//49 54//51 +f 31//44 46//50 47//52 +f 39//45 54//51 55//53 +f 32//46 47//52 48//54 +f 33//47 48//54 49//56 +f 26//33 41//55 42//57 +f 34//35 49//56 50//58 +f 27//36 42//57 43//59 +f 36//39 35//37 50//58 +f 28//38 43//59 44//61 +f 36//39 51//60 52//62 +f 48//54 63//76 64//63 +f 41//55 56//77 57//64 +f 50//58 49//56 64//63 +f 43//59 42//57 57//64 +f 51//60 50//58 65//65 +f 43//59 58//66 59//68 +f 52//62 51//60 66//67 +f 44//61 59//68 60//70 +f 53//49 52//62 67//69 +f 45//48 60//70 61//72 +f 53//49 68//71 69//73 +f 46//50 61//72 62//74 +f 55//53 54//51 69//73 +f 48//54 47//52 62//74 +f 68//71 67//69 82//78 +f 60//70 75//92 76//80 +f 69//73 68//71 83//79 +f 61//72 76//80 77//82 +f 69//73 84//81 85//83 +f 63//76 62//74 77//82 +f 63//76 78//84 79//86 +f 57//64 56//77 71//85 +f 65//65 64//63 79//86 +f 57//64 72//87 73//89 +f 65//65 80//88 81//90 +f 58//66 73//89 74//91 +f 66//67 81//90 82//78 +f 60//70 59//68 74//91 +f 71//85 86//106 87//93 +f 79//86 94//107 95//94 +f 72//87 87//93 88//95 +f 80//88 95//94 96//96 +f 73//89 88//95 89//97 +f 81//90 96//96 97//98 +f 74//91 89//97 90//99 +f 83//79 82//78 97//98 +f 75//92 90//99 91//101 +f 84//81 83//79 98//100 +f 77//82 76//80 91//101 +f 85//83 84//81 99//102 +f 78//84 77//82 92//103 +f 78//84 93//105 94//107 +f 90//99 105//122 106//108 +f 99//102 98//100 113//109 +f 92//103 91//101 106//108 +f 99//102 114//110 115//112 +f 93//105 92//103 107//111 +f 93//105 108//113 109//115 +f 86//106 101//114 102//116 +f 95//94 94//107 109//115 +f 87//93 102//116 103//118 +f 95//94 110//117 111//119 +f 88//95 103//118 104//120 +f 96//96 111//119 112//121 +f 90//99 89//97 104//120 +f 98//100 97//98 112//121 +f 110//117 109//115 124//123 +f 102//116 117//137 118//125 +f 110//117 125//124 126//126 +f 103//118 118//125 119//127 +f 111//119 126//126 127//128 +f 105//122 104//120 119//127 +f 113//109 112//121 127//128 +f 105//122 120//129 121//131 +f 113//109 128//130 129//132 +f 107//111 106//108 121//131 +f 114//110 129//132 130//134 +f 108//113 107//111 122//133 +f 108//113 123//135 124//123 +f 102//116 101//114 116//136 +f 128//130 143//152 144//138 +f 122//133 121//131 136//139 +f 129//132 144//138 145//141 +f 123//135 122//133 137//140 +f 123//135 138//142 139//144 +f 117//137 116//136 131//143 +f 125//124 124//123 139//144 +f 118//125 117//137 132//145 +f 125//124 140//146 141//148 +f 118//125 133//147 134//149 +f 126//126 141//148 142//150 +f 120//129 119//127 134//149 +f 128//130 127//128 142//150 +f 120//129 135//151 136//139 +f 140//146 155//166 156//153 +f 133//147 148//167 149//154 +f 141//148 156//153 157//155 +f 134//149 149//154 150//156 +f 143//152 142//150 157//155 +f 135//151 150//156 151//158 +f 144//138 143//152 158//157 +f 137//140 136//139 151//158 +f 144//138 159//159 160//161 +f 138//142 137//140 152//160 +f 138//142 153//162 154//164 +f 131//143 146//163 147//165 +f 140//146 139//144 154//164 +f 133//147 132//145 147//165 +f 160//161 159//159 174//168 +f 153//162 152//160 167//170 +f 153//162 168//171 169//173 +f 147//165 146//163 161//172 +f 155//166 154//164 169//173 +f 147//165 162//174 163//176 +f 155//166 170//175 171//177 +f 148//167 163//176 164//178 +f 156//153 171//177 172//179 +f 149//154 164//178 165//180 +f 158//157 157//155 172//179 +f 150//156 165//180 166//182 +f 158//157 173//181 174//168 +f 152//160 151//158 166//182 +f 163//176 178//197 179//183 +f 172//179 171//177 186//184 +f 165//180 164//178 179//183 +f 172//179 187//185 188//187 +f 165//180 180//186 181//188 +f 173//181 188//187 189//189 +f 166//182 181//188 182//190 +f 174//168 189//189 190//191 +f 168//171 167//170 182//190 +f 168//171 183//192 184//194 +f 161//172 176//193 177//195 +f 169//173 184//194 185//196 +f 162//174 177//195 178//197 +f 170//175 185//196 186//184 +f 183//192 182//190 197//198 +f 183//192 198//199 199//202 +f 177//195 176//193 191//200 +f 184//194 199//202 200//204 +f 177//195 192//203 193//205 +f 185//196 200//204 201//206 +f 178//197 193//205 194//207 +f 186//184 201//206 202//208 +f 180//186 179//183 194//207 +f 188//187 187//185 202//208 +f 180//186 195//209 196//211 +f 189//189 188//187 203//210 +f 182//190 181//188 196//211 +f 189//189 204//212 205//201 +f 201//206 216//227 217//213 +f 195//209 194//207 209//214 +f 203//210 202//208 217//213 +f 195//209 210//215 211//217 +f 203//210 218//216 219//218 +f 197//198 196//211 211//217 +f 205//201 204//212 219//218 +f 198//199 197//198 212//219 +f 198//199 213//221 214//223 +f 191//200 206//222 207//224 +f 200//204 199//202 214//223 +f 192//203 207//224 208//226 +f 200//204 215//225 216//227 +f 193//205 208//226 209//214 +f 213//221 228//242 229//230 +f 206//222 221//228 222//231 +f 215//225 214//223 229//230 +f 208//226 207//224 222//231 +f 215//225 230//232 231//234 +f 208//226 223//233 224//235 +f 216//227 231//234 232//236 +f 210//215 209//214 224//235 +f 218//216 217//213 232//236 +f 210//215 225//237 226//239 +f 218//216 233//238 234//240 +f 212//219 211//217 226//239 +f 220//220 219//218 234//240 +f 213//221 212//219 227//241 +f 225//237 224//235 239//243 +f 233//238 232//236 247//245 +f 225//237 240//244 241//247 +f 233//238 248//246 249//248 +f 227//241 226//239 241//247 +f 235//229 234//240 249//248 +f 228//242 227//241 242//249 +f 228//242 243//251 244//253 +f 221//228 236//252 237//254 +f 230//232 229//230 244//253 +f 223//233 222//231 237//254 +f 230//232 245//255 246//257 +f 223//233 238//256 239//243 +f 231//234 246//257 247//245 +f 243//251 258//271 259//258 +f 236//252 251//272 252//259 +f 245//255 244//253 259//258 +f 237//254 252//259 253//261 +f 245//255 260//260 261//262 +f 238//256 253//261 254//263 +f 247//245 246//257 261//262 +f 240//244 239//243 254//263 +f 248//246 247//245 262//264 +f 240//244 255//265 256//267 +f 248//246 263//266 264//268 +f 242//249 241//247 256//267 +f 249//248 264//268 265//270 +f 243//251 242//249 257//269 +f 263//266 262//264 277//273 +f 255//265 270//287 271//275 +f 263//266 278//274 279//276 +f 257//269 256//267 271//275 +f 264//268 279//276 280//278 +f 258//271 257//269 272//277 +f 258//271 273//279 274//281 +f 251//272 266//280 267//282 +f 260//260 259//258 274//281 +f 252//259 267//282 268//284 +f 260//260 275//283 276//285 +f 253//261 268//284 269//286 +f 261//262 276//285 277//273 +f 255//265 254//263 269//286 +f 275//283 274//281 289//288 +f 267//282 282//302 283//290 +f 275//283 290//289 291//291 +f 268//284 283//290 284//292 +f 276//285 291//291 292//293 +f 270//287 269//286 284//292 +f 278//274 277//273 292//293 +f 271//275 270//287 285//294 +f 278//274 293//295 294//297 +f 272//277 271//275 286//296 +f 280//278 279//276 294//297 +f 273//279 272//277 287//298 +f 273//279 288//300 289//288 +f 266//280 281//301 282//302 +f 293//295 308//317 309//303 +f 287//298 286//296 301//304 +f 294//297 309//303 310//306 +f 288//300 287//298 302//305 +f 288//300 303//307 304//309 +f 281//301 296//308 297//310 +f 290//289 289//288 304//309 +f 282//302 297//310 298//312 +f 290//289 305//311 306//313 +f 283//290 298//312 299//314 +f 291//291 306//313 307//315 +f 284//292 299//314 300//316 +f 293//295 292//293 307//315 +f 286//296 285//294 300//316 +f 298//312 297//310 312//318 +f 305//311 320//332 321//320 +f 298//312 313//319 314//321 +f 306//313 321//320 322//322 +f 299//314 314//321 315//323 +f 308//317 307//315 322//322 +f 301//304 300//316 315//323 +f 309//303 308//317 323//324 +f 302//305 301//304 316//325 +f 309//303 324//326 325//328 +f 303//307 302//305 317//327 +f 303//307 318//329 319//331 +f 297//310 296//308 311//330 +f 305//311 304//309 319//331 +f 317//327 316//325 332//333 +f 324//326 340//347 341//335 +f 318//329 317//327 333//334 +f 318//329 334//336 335//338 +f 311//330 327//337 328//339 +f 320//332 319//331 335//338 +f 312//318 328//339 329//341 +f 320//332 336//340 337//342 +f 313//319 329//341 330//343 +f 321//320 337//342 338//344 +f 314//321 330//343 331//345 +f 323//324 322//322 338//344 +f 316//325 315//323 331//345 +f 323//324 339//346 340//347 +f 336//340 351//361 352//348 +f 329//341 344//362 345//349 +f 337//342 352//348 353//350 +f 330//343 345//349 346//351 +f 338//344 353//350 354//352 +f 332//333 331//345 346//351 +f 339//346 354//352 355//354 +f 333//334 332//333 347//353 +f 341//335 340//347 355//354 +f 334//336 333//334 348//355 +f 334//336 349//357 350//359 +f 327//337 342//358 343//360 +f 336//340 335//338 350//359 +f 328//339 343//360 344//362 +f 356//356 355//354 370//363 +f 349//357 348//355 363//365 +f 349//357 364//366 365//368 +f 342//358 357//367 358//369 +f 351//361 350//359 365//368 +f 343//360 358//369 359//371 +f 351//361 366//370 367//372 +f 344//362 359//371 360//373 +f 352//348 367//372 368//374 +f 346//351 345//349 360//373 +f 354//352 353//350 368//374 +f 347//353 346//351 361//375 +f 355//354 354//352 369//376 +f 348//355 347//353 362//377 +f 359//371 374//392 375//378 +f 368//374 367//372 382//379 +f 360//373 375//378 376//381 +f 369//376 368//374 383//380 +f 362//377 361//375 376//381 +f 370//363 369//376 384//382 +f 363//365 362//377 377//383 +f 371//364 370//363 385//384 +f 364//366 363//365 378//385 +f 364//366 379//387 380//389 +f 357//367 372//388 373//390 +f 366//370 365//368 380//389 +f 358//369 373//390 374//392 +f 366//370 381//391 382//379 +f 379//387 378//385 393//393 +f 379//387 394//394 395//397 +f 372//388 387//395 388//398 +f 381//391 380//389 395//397 +f 373//390 388//398 389//400 +f 381//391 396//399 397//401 +f 374//392 389//400 390//402 +f 382//379 397//401 398//403 +f 375//378 390//402 391//404 +f 384//382 383//380 398//403 +f 377//383 376//381 391//404 +f 384//382 399//405 400//407 +f 378//385 377//383 392//406 +f 385//384 400//407 401//396 +f 397//401 412//422 413//408 +f 391//404 390//402 405//409 +f 399//405 398//403 413//408 +f 392//406 391//404 406//410 +f 400//407 399//405 414//411 +f 393//393 392//406 407//412 +f 400//407 415//413 416//415 +f 394//394 393//393 408//414 +f 394//394 409//416 410//418 +f 387//395 402//417 403//419 +f 396//399 395//397 410//418 +f 388//398 403//419 404//421 +f 396//399 411//420 412//422 +f 389//400 404//421 405//409 +f 409//416 424//436 425//424 +f 402//417 417//437 418//425 +f 410//418 425//424 426//426 +f 403//419 418//425 419//427 +f 411//420 426//426 427//428 +f 404//421 419//427 420//429 +f 412//422 427//428 428//430 +f 405//409 420//429 421//431 +f 414//411 413//408 428//430 +f 407//412 406//410 421//431 +f 414//411 429//432 430//434 +f 408//414 407//412 422//433 +f 416//415 415//413 430//434 +f 409//416 408//414 423//435 +f 429//432 428//430 443//438 +f 422//433 421//431 436//440 +f 429//432 444//439 445//442 +f 423//435 422//433 437//441 +f 431//423 430//434 445//442 +f 424//436 423//435 438//443 +f 424//436 439//445 440//447 +f 417//437 432//446 433//448 +f 425//424 440//447 441//449 +f 419//427 418//425 433//448 +f 426//426 441//449 442//451 +f 419//427 434//450 435//452 +f 427//428 442//451 443//438 +f 420//429 435//452 436//440 +f 432//446 447//466 448//453 +f 440//447 455//467 456//454 +f 433//448 448//453 449//455 +f 441//449 456//454 457//456 +f 434//450 449//455 450//457 +f 442//451 457//456 458//458 +f 436//440 435//452 450//457 +f 444//439 443//438 458//458 +f 437//441 436//440 451//459 +f 444//439 459//460 460//462 +f 438//443 437//441 452//461 +f 445//442 460//462 461//464 +f 439//445 438//443 453//463 +f 439//445 454//465 455//467 +f 452//461 451//459 466//468 +f 459//460 474//482 475//470 +f 453//463 452//461 467//469 +f 460//462 475//470 476//472 +f 454//465 453//463 468//471 +f 454//465 469//473 470//475 +f 447//466 462//474 463//476 +f 455//467 470//475 471//477 +f 448//453 463//476 464//478 +f 456//454 471//477 472//479 +f 449//455 464//478 465//480 +f 457//456 472//479 473//481 +f 450//457 465//480 466//468 +f 459//460 458//458 473//481 +f 470//475 478//4 479//6 +f 464//478 463//476 2//3 +f 471//477 479//6 8//10 +f 465//480 464//478 3//8 +f 472//479 8//10 9//13 +f 466//468 465//480 4//12 +f 473//481 9//13 10//18 +f 467//469 466//468 5//16 +f 474//482 10//18 480//22 +f 468//471 467//469 6//20 +f 475//470 480//22 481//26 +f 469//473 468//471 7//24 +f 469//473 477//27 478//4 +f 463//476 462//474 1//1