From 94d90dd045463a540fe14880b1c04e2ce44a1efe Mon Sep 17 00:00:00 2001
From: ancarola <raffaele.ancarola@epfl.ch>
Date: Mon, 11 Feb 2019 12:48:58 +0100
Subject: CMakeLists: include fixes, include tree structure modified

---
 .gitignore              |   1 +
 CMakeLists.txt          |  14 +-
 cmake/MMConfig.cmake.in |   2 +-
 include/mm              |  11 ++
 include/mm.hpp          |  11 --
 include/mm/mmvec.hpp    | 330 ------------------------------------------------
 include/mmvec.hpp       | 330 ++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 356 insertions(+), 343 deletions(-)
 create mode 100644 include/mm
 delete mode 100644 include/mm.hpp
 delete mode 100644 include/mm/mmvec.hpp
 create mode 100644 include/mmvec.hpp

diff --git a/.gitignore b/.gitignore
index ac480cc..3779814 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 build
 .ninja*
+CMakeFiles
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c31e16b..6e7d073 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,8 +63,20 @@ install(TARGETS mm
 
 set_target_properties(mm PROPERTIES EXPORT_NAME MM)
 
+
+if ("${CMAKE_SYSTEM}" MATCHES "Linux")
+
+# too bad but no other simpler choise
+file(GLOB INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
+
 # install public headers
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+install(FILES ${INCLUDE_FILES}
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mm
+)
+
+endif()
+        
+# TODO, install setup for windows too
 
 # export targets
 install(EXPORT mm-targets
diff --git a/cmake/MMConfig.cmake.in b/cmake/MMConfig.cmake.in
index c338eae..b2857ae 100644
--- a/cmake/MMConfig.cmake.in
+++ b/cmake/MMConfig.cmake.in
@@ -1,6 +1,6 @@
 get_filename_component(MM_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
 
-list(REMOVE_AT CMAKE_MODULE_PATH -1)
+#list(REMOVE_AT CMAKE_MODULE_PATH -1)
 
 if (NOT TARGET MM::MM)
     include("${MM_CMAKE_DIR}/MMTargets.cmake")
diff --git a/include/mm b/include/mm
new file mode 100644
index 0000000..7e9f02b
--- /dev/null
+++ b/include/mm
@@ -0,0 +1,11 @@
+#pragma once
+
+/* MiniMath
+ * A mathematical vector library that (ab)uses modern C++ abstraction features.
+ * This header includes the entire library.
+ *
+ * Warning: having (ab)used a lot of templated code it is not recommended to
+ *          include everything as it may slow down the compiler.
+ */
+
+#include "mm/mmvec.hpp"
diff --git a/include/mm.hpp b/include/mm.hpp
deleted file mode 100644
index 7e9f02b..0000000
--- a/include/mm.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-/* MiniMath
- * A mathematical vector library that (ab)uses modern C++ abstraction features.
- * This header includes the entire library.
- *
- * Warning: having (ab)used a lot of templated code it is not recommended to
- *          include everything as it may slow down the compiler.
- */
-
-#include "mm/mmvec.hpp"
diff --git a/include/mm/mmvec.hpp b/include/mm/mmvec.hpp
deleted file mode 100644
index db3c390..0000000
--- a/include/mm/mmvec.hpp
+++ /dev/null
@@ -1,330 +0,0 @@
-/* mmvec.hpp
- * Part of Mathematical library built (ab)using Modern C++ 17 abstractions.
- *
- * This library is not intended to be _performant_, it does not contain
- * hand written SMID / SSE / AVX optimizations. It is instead an example
- * of highly abstracted code, where Vectors can contain any data type.
- *
- * As a challenge, the vector data structure has been built on a container
- * of static capacity. But if a dynamic base container is needed, the code
- * should be easily modifiable to add further abstraction, by templating
- * the container, and by consequence the allocator.
- *
- * Naoki Pross <naopross@thearcway.org>
- * 2018 ~ 2019
- */
-#pragma once
-
-#include <cassert>
-#include <cmath>
-
-#include <iostream>
-#include <array>
-#include <algorithm>
-#include <numeric>
-#include <complex>
-#include <initializer_list>
-
-namespace mm {
-    // generic implementation
-    template<typename T, std::size_t d>
-    struct basic_vec;
-
-    // usable specializations
-    template<typename T, std::size_t d>
-    struct vec;
-    template<typename T>
-    struct vec3;
-    template<typename T>
-    struct vec2;
-}
-
-template<typename T, std::size_t d>
-struct mm::basic_vec : public std::array<T, d> {
-    using type = T;
-    static constexpr std::size_t dimensions = d;
-
-    // TODO: template away these
-    static constexpr T null_element = static_cast<T>(0);
-    static constexpr T unit_element = static_cast<T>(1);
-    static constexpr T unit_additive_inverse_element = static_cast<T>(-1);
-
-    basic_vec();
-    basic_vec(const std::initializer_list<T> l);
-
-    // copyable to a vector of size n <= d
-    template<std::size_t n> basic_vec(const basic_vec<T, n>& other);
-    // movable to a vector of size n <= d
-    template<std::size_t n> basic_vec(basic_vec<T, n>&& other);
-
-    T length() const;
-
-    // copy operator=
-    template<std::size_t n>
-    basic_vec<T, d>& operator=(const mm::basic_vec<T, n>& other);
-
-    // move operator=
-    template<std::size_t n>
-    basic_vec<T, d>& operator=(mm::basic_vec<T, n>&& other);
-
-    template<std::size_t n>
-    basic_vec<T, d>& operator+=(const mm::basic_vec<T, n>& other);
-
-    template<std::size_t n>
-    basic_vec<T, d>& operator-=(const mm::basic_vec<T, n>& other);
-
-
-    basic_vec<T, d>& operator*=(const T& scalar);
-};
-
-
-// member functions for basic_vec
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d>::basic_vec() : std::array<T, d>() {
-    this->fill(basic_vec<T, d>::null_element);
-}
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d>::basic_vec(const std::initializer_list<T> l) {
-    // why can't this sh*t be a constexpr with static_assert???
-    assert(l.size() <= d);
-    std::copy(l.begin(), l.end(), this->begin());
-}
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>::basic_vec(const mm::basic_vec<T, n>& other) {
-    *this = other;
-}
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>::basic_vec(basic_vec<T, n>&& other) {
-    *this = other;
-}
-
-template<typename T, std::size_t d>
-T mm::basic_vec<T, d>::length() const {
-    return std::sqrt(std::accumulate(this->begin(), this->end(),
-        basic_vec<T, d>::null_element,
-        [](const T& init, const T& val) -> T {
-            return init + val * val;
-        }
-    ));
-}
-
-
-// memeber operator overloads for basic_vec
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator=(const mm::basic_vec<T, n>& other) {
-    static_assert(
-        d >= n, "cannot copy higher dimensional vector into a smaller one"
-    );
-
-    std::copy(other.begin(), other.end(), this->begin());
-
-    return *this;
-}
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator=(mm::basic_vec<T, n>&& other) {
-    static_assert(
-        d >= n, "cannot move a higher dimensional vector into a smaller one"
-    );
-
-    std::move(other.begin(), other.end(), this->begin());
-
-    return *this;
-}
-
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator+=(const mm::basic_vec<T, n>& other) {
-    *this = *this + other;
-    return *this;
-}
-
-template<typename T, std::size_t d>
-template<std::size_t n>
-mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator-=(const mm::basic_vec<T, n>& other) {
-    *this = *this - other;
-    return *this;
-}
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator*=(const T& scalar) {
-    *this = *this * scalar;
-    return *this;
-}
-
-
-// operator overloads for basic_vec
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d> operator+(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
-    mm::basic_vec<T, d> out;
-    
-    std::transform(rhs.begin(), rhs.end(), lhs.begin(), out.begin(),
-        [](const T& r, const T& l) -> T {
-            return r + l;
-        }
-    );
-
-    return out;
-}
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d> operator*(const mm::basic_vec<T, d>& rhs, const T& lhs) {
-    return lhs * rhs;
-}
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d> operator*(const T& rhs, const mm::basic_vec<T, d>& lhs) {
-    mm::basic_vec<T, d> out;
-
-    std::transform(lhs.begin(), lhs.end(), out.begin(), 
-        [rhs](const T& t) -> T {
-            return t * rhs;
-    });
-
-    return out;
-}
-
-template<typename T, std::size_t d>
-mm::basic_vec<T, d> operator-(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
-    return rhs + mm::basic_vec<T, d>::unit_additive_inverse_element * lhs;
-}
-
-template<typename T, std::size_t d>
-T operator*(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
-    return std::inner_product(rhs.begin(), rhs.end(), lhs.begin(), 0);
-}
-
-template<typename T, std::size_t d>
-std::ostream& operator<<(std::ostream& os, const mm::basic_vec<T, d>& v) {
-    os << "<";
-    std::for_each(v.begin(), v.end() -1, [&](const T& el) {
-        os << el << ", ";
-    });
-    os << v.back() << ">";
-
-    return os;
-}
-
-
-// actual vectors to use in your code
-
-template<typename T, std::size_t d>
-class mm::vec: public mm::basic_vec<T, d> {
-public:
-    vec(std::initializer_list<T> l) : basic_vec<T, d>(l) {}
-
-    template<std::size_t n>
-    vec(const basic_vec<T, n>& other) : basic_vec<T, d>(other) {}
-};
-
-
-// three dimensional specialization with a static cross product
-// TODO: specialize operator+ for spherical coordinates
-
-template<typename T>
-class mm::vec3 : public mm::basic_vec<T, 3> {
-public:
-    vec3() : basic_vec<T, 3>() {}
-    vec3(std::initializer_list<T> l) : basic_vec<T, 3>(l) {}
-
-    template<std::size_t n>
-    vec3(const basic_vec<T, n>& other) : basic_vec<T, 3>(other) {}
-
-    T& x() { return this->at(0); }
-    T& y() { return this->at(1); }
-    T& z() { return this->at(2); }
-
-    const T& x() const { return this->at(0); }
-    const T& y() const { return this->at(1); }
-    const T& z() const { return this->at(2); }
-
-    T zenith() const;
-    T azimuth() const;
-    vec3<T> spherical() const;
-
-    static vec3<T> cross(const vec3<T>& rhs, const vec3<T>& lhs);
-};
-
-template<typename T>
-T mm::vec3<T>::zenith() const {
-    return std::acos(this->z() / this->length());
-}
-
-template<typename T>
-T mm::vec3<T>::azimuth() const {
-    return std::atan(this->y() / this->x());
-}
-
-template<typename T>
-mm::vec3<T> mm::vec3<T>::spherical() const {
-    return mm::vec3<T> {
-        this->length(),
-        this->zenith(),
-        this->azimuth(),
-    };
-}
-
-template<typename T>
-mm::vec3<T> mm::vec3<T>::cross(const vec3<T>& rhs, const vec3<T>& lhs) {
-    mm::vec3<T> res;
-
-    res.x() = (rhs.y() * lhs.z()) - (rhs.z() * lhs.y());
-    res.y() = (rhs.z() * lhs.x()) - (rhs.x() * lhs.z());
-    res.z() = (rhs.x() * lhs.y()) - (rhs.y() * lhs.x());
-
-    return res;
-}
-
-
-// two dimensional specialization with a polar conversion
-// TODO: specialize operator+ for polar coordinates
-
-template<typename T>
-class mm::vec2: public mm::basic_vec<T, 2> {
-public:
-    vec2() : basic_vec<T, 2>() {}
-    vec2(std::initializer_list<T> l) : basic_vec<T, 2>(l) {}
-
-    template<std::size_t n>
-    vec2(const basic_vec<T, n>& other) : basic_vec<T, 2>(other) {}
-
-    T& x() { return this->at(0); }
-    T& y() { return this->at(1); }
-
-    const T& x() const { return this->at(0); }
-    const T& y() const { return this->at(1); }
-
-    T angle() const;
-    vec2<T> polar() const;
-
-    static vec3<T> cross(const vec2<T>& rhs, const vec2<T>& lhs);
-};
-
-template<typename T>
-T mm::vec2<T>::angle() const {
-    return std::atan(this->y() / this->x());
-}
-
-template<typename T>
-mm::vec2<T> mm::vec2<T>::polar() const {
-    return mm::vec2 {
-        this->length(),
-        this->angle()
-    };
-}
-
-template<typename T>
-mm::vec3<T> mm::vec2<T>::cross(const mm::vec2<T>& rhs, const mm::vec2<T>& lhs) {
-    return mm::vec3<T>::cross(mm::vec3<T>(rhs), mm::vec3<T>(lhs));
-}
diff --git a/include/mmvec.hpp b/include/mmvec.hpp
new file mode 100644
index 0000000..db3c390
--- /dev/null
+++ b/include/mmvec.hpp
@@ -0,0 +1,330 @@
+/* mmvec.hpp
+ * Part of Mathematical library built (ab)using Modern C++ 17 abstractions.
+ *
+ * This library is not intended to be _performant_, it does not contain
+ * hand written SMID / SSE / AVX optimizations. It is instead an example
+ * of highly abstracted code, where Vectors can contain any data type.
+ *
+ * As a challenge, the vector data structure has been built on a container
+ * of static capacity. But if a dynamic base container is needed, the code
+ * should be easily modifiable to add further abstraction, by templating
+ * the container, and by consequence the allocator.
+ *
+ * Naoki Pross <naopross@thearcway.org>
+ * 2018 ~ 2019
+ */
+#pragma once
+
+#include <cassert>
+#include <cmath>
+
+#include <iostream>
+#include <array>
+#include <algorithm>
+#include <numeric>
+#include <complex>
+#include <initializer_list>
+
+namespace mm {
+    // generic implementation
+    template<typename T, std::size_t d>
+    struct basic_vec;
+
+    // usable specializations
+    template<typename T, std::size_t d>
+    struct vec;
+    template<typename T>
+    struct vec3;
+    template<typename T>
+    struct vec2;
+}
+
+template<typename T, std::size_t d>
+struct mm::basic_vec : public std::array<T, d> {
+    using type = T;
+    static constexpr std::size_t dimensions = d;
+
+    // TODO: template away these
+    static constexpr T null_element = static_cast<T>(0);
+    static constexpr T unit_element = static_cast<T>(1);
+    static constexpr T unit_additive_inverse_element = static_cast<T>(-1);
+
+    basic_vec();
+    basic_vec(const std::initializer_list<T> l);
+
+    // copyable to a vector of size n <= d
+    template<std::size_t n> basic_vec(const basic_vec<T, n>& other);
+    // movable to a vector of size n <= d
+    template<std::size_t n> basic_vec(basic_vec<T, n>&& other);
+
+    T length() const;
+
+    // copy operator=
+    template<std::size_t n>
+    basic_vec<T, d>& operator=(const mm::basic_vec<T, n>& other);
+
+    // move operator=
+    template<std::size_t n>
+    basic_vec<T, d>& operator=(mm::basic_vec<T, n>&& other);
+
+    template<std::size_t n>
+    basic_vec<T, d>& operator+=(const mm::basic_vec<T, n>& other);
+
+    template<std::size_t n>
+    basic_vec<T, d>& operator-=(const mm::basic_vec<T, n>& other);
+
+
+    basic_vec<T, d>& operator*=(const T& scalar);
+};
+
+
+// member functions for basic_vec
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d>::basic_vec() : std::array<T, d>() {
+    this->fill(basic_vec<T, d>::null_element);
+}
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d>::basic_vec(const std::initializer_list<T> l) {
+    // why can't this sh*t be a constexpr with static_assert???
+    assert(l.size() <= d);
+    std::copy(l.begin(), l.end(), this->begin());
+}
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>::basic_vec(const mm::basic_vec<T, n>& other) {
+    *this = other;
+}
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>::basic_vec(basic_vec<T, n>&& other) {
+    *this = other;
+}
+
+template<typename T, std::size_t d>
+T mm::basic_vec<T, d>::length() const {
+    return std::sqrt(std::accumulate(this->begin(), this->end(),
+        basic_vec<T, d>::null_element,
+        [](const T& init, const T& val) -> T {
+            return init + val * val;
+        }
+    ));
+}
+
+
+// memeber operator overloads for basic_vec
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator=(const mm::basic_vec<T, n>& other) {
+    static_assert(
+        d >= n, "cannot copy higher dimensional vector into a smaller one"
+    );
+
+    std::copy(other.begin(), other.end(), this->begin());
+
+    return *this;
+}
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator=(mm::basic_vec<T, n>&& other) {
+    static_assert(
+        d >= n, "cannot move a higher dimensional vector into a smaller one"
+    );
+
+    std::move(other.begin(), other.end(), this->begin());
+
+    return *this;
+}
+
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator+=(const mm::basic_vec<T, n>& other) {
+    *this = *this + other;
+    return *this;
+}
+
+template<typename T, std::size_t d>
+template<std::size_t n>
+mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator-=(const mm::basic_vec<T, n>& other) {
+    *this = *this - other;
+    return *this;
+}
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d>& mm::basic_vec<T, d>::operator*=(const T& scalar) {
+    *this = *this * scalar;
+    return *this;
+}
+
+
+// operator overloads for basic_vec
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d> operator+(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
+    mm::basic_vec<T, d> out;
+    
+    std::transform(rhs.begin(), rhs.end(), lhs.begin(), out.begin(),
+        [](const T& r, const T& l) -> T {
+            return r + l;
+        }
+    );
+
+    return out;
+}
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d> operator*(const mm::basic_vec<T, d>& rhs, const T& lhs) {
+    return lhs * rhs;
+}
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d> operator*(const T& rhs, const mm::basic_vec<T, d>& lhs) {
+    mm::basic_vec<T, d> out;
+
+    std::transform(lhs.begin(), lhs.end(), out.begin(), 
+        [rhs](const T& t) -> T {
+            return t * rhs;
+    });
+
+    return out;
+}
+
+template<typename T, std::size_t d>
+mm::basic_vec<T, d> operator-(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
+    return rhs + mm::basic_vec<T, d>::unit_additive_inverse_element * lhs;
+}
+
+template<typename T, std::size_t d>
+T operator*(const mm::basic_vec<T, d>& rhs, const mm::basic_vec<T, d>& lhs) {
+    return std::inner_product(rhs.begin(), rhs.end(), lhs.begin(), 0);
+}
+
+template<typename T, std::size_t d>
+std::ostream& operator<<(std::ostream& os, const mm::basic_vec<T, d>& v) {
+    os << "<";
+    std::for_each(v.begin(), v.end() -1, [&](const T& el) {
+        os << el << ", ";
+    });
+    os << v.back() << ">";
+
+    return os;
+}
+
+
+// actual vectors to use in your code
+
+template<typename T, std::size_t d>
+class mm::vec: public mm::basic_vec<T, d> {
+public:
+    vec(std::initializer_list<T> l) : basic_vec<T, d>(l) {}
+
+    template<std::size_t n>
+    vec(const basic_vec<T, n>& other) : basic_vec<T, d>(other) {}
+};
+
+
+// three dimensional specialization with a static cross product
+// TODO: specialize operator+ for spherical coordinates
+
+template<typename T>
+class mm::vec3 : public mm::basic_vec<T, 3> {
+public:
+    vec3() : basic_vec<T, 3>() {}
+    vec3(std::initializer_list<T> l) : basic_vec<T, 3>(l) {}
+
+    template<std::size_t n>
+    vec3(const basic_vec<T, n>& other) : basic_vec<T, 3>(other) {}
+
+    T& x() { return this->at(0); }
+    T& y() { return this->at(1); }
+    T& z() { return this->at(2); }
+
+    const T& x() const { return this->at(0); }
+    const T& y() const { return this->at(1); }
+    const T& z() const { return this->at(2); }
+
+    T zenith() const;
+    T azimuth() const;
+    vec3<T> spherical() const;
+
+    static vec3<T> cross(const vec3<T>& rhs, const vec3<T>& lhs);
+};
+
+template<typename T>
+T mm::vec3<T>::zenith() const {
+    return std::acos(this->z() / this->length());
+}
+
+template<typename T>
+T mm::vec3<T>::azimuth() const {
+    return std::atan(this->y() / this->x());
+}
+
+template<typename T>
+mm::vec3<T> mm::vec3<T>::spherical() const {
+    return mm::vec3<T> {
+        this->length(),
+        this->zenith(),
+        this->azimuth(),
+    };
+}
+
+template<typename T>
+mm::vec3<T> mm::vec3<T>::cross(const vec3<T>& rhs, const vec3<T>& lhs) {
+    mm::vec3<T> res;
+
+    res.x() = (rhs.y() * lhs.z()) - (rhs.z() * lhs.y());
+    res.y() = (rhs.z() * lhs.x()) - (rhs.x() * lhs.z());
+    res.z() = (rhs.x() * lhs.y()) - (rhs.y() * lhs.x());
+
+    return res;
+}
+
+
+// two dimensional specialization with a polar conversion
+// TODO: specialize operator+ for polar coordinates
+
+template<typename T>
+class mm::vec2: public mm::basic_vec<T, 2> {
+public:
+    vec2() : basic_vec<T, 2>() {}
+    vec2(std::initializer_list<T> l) : basic_vec<T, 2>(l) {}
+
+    template<std::size_t n>
+    vec2(const basic_vec<T, n>& other) : basic_vec<T, 2>(other) {}
+
+    T& x() { return this->at(0); }
+    T& y() { return this->at(1); }
+
+    const T& x() const { return this->at(0); }
+    const T& y() const { return this->at(1); }
+
+    T angle() const;
+    vec2<T> polar() const;
+
+    static vec3<T> cross(const vec2<T>& rhs, const vec2<T>& lhs);
+};
+
+template<typename T>
+T mm::vec2<T>::angle() const {
+    return std::atan(this->y() / this->x());
+}
+
+template<typename T>
+mm::vec2<T> mm::vec2<T>::polar() const {
+    return mm::vec2 {
+        this->length(),
+        this->angle()
+    };
+}
+
+template<typename T>
+mm::vec3<T> mm::vec2<T>::cross(const mm::vec2<T>& rhs, const mm::vec2<T>& lhs) {
+    return mm::vec3<T>::cross(mm::vec3<T>(rhs), mm::vec3<T>(lhs));
+}
-- 
cgit v1.2.1