hpr-cpp/source/hpr/math/vector.hpp

321 lines
11 KiB
C++

#pragma once
#include <hpr/numeric.hpp>
#include <hpr/container/static_array.hpp>
namespace hpr
{
// forward declarations
template <IsReal T, Size S> requires (S >= 0)
class Vector;
template <IsReal T, Size S>
using SubVector = typename std::conditional<S >= 2, Vector<T, S - 1>, Vector<T, 1>>::type;
// type traits
template <typename T>
struct is_vector : public std::false_type {};
template <typename T, Size S>
struct is_vector<Vector<T, S>> : public std::true_type {};
// concepts
template <typename T>
concept IsVector = is_vector<T>::value;
// aliases
template <typename Type, Size S>
using vec = Vector<Type, S>;
using vec2 = Vector<scalar, 2>;
using vec3 = Vector<scalar, 3>;
using vec4 = Vector<scalar, 4>;
template <IsReal Type, Size S> requires (S >= 0)
class Vector : public StaticArray<Type, S>
{
using base = StaticArray<Type, S>;
public:
using value_type = Type;
using size_type = Size;
using pointer = Type*;
using reference = Type&;
using iterator = Iterator<Type>;
using const_iterator = Iterator<const Type>;
public:
//! null constructor
constexpr
Vector() :
base {}
{}
//! copy constructor
constexpr
Vector(const Vector& vs) :
base {static_cast<base>(vs)}
{}
//! move constructor
constexpr
Vector(Vector&& vs) noexcept :
base {std::forward<base>(static_cast<base>(vs))}
{}
//! copy assignment operator
constexpr
Vector& operator=(const Vector& vs)
{
base::operator=(vs);
return *this;
}
//! move assignment operator
constexpr
Vector& operator=(Vector&& vs) noexcept
{
swap(*this, vs);
return *this;
}
//! destructor
virtual
~Vector() = default;
//! copy constructor from base
constexpr
Vector(const base& arr) :
base {arr}
{}
//! move constructor from base
constexpr
Vector(base&& arr) :
base {std::forward<base>(arr)}
{}
//! construct from iterators
constexpr
Vector(typename base::iterator start, typename base::iterator end) :
base {start, end}
{}
//! construct from constant iterators
constexpr
Vector(typename base::const_iterator start, typename base::const_iterator end) :
base {start, end}
{}
//! construct from initializer list
constexpr
Vector(std::initializer_list<value_type> list) :
base {list}
{}
//! copy constructor with variadic args
template <IsReal... Args>
constexpr
Vector(const value_type& v, const Args& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(args)...}
{}
//! move constructor with variadic args
template <IsReal... Args>
constexpr
Vector(value_type&& v, Args&& ...args) requires (S == 1 + sizeof...(args)):
base {v, static_cast<value_type>(std::forward<Args>(args))...}
{}
//! copy constructor with sub vector and value
constexpr
Vector(const SubVector<Type, S>& svs, const value_type& v) requires (S >= 1):
base {}
{
for (auto n = 0; n < svs.size(); ++n)
(*this)[n] = svs[n];
(*this)[svs.size()] = v;
}
//! copy constructor from greater vector
template <Size GS> requires (GS > S)
constexpr explicit
Vector(const Vector<Type, GS>& vs) :
base {vs.begin(), vs.begin() + S}
{}
};
// global operators
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs) { Vector<T, S> vs; for (Size n = 0; n < S; ++n) vs[n] = -lhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs[n]; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= rhs[n]; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= rhs[n]; return vs; }
template <IsReal T, Size S> inline bool operator==(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] != rhs[n]) return false; return true; }
template <IsReal T, Size S> inline bool operator!=(const Vector<T, S>& lhs, const Vector<T, S>& rhs) { for (Size n = 0; n < S; ++n) if (lhs[n] == rhs[n]) return false; return true; }
template <IsReal T, Size S> inline Vector<T, S>& operator+=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] += rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator-=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] -= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator*=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] *= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S>& operator/=(Vector<T, S>& lhs, const T& rhs) { for (Size n = 0; n < S; ++n) lhs[n] /= rhs; return lhs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] += rhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const Vector<T, S>& lhs, const T& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] -= rhs; return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator*(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] *= static_cast<T>(rhs); return vs; }
template <IsReal T, IsReal T2, Size S> inline Vector<T, S> operator/(const Vector<T, S>& lhs, const T2& rhs) { Vector<T, S> vs {lhs}; for (Size n = 0; n < S; ++n) vs[n] /= static_cast<T>(rhs); return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator+(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] += lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator-(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] -= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator*(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] *= lhs; return vs; }
template <IsReal T, Size S> inline Vector<T, S> operator/(const T& lhs, const Vector<T, S>& rhs) { Vector<T, S> vs {rhs}; for (Size n = 0; n < S; ++n) vs[n] /= lhs; return vs; }
// boolean operations
template <typename Type, Size S>
inline
Vector<bool, S> equal(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs, const scalar& precision = hpr::precision())
{
Vector<bool, S> vs;
for (auto n = 0; n < S; ++n)
vs[n] = equal(lhs[n], rhs[n], precision);
return vs;
}
template <Size S>
inline
bool any(const Vector<bool, S>& vs)
{
bool res = false;
for (auto e : vs)
res = res || e;
return res;
}
template <Size S>
inline
bool all(const Vector<bool, S>& vs)
{
bool res = true;
for (auto e : vs)
res = res && e;
return res;
}
// per element operations
template <typename Type, Size S>
inline
Vector<Type, S> abs(const Vector<Type, S>& vs)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = abs(vs[n]);
return res;
}
template <typename Type, Size S>
inline
Type sum(const Vector<Type, S>& vs)
{
Type sum {};
for (const Type& v : vs)
sum += v;
return sum;
}
template <typename Type, Size S>
inline
Vector<Type, S> pow(const Vector<Type, S>& vs, scalar degree)
{
Vector<Type, S> res;
for (auto n = 0; n < S; ++n)
res[n] = pow(vs[n], degree);
return res;
}
// vector operations
template <typename Type, Size S>
inline
Type norm(const Vector<Type, S>& vs)
{
return sqrt(sum(pow(abs(vs), 2)));
}
template <typename Type, Size S>
inline
Type dot(const Vector<Type, S>& lhs, const Vector<Type, S>& rhs)
{
return sum(lhs * rhs);
}
template <typename Type, Size S>
inline
Type length(const Vector<Type, S>& vs)
{
return sqrt(dot(vs, vs));
}
template <typename Type, Size S>
inline
Type mag(const Vector<Type, S>& vs)
{
return length(vs);
}
template <typename Type, Size S>
inline
Type distance(const Vector<Type, S>& vs1, const Vector<Type, S>& vs2)
{
return length(vs1 - vs2);
}
template <typename Type, Size S>
inline
Vector<Type, S> normalize(const Vector<Type, S>& vs)
{
return vs * isqrt(dot(vs, vs));
}
template <typename Type>
inline
Type angle(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs));
return acos(cos); //clip(cos, -1., 1.));
}
// vector 3 operations
template <typename Type>
inline
Vector<Type, 3> cross(const Vector<Type, 3>& lhs, const Vector<Type, 3>& rhs)
{
return Vector<Type, 3>(
lhs[1] * rhs[2] - lhs[2] * rhs[1],
lhs[2] * rhs[0] - lhs[0] * rhs[2],
lhs[0] * rhs[1] - lhs[1] * rhs[0]
);
}
} // end namespace hpr