|
|
@@ -20,70 +20,73 @@
|
|
|
|
|
|
namespace math { namespace matrix {
|
|
|
template <typename, size_t, size_t> class matrix;
|
|
|
-} }
|
|
|
+}}
|
|
|
|
|
|
namespace math { namespace vector {
|
|
|
-#define VECTOR_ENABLE_IF_LT_N(index, expr) \
|
|
|
-template <bool _ = true> \
|
|
|
-typename std::enable_if<std::size_t(index) < N && _, expr>::type
|
|
|
-
|
|
|
-#define VECTOR_ENABLE_IF_EQ_N(index, t, n) \
|
|
|
-template <bool _ = true> \
|
|
|
-typename std::enable_if<std::size_t(index) == N && _, vector<t, n> >::type
|
|
|
-
|
|
|
-#define VECTOR_ENABLE_IF_EQ_T(_type, t, n) \
|
|
|
-typename std::enable_if<std::is_same<_type, t>::value, vector<t, n> >::type
|
|
|
-
|
|
|
-#define VECTOR_DISABLE_IF_VECTOR(_type, t, n) \
|
|
|
-typename std::enable_if<!is_vector<_type>::value, vector<t, n> >::type
|
|
|
-
|
|
|
-#define VECTOR_ACCESS_FN(name, i) \
|
|
|
-VECTOR_ENABLE_IF_LT_N(i, value_type const &) name() const { return _data[i]; } \
|
|
|
-VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
|
|
|
-
|
|
|
-#define VECTOR_FOR_EACH_RANGE(var, end) for (std::size_t var = 0; var < end; ++var)
|
|
|
+#define VECTOR_ENABLE_IF_LT_N(index, expr) \
|
|
|
+ template <bool _ = true> \
|
|
|
+ typename std::enable_if<std::size_t(index) < N && _, expr>::type
|
|
|
+
|
|
|
+#define VECTOR_ENABLE_IF_EQ_N(index, t, n) \
|
|
|
+ template <bool _ = true> \
|
|
|
+ typename std::enable_if<std::size_t(index) == N && _, vector<t, n>>::type
|
|
|
+
|
|
|
+#define VECTOR_ENABLE_IF_EQ_T(_type, t, n) \
|
|
|
+ typename std::enable_if<std::is_same<_type, t>::value, vector<t, n>>::type
|
|
|
+
|
|
|
+#define VECTOR_DISABLE_IF_VECTOR(_type, t, n) \
|
|
|
+ typename std::enable_if<!is_vector<_type>::value, vector<t, n>>::type
|
|
|
+
|
|
|
+#define VECTOR_ACCESS_FN(name, i) \
|
|
|
+ VECTOR_ENABLE_IF_LT_N(i, value_type const &) name() const { \
|
|
|
+ return _data[i]; \
|
|
|
+ } \
|
|
|
+ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
|
|
|
+
|
|
|
+#define VECTOR_FOR_EACH_RANGE(var, end) \
|
|
|
+ for (std::size_t var = 0; var < end; ++var)
|
|
|
#define VECTOR_FOR_EACH(var) VECTOR_FOR_EACH_RANGE(var, N)
|
|
|
-
|
|
|
- struct {} fill;
|
|
|
+
|
|
|
+ struct {
|
|
|
+ } fill;
|
|
|
using fill_t = decltype(fill);
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- struct is_vector { static const constexpr bool value = false; };
|
|
|
-
|
|
|
- template <typename T, std::size_t N>
|
|
|
- class vector;
|
|
|
- template <typename T, std::size_t N>
|
|
|
- struct is_vector<vector<T, N>> { static const constexpr bool value = true; };
|
|
|
+
|
|
|
+ template <typename T> struct is_vector {
|
|
|
+ static const constexpr bool value = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename T, std::size_t N> class vector;
|
|
|
+ template <typename T, std::size_t N> struct is_vector<vector<T, N>> {
|
|
|
+ static const constexpr bool value = true;
|
|
|
+ };
|
|
|
template <typename T, std::size_t R, std::size_t C>
|
|
|
- struct is_vector<matrix::matrix<T, R, C>> { static const constexpr bool value = true; };
|
|
|
-
|
|
|
- template <typename T, std::size_t N>
|
|
|
- class vector {
|
|
|
+ struct is_vector<matrix::matrix<T, R, C>> {
|
|
|
+ static const constexpr bool value = true;
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename T, std::size_t N> class vector {
|
|
|
public:
|
|
|
using value_type = T;
|
|
|
+
|
|
|
private:
|
|
|
using mag_t = decltype(std::sqrt(std::declval<T>()));
|
|
|
template <typename M>
|
|
|
- using mul_t = decltype(std::declval<T>()*std::declval<M>());
|
|
|
+ using mul_t = decltype(std::declval<T>() * std::declval<M>());
|
|
|
template <typename M>
|
|
|
- using div_t = decltype(std::declval<T>()/std::declval<M>());
|
|
|
+ using div_t = decltype(std::declval<T>() / std::declval<M>());
|
|
|
+
|
|
|
public:
|
|
|
-
|
|
|
// Constructors
|
|
|
vector() = default;
|
|
|
-
|
|
|
+
|
|
|
vector(std::array<T, N> const & init) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
|
|
|
}
|
|
|
-
|
|
|
- vector(vector const & other) {
|
|
|
- *this = other;
|
|
|
- }
|
|
|
-
|
|
|
- vector(vector && other) {
|
|
|
- *this = std::move(other);
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
+ vector(vector const & other) { *this = other; }
|
|
|
+
|
|
|
+ vector(vector && other) { *this = std::move(other); }
|
|
|
+
|
|
|
// Conversion
|
|
|
template <typename T2, std::size_t N2>
|
|
|
explicit vector(vector<T2, N2> const & other) {
|
|
|
@@ -91,188 +94,181 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
|
|
|
_data[i] = static_cast<T>(other[i]);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector(T const & v, fill_t) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] = v; }
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Assignment
|
|
|
- vector& operator=(vector const & other) {
|
|
|
+ vector & operator=(vector const & other) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] = other[i]; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
- vector& operator=(vector && other) {
|
|
|
+
|
|
|
+ vector & operator=(vector && other) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] = std::move(other._data[i]); }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Named Accessors
|
|
|
// - Numeric Vector Accessors
|
|
|
VECTOR_ACCESS_FN(x, 0)
|
|
|
VECTOR_ACCESS_FN(y, 1)
|
|
|
VECTOR_ACCESS_FN(z, 2)
|
|
|
VECTOR_ACCESS_FN(w, 3)
|
|
|
-
|
|
|
+
|
|
|
// - Color Vector Accessors
|
|
|
VECTOR_ACCESS_FN(r, 0)
|
|
|
VECTOR_ACCESS_FN(g, 1)
|
|
|
VECTOR_ACCESS_FN(b, 2)
|
|
|
VECTOR_ACCESS_FN(a, 3)
|
|
|
-
|
|
|
+
|
|
|
// Unnamed Accessors
|
|
|
- value_type const & operator[](std::size_t idx) const {
|
|
|
- return _data[idx];
|
|
|
- }
|
|
|
-
|
|
|
- value_type & operator[](std::size_t idx) {
|
|
|
- return _data[idx];
|
|
|
- }
|
|
|
-
|
|
|
+ value_type const & operator[](std::size_t idx) const { return _data[idx]; }
|
|
|
+
|
|
|
+ value_type & operator[](std::size_t idx) { return _data[idx]; }
|
|
|
+
|
|
|
value_type const & at(std::size_t idx) const {
|
|
|
expects(idx < N, std::out_of_range, "index out of range");
|
|
|
return _data[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
value_type & at(std::size_t idx) {
|
|
|
expects(idx < N, std::out_of_range, "index out of range");
|
|
|
return _data[idx];
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Mathematical Operations
|
|
|
- vector& operator+=(vector const & other) {
|
|
|
+ vector & operator+=(vector const & other) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] += other[i]; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
- vector& operator+=(T const & other) {
|
|
|
+
|
|
|
+ vector & operator+=(T const & other) {
|
|
|
return operator+=(vector(other, fill));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector operator+(vector const & other) const {
|
|
|
return vector{*this} += other;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector operator+(T const & other) const {
|
|
|
return operator+(vector(other, fill));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
friend vector operator+(T const & lhs, vector const & rhs) {
|
|
|
return rhs + lhs;
|
|
|
}
|
|
|
-
|
|
|
- vector& operator-=(vector const & other) {
|
|
|
+
|
|
|
+ vector & operator-=(vector const & other) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] -= other[i]; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
- vector& operator-=(T const & other) {
|
|
|
+
|
|
|
+ vector & operator-=(T const & other) {
|
|
|
return operator-=(vector(other, fill));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector operator-(vector const & other) const {
|
|
|
return vector{*this} -= other;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector operator-(T const & other) const {
|
|
|
return operator-(vector(other, fill));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
friend vector operator-(T const & lhs, vector const & rhs) {
|
|
|
return vector(lhs, fill) - rhs;
|
|
|
}
|
|
|
-
|
|
|
- vector operator-() const {
|
|
|
- return vector{} -= *this;
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
+ vector operator-() const { return vector{} -= *this; }
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(M c) {
|
|
|
+ VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(M c) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] *= c; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N) operator*(M c) const {
|
|
|
+ VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
|
|
|
+ operator*(M c) const {
|
|
|
return vector<mul_t<M>, N>{*this} *= c;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N) operator*(M c, vector<T, N> const & v) {
|
|
|
+ friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
|
|
|
+ operator*(M c, vector<T, N> const & v) {
|
|
|
return v * c;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(vector<M, N> c) {
|
|
|
+ VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(vector<M, N> c) {
|
|
|
VECTOR_FOR_EACH(i) { _data[i] *= c[i]; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
|
|
|
return vector<mul_t<M>, N>{*this} *= other;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(M c) {
|
|
|
+ VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(M c) {
|
|
|
expects(c != 0, std::domain_error, "divide by zero");
|
|
|
VECTOR_FOR_EACH(i) { _data[i] /= c; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N) operator/(M c) const {
|
|
|
+ VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N)
|
|
|
+ operator/(M c) const {
|
|
|
return vector<div_t<M>, N>{*this} /= c;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
- VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(vector<M, N> c) {
|
|
|
- VECTOR_FOR_EACH(i) { expects(c[i] != 0, std::domain_error, "divide by zero"); }
|
|
|
+ VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N) & operator/=(vector<M, N> c) {
|
|
|
+ VECTOR_FOR_EACH(i) {
|
|
|
+ expects(c[i] != 0, std::domain_error, "divide by zero");
|
|
|
+ }
|
|
|
VECTOR_FOR_EACH(i) { _data[i] /= c[i]; }
|
|
|
return *this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename M>
|
|
|
vector<div_t<M>, N> operator/(vector<M, N> const & other) const {
|
|
|
return vector<div_t<M>, N>{*this} /= other;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Vector Operations
|
|
|
value_type dot(vector const & other) const {
|
|
|
value_type accum{};
|
|
|
VECTOR_FOR_EACH(i) { accum += at(i) * other.at(i); }
|
|
|
return accum;
|
|
|
}
|
|
|
-
|
|
|
- mag_t magnitude() const {
|
|
|
- return std::sqrt(dot(*this));
|
|
|
- }
|
|
|
-
|
|
|
- vector<mag_t, N> unit() const {
|
|
|
- return *this / magnitude();
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
+ mag_t magnitude() const { return std::sqrt(dot(*this)); }
|
|
|
+
|
|
|
+ vector<mag_t, N> unit() const { return *this / magnitude(); }
|
|
|
+
|
|
|
VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
|
|
|
- return {{
|
|
|
- y()*other.z() - z()*other.y(),
|
|
|
- z()*other.x() - x()*other.z(),
|
|
|
- x()*other.y() - y()*other.x()
|
|
|
- }};
|
|
|
+ return {{y() * other.z() - z() * other.y(),
|
|
|
+ z() * other.x() - x() * other.z(),
|
|
|
+ x() * other.y() - y() * other.x()}};
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
|
|
|
- return {{ 0, 0, x()*other.y() - y()*other.x() }};
|
|
|
+ return {{0, 0, x() * other.y() - y() * other.x()}};
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
vector<mag_t, N> projection(vector const & other) const {
|
|
|
vector<mag_t, N> b_p = other.unit();
|
|
|
return b_p * vector<mag_t, N>{*this}.dot(b_p);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private:
|
|
|
value_type _data[N] = {value_type()};
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
template <typename T, std::size_t N>
|
|
|
vector<T, N> abs(vector<T, N> const & self) {
|
|
|
vector<T, N> tmp(self);
|
|
|
@@ -280,34 +276,49 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
|
|
|
VECTOR_FOR_EACH(i) { tmp[i] = abs(tmp[i]); }
|
|
|
return tmp;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename T, std::size_t N>
|
|
|
int compare(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
VECTOR_FOR_EACH(i) {
|
|
|
- if (lhs[i] < rhs[i]) return -1;
|
|
|
- else if (lhs[i] > rhs[i]) return 1;
|
|
|
+ if (lhs[i] < rhs[i])
|
|
|
+ return -1;
|
|
|
+ else if (lhs[i] > rhs[i])
|
|
|
+ return 1;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator==(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) == 0; }
|
|
|
+ bool operator==(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) == 0;
|
|
|
+ }
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator!=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) != 0; }
|
|
|
+ bool operator!=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) != 0;
|
|
|
+ }
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator< (vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) < 0; }
|
|
|
+ bool operator<(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) < 0;
|
|
|
+ }
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator<=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) <= 0; }
|
|
|
+ bool operator<=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) <= 0;
|
|
|
+ }
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator> (vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) > 0; }
|
|
|
+ bool operator>(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) > 0;
|
|
|
+ }
|
|
|
template <typename T, std::size_t N>
|
|
|
- bool operator>=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) >= 0; }
|
|
|
-} }
|
|
|
+ bool operator>=(vector<T, N> const & lhs, vector<T, N> const & rhs) {
|
|
|
+ return compare(lhs, rhs) >= 0;
|
|
|
+ }
|
|
|
+}}
|
|
|
|
|
|
template <typename... Ts>
|
|
|
-auto make_vector(Ts && ...elems) -> math::vector::vector<typename std::common_type<Ts...>::type, sizeof...(Ts)> {
|
|
|
+auto make_vector(Ts &&... elems)
|
|
|
+ -> math::vector::vector<typename std::common_type<Ts...>::type,
|
|
|
+ sizeof...(Ts)> {
|
|
|
return {{elems...}};
|
|
|
}
|
|
|
|
|
|
-
|
|
|
using math::vector::abs;
|