CGII/framework/include/cgv/math/fvec.h
2018-05-17 16:01:02 +02:00

411 lines
No EOL
12 KiB
C++

#pragma once
#define _USE_MATH_DEFINES
#include <limits>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cgv/type/standard_types.h>
namespace cgv {
namespace math {
template <typename T> class vec;
/** A vector with zero based index.*/
template <typename T, cgv::type::uint32_type N>
class fvec
{
protected:
//elements of vector
T v[N];
public:
//@name type definitions
//@{
///
typedef T value_type;
///
typedef T& reference;
///
typedef const T& const_reference;
///
typedef std::size_t size_type;
///
typedef std::ptrdiff_t difference_type;
///
typedef T* pointer;
///
typedef const T* const_pointer;
///
typedef T* iterator;
///
typedef const T* const_iterator;
///
typedef std::reverse_iterator<iterator> reverse_iterator;
///
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
//@}
//@name iterator generation
//@{
///
iterator begin() { return v; }
///
iterator end() { return v+N; }
///
const_iterator begin() const { return v; }
///
const_iterator end() const { return v+N; }
///
reverse_iterator rbegin() { return reverse_iterator(end()); }
///
reverse_iterator rend() { return reverse_iterator(begin()); }
///
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
/// reverse iterator pointing to the end of reverse iteration
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
//@}
//@name construction and assignment
//@{
///creates a vector not initialized
fvec() {}
///creates a vector initialized to constant value a
fvec(const T &a) { std::fill(v, v+N, a); }
/// construct and init first two coordinates to the given values
fvec(const T &x, const T &y) { set(x,y); }
/// construct and init first three coordinates to the given values
fvec(const T &x, const T &y, const T &z) { set(x,y,z); }
/// construct and init first four coordinates to the given values
fvec(const T &x, const T &y, const T &z,const T &w) { set(x,y,z,w); }
///creates a column vector initialized to array a
fvec(const T *a) { std::copy(a, a+N, v); }
///creates a column vector initialized to array of a different type
template <typename S>
fvec(const S *a) { for (unsigned i=0; i<N; ++i) v[i] = (T)a[i]; }
///copy constructor
fvec(const fvec &rhs) { if (this != &rhs) std::copy(rhs.v, rhs.v+N, v); }
///copies a column vector of a different type
template <typename S>
fvec(const fvec<S,N>& fv) { for (unsigned i=0; i<N; ++i) v[i] = (T)fv(i); }
///assign vector rhs, if vector and rhs have different sizes, vector has been resized to match the size of
fvec & operator = (const fvec &rhs) { if (this != &rhs) std::copy(rhs.v, rhs.v+N, v); return *this; }
///assign a to every element
fvec & operator = (const T &a) { std::fill(v, v+N, a); return *this; }
///set the first two components
void set(const T &x, const T &y) { v[0] = x; v[1] = y; }
///set the first three components
void set(const T &x, const T &y, const T &z) { v[0] = x; v[1] = y; v[2] = z; }
///set the first four components
void set(const T &x, const T &y, const T &z, const T &w) { v[0] = x; v[1] = y; v[2] = z; v[3] = w; }
///fill elements of vector with scalar v
void fill(const T& a) { std::fill(v, v+N, a); }
///fill the vector with zeros
void zeros() { fill((T)0); }
///fill the vector with ones
void ones() { fill((T)1); }
/// convert to homogeneous version by adding a 1
fvec<T,N+1> lift() const { fvec<T,N+1> h_v; (fvec<T,N>&)h_v=*this; h_v(N) = 1; return h_v; }
/// conversion to vector type
vec<T> to_vec() const;
//@}
//@name access to components
//@{
///first element
T& x() { return v[0]; }
///first element of const vector
const T& x() const { return v[0]; }
///second element
T& y() { return v[1]; }
///second element of const vector
const T& y() const { return v[1]; }
///third element
T& z() { return v[2]; }
///third element of const vector
const T& z() const { return v[2]; }
///fourth element
T& w() { return v[3]; }
///fourth element of const vector
const T& w() const { return v[3]; }
///access i'th element
T& operator()(const int i) { return v[i]; }
///access i'th element of const vector
const T & operator()(const int i) const { return v[i]; }
///return number of elements
static unsigned size() { return N; }
///cast into array. This allows calls like glVertex<N><T>v(p) instead of glVertex<N><T,N>(p.x(),p.y(),....)
operator T*() { return v; }
///cast into const array
operator const T*() const { return v; }
//@}
//@name operators
//@{
///in place addition of a scalar s
fvec<T,N>& operator += (const T& s) { for (unsigned i=0;i<N;++i) v[i] += s; return *this; }
///in place subtraction by scalar s
fvec<T,N>& operator -= (const T& s) { for (unsigned i=0;i<N;++i) v[i] -= s; return *this; }
///in place multiplication with s
fvec<T,N>& operator *= (const T& s) { for (unsigned i=0;i<N;++i) v[i] *= s; return *this; }
///in place division by scalar s
fvec<T,N>& operator /= (const T& s) { for (unsigned i=0;i<N;++i) v[i] /= s; return *this; }
///in place vector addition
template <typename S>
fvec<T,N>& operator += (const fvec<S,N>& _v) { for (unsigned i=0; i<N;++i) v[i] += _v(i); return *this; }
///in place vector subtraction
template <typename S>
fvec<T,N>& operator -= (const fvec<S,N>& _v) { for (unsigned i=0; i<N;++i) v[i] -= _v(i); return *this; }
///in place componentwise vector multiplication
template <typename S>
fvec<T,N>& operator *= (const fvec<S,N>& _v) { for (unsigned i=0; i<N;++i) v[i] *= _v(i); return *this; }
///in place componentwise vector division
template <typename S>
fvec<T,N>& operator /= (const fvec<S,N>& _v) { for (unsigned i=0; i<N;++i) v[i] /= _v(i); return *this; }
///vector addition
template <typename S>
fvec<T,N> operator + (const fvec<S,N>& v) const { fvec<T,N> r = *this; r += v; return r; }
///componentwise addition of scalar
fvec<T,N> operator + (const T& s) const { fvec<T,N> r = *this; r += s; return r; }
///componentwise subtraction of scalar
fvec<T,N> operator - (const T& s) const { fvec<T,N> r = *this; r -= s; return r; }
///vector subtraction
template <typename S>
fvec<T,N> operator - (const fvec<S,N>& v) const { fvec<T,N> r = *this; r -= v; return r; }
///componentwise vector multiplication
template <typename S>
fvec<T,N> operator * (const fvec<S,N>& v) const { fvec<T,N> r = *this; r *= v; return r; }
///componentwise vector division
template <typename S>
fvec<T,N> operator / (const fvec<S,N>& v) const { fvec<T,N> r = *this; r /= v; return r; }
///negates the vector
fvec<T,N> operator-(void) const { fvec<T,N> r; for (unsigned i=0; i<N; ++i) r(i) = -v[i]; return r; }
///multiplication with scalar s
fvec<T,N> operator * (const T& s) const { fvec<T,N> r = *this; r *= s; return r; }
///divides vector by scalar s
fvec<T,N> operator / (const T& s) const { fvec<T,N> r = *this; r /= s; return r; }
///test for equality
template <typename S>
bool operator == (const fvec<S,N>& v) const {
for (unsigned i=0;i<N;++i)
if(operator()(i) != (T)v(i)) return false;
return true;
}
///test for inequality
template <typename S>
bool operator != (const fvec<S,N>& v) const {
for (unsigned i=0;i<N;++i)
if(operator()(i) != (T)v(i)) return true;
return false;
}
//@}
//@name functions
//@{
///length of the vector L2-Norm
T length() const
{
return (T)sqrt((double)sqr_length());
}
///componentwise absolute values
void abs() {
if(std::numeric_limits<T>::is_signed) {
for(unsigned i = 0; i < N;i++)
v[i]=(T)std::abs((double)v[i]);
}
}
///ceil componentwise
void ceil() {
for(unsigned i = 0; i < N;i++)
v[i]=(T)::ceil((double)v[i]);
}
///floor componentwise
void floor() {
for(unsigned i = 0; i < N;i++)
v[i]=(T)::floor((double)v[i]);
}
///round componentwise
void round() {
for(unsigned i = 0; i < N;i++)
v[i]=(T)::floor((double)v[i]+0.5);
}
///square length of vector
T sqr_length() const {
T l=0;
for(unsigned i = 0; i!=N;i++)
l+= operator()(i)*operator()(i);
return l;
}
/// normalize the vector using the L2-Norm and return the length
double normalize() {
T l = length();
T inv_l = (T)1.0/l;
for(unsigned i = 0; i<N; i++)
operator()(i)=inv_l*operator()(i);
return l;
}
//@}
};
/// return normalized vector
template<typename T, cgv::type::uint32_type N>
fvec<T,N> normalize(const fvec<T,N>& v) { fvec<T,N> w(v); w.normalize(); return w; }
///output of a vector
template<typename T, cgv::type::uint32_type N>
std::ostream& operator<<(std::ostream& out, const fvec<T,N>& v)
{
for (unsigned i=0;i<N-1;++i)
out << v(i)<<" ";
out << v(N-1);
return out;
}
///input of a vector
template<typename T, cgv::type::uint32_type N>
std::istream& operator>>(std::istream& in, fvec<T,N>& v)
{
for (unsigned i=0;i<N;++i)
in >> v(i);
return in;
}
///returns the product of a scalar s and vector v
template <typename T, cgv::type::uint32_type N>
fvec<T,N> operator * (const T& s, const fvec<T,N>& v)
{
fvec<T,N> r = v; r *= s; return r;
}
///returns the dot product of vector v and w
template <typename T, cgv::type::uint32_type N>
inline T dot(const fvec<T,N>& v, const fvec<T,N>& w)
{
T r = 0;
for (unsigned i=0;i<N;++i) r += v(i)*w(i);
return r;
}
///returns the length of vector v
template <typename T, cgv::type::uint32_type N>
inline T length(const fvec<T,N>& v)
{
return sqrt(dot(v,v));
}
///returns the squared length of vector v
template <typename T, cgv::type::uint32_type N>
inline T sqr_length(const fvec<T,N>& v)
{
return dot(v,v);
}
///returns the cross product of vector v and w
template < typename T, cgv::type::uint32_type N>
inline fvec<T,N> cross(const fvec<T,N>& v, const fvec<T,N>& w)
{
fvec<T,N> r(3);
r(0)= v(1)*w(2) - v(2)*w(1);
r(1)= v(2)*w(0) - v(0)*w(2);
r(2)= v(0)*w(1) - v(1)*w(0);
return r;
}
///returns the cross product of vector v and w
template < typename T, cgv::type::uint32_type N>
inline fvec<T,N+1> hom(const fvec<T,N>& v)
{
fvec<T,N+1> h;
for (unsigned i = 0; i<N; ++i)
h(i) = v(i);
h(N) = 1;
return h;
}
///returns the minimal entry
template < typename T, cgv::type::uint32_type N>
T min_value(const fvec<T,N> &v)
{
return *(std::min_element(&v(0),&v(N-1)+1));
}
///returns the index of the smallest value
template < typename T, cgv::type::uint32_type N>
unsigned min_index(const fvec<T,N> &v)
{
return (unsigned) (std::min_element(&v(0),&v(N-1)+1)-&v(0));
}
///return the index of the largest entry
template < typename T, cgv::type::uint32_type N>
unsigned max_index(const fvec<T,N> &v)
{
return (unsigned) (std::max_element(&v(0),&v(N-1)+1)-&v(0));
}
///return the value of the largest entry
template < typename T, cgv::type::uint32_type N>
T max_value(const fvec<T,N> &v)
{
return *(std::max_element(&v(0),&v(N-1)+1));
}
}
}
#include "vec.h"
namespace cgv {
namespace math {
/// conversion to vector type
template <typename T, cgv::type::uint32_type N>
vec<T> fvec<T,N>::to_vec() const {
vec<T> r;
r.set_extern_data(N,const_cast<T*>(v));
return r;
}
}
}
/*
#include <cgv/utils/convert_string.h>
#include <cgv/type/info/type_name.h>
namespace cgv {
namespace type {
namespace info {
template <typename T, cgv::type::uint32_type N>
struct type_name<cgv::math::fvec<T,N> >
{
static const char* get_name() {
static std::string name;
if (name.empty()) {
name = "fvec<";
name += type_name<T>::get_name();
name += ',';
name += cgv::utils::to_string(N);
name += '>';
}
return name.c_str();
}
};
}
}
}
*/