From e624d81e54ae481383afbd772bf87850bf75f2d7 Mon Sep 17 00:00:00 2001
From: Nao Pross <naopross@thearcway.org>
Date: Fri, 22 Feb 2019 23:08:15 +0100
Subject: Undo directory structure change

---
 include/mm/mmmatrix.hpp |  59 ----------
 include/mm/mmvec.hpp    | 308 ------------------------------------------------
 include/mmmatrix.hpp    |  59 ++++++++++
 include/mmvec.hpp       | 308 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 367 insertions(+), 367 deletions(-)
 delete mode 100644 include/mm/mmmatrix.hpp
 delete mode 100644 include/mm/mmvec.hpp
 create mode 100644 include/mmmatrix.hpp
 create mode 100644 include/mmvec.hpp

(limited to 'include')

diff --git a/include/mm/mmmatrix.hpp b/include/mm/mmmatrix.hpp
deleted file mode 100644
index 7934d87..0000000
--- a/include/mm/mmmatrix.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/* mmmatrix.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 matrices can contain any data type.
- *
- * As a challenge, the matrix 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 possibly the allocator.
- *
- * Naoki Pross <naopross@thearcway.org>
- * 2018 ~ 2019
- */
-#pragma once
-
-#include <cmath>
-#include <array>
-
-namespace mm {
-    template<typename T, std::size_t Rows, std::size_t Cols>
-    class basic_matrix;
-}
-
-template<typename T, std::size_t Rows, std::size_t Cols>
-class mm::basic_matrix {
-public:
-    using type = T;
-
-    static constexpr std::size_t rows = Rows;
-    static constexpr std::size_t cols = Cols;
-
-    basic_matrix() {}
-
-    template<std::size_t Rows_, std::size_t Cols_>
-    basic_matrix(const basic_matrix<T, Rows_, Cols_>& other);
-
-    const T& at(std::size_t row, std::size_t col);
-
-private:
-    std::array<T, (Rows * Cols)> data;
-};
-
-
-
-template<typename T, std::size_t Rows, std::size_t Cols>
-template<std::size_t ORows, std::size_t OCols>
-mm::basic_matrix<T, Rows, Cols>::basic_matrix(const basic_matrix<T, ORows, OCols>& other) {
-    static_assert((ORows <= Rows),
-        "cannot copy a taller matrix into a smaller one"
-    );
-
-    static_assert((OCols <= Cols),
-        "cannot copy a larger matrix into a smaller one"
-    );
-
-    std::copy(std::begin(other.data), std::end(other.data), data.begin());
-}
diff --git a/include/mm/mmvec.hpp b/include/mm/mmvec.hpp
deleted file mode 100644
index 4bac658..0000000
--- a/include/mm/mmvec.hpp
+++ /dev/null
@@ -1,308 +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);
-    template<std::size_t n> basic_vec(const basic_vec<T, n>& other);
-
-    T length() const;
-
-    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);
-
-    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) {
-    // construct with empty values
-    basic_vec();
-
-    // 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) {
-    // construct with empty values
-    basic_vec();
-    // uses operator=
-    *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+=(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/mmmatrix.hpp b/include/mmmatrix.hpp
new file mode 100644
index 0000000..7934d87
--- /dev/null
+++ b/include/mmmatrix.hpp
@@ -0,0 +1,59 @@
+/* mmmatrix.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 matrices can contain any data type.
+ *
+ * As a challenge, the matrix 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 possibly the allocator.
+ *
+ * Naoki Pross <naopross@thearcway.org>
+ * 2018 ~ 2019
+ */
+#pragma once
+
+#include <cmath>
+#include <array>
+
+namespace mm {
+    template<typename T, std::size_t Rows, std::size_t Cols>
+    class basic_matrix;
+}
+
+template<typename T, std::size_t Rows, std::size_t Cols>
+class mm::basic_matrix {
+public:
+    using type = T;
+
+    static constexpr std::size_t rows = Rows;
+    static constexpr std::size_t cols = Cols;
+
+    basic_matrix() {}
+
+    template<std::size_t Rows_, std::size_t Cols_>
+    basic_matrix(const basic_matrix<T, Rows_, Cols_>& other);
+
+    const T& at(std::size_t row, std::size_t col);
+
+private:
+    std::array<T, (Rows * Cols)> data;
+};
+
+
+
+template<typename T, std::size_t Rows, std::size_t Cols>
+template<std::size_t ORows, std::size_t OCols>
+mm::basic_matrix<T, Rows, Cols>::basic_matrix(const basic_matrix<T, ORows, OCols>& other) {
+    static_assert((ORows <= Rows),
+        "cannot copy a taller matrix into a smaller one"
+    );
+
+    static_assert((OCols <= Cols),
+        "cannot copy a larger matrix into a smaller one"
+    );
+
+    std::copy(std::begin(other.data), std::end(other.data), data.begin());
+}
diff --git a/include/mmvec.hpp b/include/mmvec.hpp
new file mode 100644
index 0000000..4bac658
--- /dev/null
+++ b/include/mmvec.hpp
@@ -0,0 +1,308 @@
+/* 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);
+    template<std::size_t n> basic_vec(const basic_vec<T, n>& other);
+
+    T length() const;
+
+    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);
+
+    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) {
+    // construct with empty values
+    basic_vec();
+
+    // 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) {
+    // construct with empty values
+    basic_vec();
+    // uses operator=
+    *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+=(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