Just made a simple Vec
class, nothing fancy but I am open to suggestions for improvements. Of course, this is not suppose to replace or used for the same tasks as std::vector
. This is more like opencv's Vec
and eventually I want to include this in a bigger project of mine.
#include <cmath>
#include <vector>
#include <initializer_list>
#include <cassert>
#define VEC_ASSERT(x) assert(x)
template<typename T, unsigned int C>
class Vec {
public:
typedef T dataType;
typedef T& dataType_ref;
typedef const T& dataType_cref;
// Empty Constructor
Vec();
// Single-Arg Constructor
explicit Vec(T v);
// From std::vector Constructor
Vec(const std::vector<T>& v);
// From std::initializer_list Constructor
Vec(const std::initializer_list<T>& l);
// Main Constructor
template<typename ... Args>
explicit Vec(T v, Args&& ... args);
// Get vector dimensions
unsigned int dim() const;
// Get vector length
double length() const;
// Get vectors dist
double dist(const Vec<T, C>& v) const;
// Get the cross product (3D Vectors only)
Vec<T, C> cross(const Vec<T, C>& v) const;
// Get the dot product
double dot(const Vec<T, C>& v) const;
// Get ortho vector (2D vectors only)
Vec<T, C> ortho() const;
// Normalize vector values
Vec<T, C> norm() const;
// Rotate (2D Vectors only)
Vec<T, C> rotate(double angle) const;
// Rotate on x-axis (3D Vectors only)
Vec<T, C> rotateX(double angle) const;
// Rotate on y-axis (3D Vectors only)
Vec<T, C> rotateY(double angle) const;
// Rotate on z-axis (3D Vectors only)
Vec<T, C> rotateZ(double angle) const;
// Convert to std::vector
std::vector<dataType> to_std_vector() const;
// Cast
template<typename TT, unsigned int CC = C>
Vec<TT, CC> to() const;
// Access vector values
dataType_ref operator[](int index);
dataType_ref operator()(int index);
dataType_cref operator[](int index) const;
dataType_cref operator()(int index) const;
// Vector Operations with Scalars
Vec<T, C> operator+(T v);
Vec<T, C> operator-(T v);
Vec<T, C> operator*(T v);
Vec<T, C> operator/(T v);
Vec<T, C>& operator+=(T v);
Vec<T, C>& operator-=(T v);
Vec<T, C>& operator*=(T v);
Vec<T, C>& operator/=(T v);
// Vector Operations with Vectors
Vec<T, C> operator+(const Vec<T, C>& v);
Vec<T, C> operator-(const Vec<T, C>& v);
Vec<T, C> operator*(const Vec<T, C>& v);
Vec<T, C> operator/(const Vec<T, C>& v);
private:
// Recursive pusher (used by constructor)
template<typename ... Args>
void push(T v, Args&& ... args);
// Base pusher
void push(T v);
// Vector values
dataType values[C];
// Index for Vector pusher
unsigned int idx;
};
template<typename T, unsigned int C>
Vec<T, C>::Vec() {
for ( unsigned int i = 0; i < C; ++i )
this->values[i] = 0;
}
template<typename T, unsigned int C>
Vec<T, C>::Vec(T v) {
for ( unsigned int i = 0; i < C; ++i )
this->values[i] = v;
}
template<typename T, unsigned int C>
Vec<T, C>::Vec(const std::vector<T>& v) {
VEC_ASSERT(v.size() <= C);
for ( unsigned i = 0; i < v.size(); ++i )
this->values[i] = v[i];
}
template<typename T, unsigned int C>
Vec<T, C>::Vec(const std::initializer_list<T>& l) {
VEC_ASSERT(l.size() <= C);
unsigned i = 0;
for ( auto it : l )
this->values[i++] = it;
}
template<typename T, unsigned int C>
template<typename ... Args>
Vec<T, C>::Vec(T v, Args&& ... args) {
this->idx = 0;
this->values[idx] = v;
this->push(args ...);
}
template<typename T, unsigned int C>
template<typename ... Args>
void Vec<T, C>::push(T v, Args&& ... args) {
this->values[++(this->idx)] = v;
this->push(args ...);
}
template<typename T, unsigned int C>
void Vec<T, C>::push(T v) {
VEC_ASSERT(this->idx + 1 < C);
this->values[++(this->idx)] = v;
}
template<typename T, unsigned int C>
unsigned int Vec<T, C>::dim() const {
return C;
}
template<typename T, unsigned int C>
double Vec<T, C>::length() const {
double result = 0;
for ( unsigned int i = 0; i < C; ++i )
result += this->values[i] * this->values[i];
return std::sqrt(result);
}
template<typename T, unsigned int C>
double Vec<T, C>::dist(const Vec<T, C>& v) const {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] - v[i];
return result.length();
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::cross(const Vec<T, C>& v) const {
VEC_ASSERT(C == 3);
Vec<T, C> result;
result[0] = this->values[1] * v[2] - this->values[2] * v[1];
result[1] = this->values[0] * v[2] - this->values[2] * v[0];
result[2] = this->values[0] * v[0] - this->values[1] * v[0];
return result;
}
template<typename T, unsigned int C>
double Vec<T, C>::dot(const Vec<T, C>& v) const {
double result = 0.0;
for ( unsigned int i = 0; i < C; ++i )
result += this->values[i] * v[i];
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::ortho() const {
VEC_ASSERT(C == 2);
return Vec<T, C>(this->values[1], -(this->values[0]));
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::norm() const {
VEC_ASSERT(this->length() != 0);
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] * (1.0 / this->length());
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::rotate(double angle) const {
VEC_ASSERT(C == 2);
double theta = angle / 180.0 * M_PI;
double c = std::cos(theta);
double s = std::sin(theta);
double x = this->values[0] * c - this->values[1] * s;
double y = this->values[0] * s + this->values[1] * c;
return Vec<T, C>(x, y);
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::rotateX(double angle) const {
VEC_ASSERT(C == 3);
double theta = angle / 180.0 * M_PI;
double c = std::cos(theta);
double s = std::sin(theta);
double x = this->values[0];
double y = this->values[1] * c - this->values[2] * s;
double z = this->values[1] * s + this->values[2] * c;
return Vec<T, C>(x, y, z);
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::rotateY(double angle) const {
VEC_ASSERT(C == 3);
double theta = angle / 180.0 * M_PI;
double c = std::cos(theta);
double s = std::sin(theta);
double x = this->values[0] * c + this->values[2] * s;
double y = this->values[1];
double z = -(this->values[0]) * s + this->values[2] * c;
return Vec<T, C>(x, y, z);
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::rotateZ(double angle) const {
VEC_ASSERT(C == 3);
double theta = angle / 180.0 * M_PI;
double c = std::cos(theta);
double s = std::sin(theta);
double x = this->values[0] * c - this->values[1] * s;
double y = this->values[0] * s + this->values[1] * c;
double z = this->values[2];
return Vec<T, C>(x, y, z);
}
template<typename T, unsigned int C>
auto Vec<T, C>::to_std_vector() const -> std::vector<dataType> {
return std::vector<dataType>(&this->values[0], &this->values[0] + C);
}
template<typename T, unsigned int C>
template<typename TT, unsigned int CC>
Vec<TT, CC> Vec<T, C>::to() const {
Vec<TT, CC> result;
for ( unsigned int i = 0; i < std::min(C, CC); ++i )
result[i] = static_cast<TT>(this->values[i]);
return result;
}
template<typename T, unsigned int C>
auto Vec<T, C>::operator[](int index) -> dataType_ref {
VEC_ASSERT(index < C);
return this->values[index];
}
template<typename T, unsigned int C>
auto Vec<T, C>::operator()(int index) -> dataType_ref {
VEC_ASSERT(index < C);
return this->values[index];
}
template<typename T, unsigned int C>
auto Vec<T, C>::operator[](int index) const -> dataType_cref {
VEC_ASSERT(index < C);
return this->values[index];
}
template<typename T, unsigned int C>
auto Vec<T, C>::operator()(int index) const -> dataType_cref {
VEC_ASSERT(index < C);
return this->values[index];
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator+(T v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] + v;
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator-(T v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] - v;
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator*(T v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] * v;
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator/(T v) {
VEC_ASSERT(v != 0);
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] / v;
return result;
}
template<typename T, unsigned int C>
Vec<T, C>& Vec<T, C>::operator+=(T v) {
for ( unsigned int i = 0; i < C; ++i )
this->values[i] += v;
return *this;
}
template<typename T, unsigned int C>
Vec<T, C>& Vec<T, C>::operator-=(T v) {
for ( unsigned int i = 0; i < C; ++i )
this->values[i] -= v;
return *this;
}
template<typename T, unsigned int C>
Vec<T, C>& Vec<T, C>::operator*=(T v) {
for ( unsigned int i = 0; i < C; ++i )
this->values[i] *= v;
return *this;
}
template<typename T, unsigned int C>
Vec<T, C>& Vec<T, C>::operator/=(T v) {
VEC_ASSERT(v != 0);
for ( unsigned int i = 0; i < C; ++i )
this->values[i] /= v;
return *this;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator+(const Vec<T, C>& v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] + v[i];
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator-(const Vec<T, C>& v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] - v[i];
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator*(const Vec<T, C>& v) {
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] * v[i];
return result;
}
template<typename T, unsigned int C>
Vec<T, C> Vec<T, C>::operator/(const Vec<T, C>& v) {
for ( unsigned int i = 0; i < C; ++i )
VEC_ASSERT(v[i] != 0);
Vec<T, C> result;
for ( unsigned int i = 0; i < C; ++i )
result[i] = this->values[i] / v[i];
return result;
}
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<unsigned int, 2> Vec2u;
typedef Vec<unsigned int, 3> Vec3u;
typedef Vec<unsigned int, 4> Vec4u;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<char, 2> Vec2c;
typedef Vec<char, 3> Vec3c;
typedef Vec<char, 4> Vec4c;
typedef Vec<unsigned char, 2> Vec2uc;
typedef Vec<unsigned char, 3> Vec3uc;
typedef Vec<unsigned char, 4> Vec4uc;