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

1234 lines
22 KiB
C++

#pragma once
#include <iostream>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <functional>
#include <iterator>
#include <limits>
#include <string.h>
#include <vector>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace cgv {
namespace math {
/// A column vector class.
template <typename T>
class vec
{
protected:
///pointer to _data storage
T *_data;
///number or elements
unsigned _size;
/// store whether data is not owned by vector
bool data_is_external;
public:
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;
iterator begin()
{
return _data;
}
iterator end()
{
return _data+_size;
}
const_iterator begin() const
{
return _data;
}
const_iterator end() const
{
return _data+_size;
}
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
///number of elements
unsigned size() const
{
return _size;
}
///number of elements
unsigned dim() const
{
return _size;
}
///standard constructor
vec()
{
_data = NULL;
_size = 0;
data_is_external = false;
}
///creates a vector with dim elements
explicit vec(unsigned dim)
{
_size=dim;
if(dim > 0)
_data = new T[_size];
else
_data = NULL;
data_is_external = false;
}
///creates a vector with dim elements from an array
vec(unsigned dim, const T* marray)
{
_size = dim;
if(dim > 0)
{
_data = new T[_size];
memcpy(_data,marray,_size*sizeof(T));
}else
_data = NULL;
data_is_external = false;
}
///copy constructor for vectors with equal element type
vec(const vec<T>&v)
{
_size = v.size();
if (v._data) {
_data = new T[v.size()];
memcpy(_data,v._data,_size*sizeof(T));
}
else
_data=NULL;
data_is_external = false;
}
///copy constructor for vectors with different element type
template <typename S>
vec(const vec<S>& v)
{
_size = v.size();
if(v.size() > 0) {
_data = new T[v.size()];
for(unsigned i = 0; i < _size;i++)
_data [i]=(T)v(i);
}
else
_data =NULL;
data_is_external = false;
}
///creates a 3d vector (c0,c1,c2)^T
vec(const T& c0, const T& c1)
{
_size = 2;
_data = new T[2];
_data[0] = c0;
_data[1] = c1;
data_is_external = false;
}
///creates a 3d vector (c0,c1,c2)^T
vec(const T& c0, const T& c1, const T& c2)
{
_size = 3;
_data = new T[3];
_data[0] = c0;
_data[1] = c1;
_data[2] = c2;
data_is_external = false;
}
///creates a 4d vector (c0,c1,c2,c3)^T
vec(const T& c0, const T& c1, const T& c2, const T& c3)
{
_size = 4;
_data = new T[4];
_data[0] = c0;
_data[1] = c1;
_data[2] = c2;
_data[3] = c3;
data_is_external = false;
}
///set entries of a 2d vector
void set(const T& c0, const T& c1)
{
assert(_size == 2);
_data[0] = c0;
_data[1] = c1;
}
///set entries of a 3d vector
void set(const T& c0, const T& c1, const T& c2)
{
assert(_size == 3);
_data[0] = c0;
_data[1] = c1;
_data[2] = c2;
}
///set entries of a 4d vector
void set(const T& c0, const T& c1, const T& c2, const T& c3)
{
assert(_size == 4);
_data[0] = c0;
_data[1] = c1;
_data[2] = c2;
_data[3] = c3;
}
/// set data pointer to an external data array
void set_extern_data(unsigned dim, T* data)
{
destruct();
_size = dim;
_data = data;
data_is_external = true;
}
///destructor
virtual ~vec()
{
destruct();
}
void destruct()
{
if(_data && !data_is_external)
{
delete[] _data;
_data=NULL;
_size=0;
}
}
///cast into non const array
operator T*()
{
return _data;
}
///cast into const array
operator const T*() const
{
return _data;
}
///assignment of a vector v
vec<T>& operator = (const vec<T>& v)
{
if(v.size() == 0)
destruct();
else {
if (size() != v.size())
resize(v.size());
memcpy(_data,v._data,_size*sizeof(T));
}
return *this;
}
///assignment of a scalar s
vec<T>& operator = (const T& s)
{
fill(s);
return *this;
}
///assignment of a vector v
template <typename S>
vec<T>& operator = (const vec<S>& v)
{
resize(v.size());
for (unsigned i=0;i<_size;++i) _data[i]=(T)v(i);
return *this;
}
///element accessor
T& operator () (unsigned i)
{
assert(i < _size);
return _data[i];
}
///const element accessor
const T& operator () (unsigned i) const
{
assert(i < _size);
return _data[i];
}
///element accessor for the first element
T& first()
{
assert( _size > 0);
return _data[0];
}
///const element accessor for the first element
const T& first() const
{
assert( _size > 0);
return _data[0];
}
///element accessor for the flast element
T& last()
{
assert( _size > 0);
return _data[_size-1];
}
///const element accessor for the last element
const T& last() const
{
assert( _size > 0);
return _data[_size-1];
}
///element accessor for the first element
T& x()
{
assert( _size > 0);
return _data[0];
}
///const element accessor for the first element
const T& x() const
{
assert( _size > 0);
return _data[0];
}
///element accessor for the second element
T& y()
{
assert( _size > 1);
return _data[1];
}
///const element accessor for the second element
const T& y() const
{
assert( _size > 1);
return _data[1];
}
///element accessor for the third element
T& z()
{
assert( _size > 2);
return _data[2];
}
///const element accessor for the third element
const T& z() const
{
assert( _size > 2);
return _data[2];
}
///element accessor for the fourth element
T& w()
{
assert( _size > 3);
return _data[3];
}
///const element accessor for the fourth element
const T& w() const
{
assert( _size > 3);
return _data[3];
}
///in place addition of a scalar s
vec<T>& operator += (const T& s)
{
for (unsigned i=0;i<_size;++i)
_data[i] += s;
return *this;
}
///in place subtraction by scalar s
vec<T>& operator -= (const T& s)
{
for (unsigned i=0;i<_size; ++i)
_data[i] -= s;
return *this;
}
///in place multiplication with s
vec<T>& operator *= (const T& s)
{
for (unsigned i=0;i<_size;++i) _data[i] *= s; return *this;
}
///in place division by scalar s
vec<T>& operator /= (const T& s)
{
for (unsigned i=0;i<_size;++i) _data[i] /= s; return *this;
}
///in place vector addition
template <typename S>
vec<T>& operator += (const vec<S>& v)
{
assert(_size == v._size);
for (unsigned i=0;i<_size;++i) _data[i] += v(i); return *this;
}
///in place vector subtraction
template <typename S>
vec<T>& operator -= (const vec<S>& v)
{
assert(_size == v._size);
for (unsigned i=0;i<_size;++i) _data[i] -= v(i); return *this;
}
///in place componentwise vector multiplication
template <typename S>
vec<T>& operator *= (const vec<S>& v)
{
assert(_size == v._size);
for (unsigned i=0;i<_size;++i) _data[i] *= v(i); return *this;
}
///in place componentwise vector division
template <typename S>
vec<T>& operator /= (const vec<S>& v)
{
assert(_size == v._size);
for (unsigned i=0;i<_size;++i) _data[i] /= v(i); return *this;
}
///vector addition
template <typename S>
const vec<T> operator + (const vec<S>& v) const
{
vec<T> r = *this; r += v; return r;
}
///componentwise addition of scalar
const vec<T> operator + (const T& s) const
{
vec<T> r = *this; r += s; return r;
}
///componentwise subtraction of scalar
const vec<T> operator - (const T& s) const
{
vec<T> r = *this; r -= s; return r;
}
///vector subtraction
template <typename S>
vec<T> operator - (const vec<S>& v) const
{
vec<T> r = *this; r -= v; return r;
}
///componentwise vector multiplication
template <typename S>
const vec<T> operator * (const vec<S>& v) const
{
vec<T> r = *this; r *= v; return r;
}
///componentwise vector division
template <typename S>
const vec<T> operator / (const vec<S>& v) const
{
vec<T> r = *this; r /= v; return r;
}
///negates the vector
vec<T> operator-(void) const
{
vec<T> r=(*this);
r=(T)(-1)*r;
return r;
}
///multiplication with scalar s
vec<T> operator * (const T& s) const
{
vec<T> r = *this; r *= s; return r;
}
///divides vector by scalar s
vec<T> operator / (const T& s)const
{
vec<T> r = *this;
r /= s;
return r;
}
///fill elements of vector with scalar v
void fill(const T& v)
{
for (unsigned i=0; i<_size; ++i)
_data[i]= (T)v;
}
///fill the vector with zeros
void zeros()
{
fill((T)0);
}
///fill the vector with ones
void ones()
{
fill((T)1);
}
///resize the vector to size n and fills the vector with zeros
void zeros(unsigned n)
{
resize(n);
fill((T)0);
}
///resize the vector to size n and fills thevector with ones
void ones(unsigned n)
{
resize(n);
fill((T)1);
}
///resize the vector
void resize(unsigned dim)
{
if(_data)
{
if(dim != _size)
{
destruct();
_size=dim;
if(dim > 0)
_data = new T[dim];
else
_data = NULL;
data_is_external = false;
}
}else
{
_size=dim;
if(dim > 0)
_data = new T[dim];
else
_data = NULL;
data_is_external = false;
}
}
///test for equality
template <typename S>
bool operator == (const vec<S>& v) const
{
for (unsigned i=0;i<_size;++i)
if(operator()(i) != (T)v(i)) return false;
return true;
}
///test for inequality
template <typename S>
bool operator != (const vec<S>& v) const
{
for (unsigned i=0;i<_size;++i)
if(operator()(i) != (T)v(i)) return true;
return false;
}
///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 < _size;i++)
_data[i]=(T)std::abs((double)_data[i]);
}
}
///ceil componentwise
void ceil()
{
for(unsigned i = 0; i < _size;i++)
_data[i]=(T)::ceil((double)_data[i]);
}
///floor componentwise
void floor()
{
for(unsigned i = 0; i < _size;i++)
_data[i]=(T)::floor((double)_data[i]);
}
///round componentwise
void round()
{
for(unsigned i = 0; i < _size;i++)
_data[i]=(T)::floor((double)_data[i]+0.5);
}
///square length of vector
T sqr_length() const
{
T l=0;
for(unsigned i = 0; i!=_size;i++)
l+= operator()(i)*operator()(i);
return l;
}
///normalize the vector using the L2-Norm
void normalize()
{
T l = (T)1.0/length();
for(unsigned i = 0; i<_size; i++)
operator()(i)=l*operator()(i);
}
///extracts sub vector beginning at index ifrom with given size
vec<T> sub_vec(unsigned ifrom, unsigned size) const
{
vec<T> vnew(size);
for(unsigned i = 0; i < size; i++)
vnew(i)=operator()(i+ifrom);
return vnew;
}
///copy sub vector beginning at index ifrom with given size s into subvec
void copy(unsigned ifrom, unsigned s,vec<T>& subvec) const
{
assert(subvec.size() == s);
assert(ifrom+s <=size());
for(unsigned i = 0; i < s; i++)
subvec(i)=operator()(i+ifrom);
}
///paste v into vector beginning at index pos ifrom
void paste(unsigned ifrom,const vec<T>& v)
{
assert(ifrom+v.size() <= size());
for(unsigned i = 0; i < v.size(); i++)
operator()(i+ifrom) = v(i);
}
};
///returns a normalized version of v
template<typename T>
vec<T> normalize(const vec<T>& v)
{
vec<T> r = v;
r.normalize();
return r;
}
///return the p-norm of the vector default is p == 1
template <typename T,typename S>
T p_norm(const vec<T>& values,const S& p=1)
{
assert(p > 0);
unsigned N = values.size();
T n=0;
for(unsigned i = 0; i < N;i++)
{
n+=pow(fabs(values(i)),(T)p);
}
return pow(n,(T)(1.0/(T)p));
}
///return the infinity norm of the vector
template <typename T>
T inf_norm(const vec<T>& values)
{
vec<T> r = abs(values);
return max_value(r);
}
///returns the length of v L2-norm
template<typename T>
T length(const vec<T>& v)
{
return v.length();
}
///returns the square length of v
template<typename T>
T sqr_length(const vec<T>& v)
{
return v.sqr_length();
}
///output of a vector
template<typename T>
std::ostream& operator<<(std::ostream& out, const vec<T>& v)
{
for (unsigned i=0;i<v.size()-1;++i)
{
out << v(i)<<" ";
}
out << v(v.size()-1);
return out;
}
///input of a vector
template<typename T>
std::istream& operator>>(std::istream& in, vec<T>& v)
{
for (unsigned i=0;i<v.size();++i)
{
in >> v(i);
}
return in;
}
///returns the product of a scalar s and vector v
template <typename T>
const vec<T> operator * (const T& s, const vec<T>& v)
{
vec<T> r = v; r *= s; return r;
}
///returns the dot product of vector v and w
template <typename T>
inline T dot(const vec<T>& v, const vec<T>& w)
{
T r = 0;
for (unsigned i=0;i<v.size();++i) r += v(i)*(T)w(i);
return r;
}
///returns the cross product of vector v and w
template < typename T>
inline vec<T> cross(const vec<T>& v, const vec<T>& w)
{
vec<T> r(3);
r(0)= v(1)*(T)w(2) - v(2)*(T)w(1);
r(1)= -v(0)*(T)w(2) + v(2)*(T)w(0);
r(2)= v(0)*(T)w(1) - v(1)*(T)w(0);
return r;
}
///returns the double cross product of vector a, b and c a x(b x c)
template < typename T, typename S, typename U>
vec<T> dbl_cross(const vec<T> &a, const vec<S> &b, vec<U> &c)
{
return dot(a,c)*b - dot(a,b)*c;
}
///returns the spat product (mixed vector product) of the vectors a, b and c
template < typename T, typename S, typename U>
T spat(const vec<T> &a,const vec<S> &b,const vec<U> &c)
{
return dot(cross(a,b),c);
}
///calculates the projection of v onto n
template <typename T>
vec<T> project(const vec<T> &v, const vec<T> &n)
{
return dot(v,n)/dot(n,n)*n;
}
///calculates the reflected direction of v; n is the normal of the reflecting surface
template <typename T>
vec<T> reflect(const vec<T> &v, const vec<T> &n)
{
return v-(T)2.0*dot(v,n)/dot(n,n)*n;
}
///calculates the refracted direction of v on a surface with normal n and refraction indices c1,c2, *the optional parameter total reflection
///will be set true if a total reflection occured otherwise false
template <typename T>
vec<T> refract(const vec<T> &v,const vec<T> &n,T c1, T c2,bool* total_reflection=NULL)
{
T NdotV =-dot(n,v)/dot(n,n);
T c = c2/c1;
T cosasqr = (T)1.0-(c*c)*((T)1.0-NdotV*NdotV);
//total reflection
if(cosasqr < 0)
{
if(total_reflection)
*total_reflection=true;
return reflect(v,n);
}
else
{
if(total_reflection)
*total_reflection=false;
return c*v + (c*NdotV - sqrt(cosasqr)/dot(n,n) )*n;
}
}
///create a zero vector
template <typename T>
vec<T> zeros(const unsigned dim)
{
vec<T> v;
v.zeros(dim);
return v;
}
///create a one vector
template <typename T>
vec<T> ones(const unsigned dim)
{
vec<T> v;
v.ones(dim);
return v;
}
///vector of componentwise floor values
template <typename T>
vec<T> floor(const vec<T> &v)
{
vec<T> r(v.size());
for(unsigned i = 0; i < v.size();i++)
r(i)=::floor((T)v(i));
return r;
}
///vector of componentwise ceil values
template <typename T>
vec<T> ceil(const vec<T> &v)
{
vec<T> r(v.size());
for(unsigned i = 0; i < v.size();i++)
r(i)=::ceil(v(i));
return r;
}
///vector of componentwise ceil values
template <typename T>
vec<T> round(const vec<T> &v)
{
vec<T> r(v.size());
for(unsigned i = 0; i < v.size();i++)
r(i)=::floor(v(i)+0.5);
return r;
}
///vector of componentwise absolute values
template <typename T>
vec<T> abs(const vec<T> &v)
{
vec<T> r(v.size());
for(unsigned i = 0; i < v.size();i++)
r(i)=std::abs(v(i));
return r;
}
///returns the minimal entry
template <typename T>
T min_value(const vec<T> &v)
{
return *(std::min_element(&v(0),&v(v.size()-1)+1));
}
///returns the index of the smallest value
template <typename T>
unsigned min_index(const vec<T> &v)
{
return (unsigned) (std::min_element(&v(0),&v(v.size()-1)+1)-&v(0));
}
///return the index of the largest entry
template <typename T>
unsigned max_index(const vec<T> &v)
{
return (unsigned) (std::max_element(&v(0),&v(v.size()-1)+1)-&v(0));
}
///return the value of the largest entry
template <typename T>
T max_value(const vec<T> &v)
{
return *(std::max_element(&v(0),&v(v.size()-1)+1));
}
///compute the mean of all values
template<typename T>
T mean_value(const vec<T>& values)
{
unsigned N = values.size();
T mu=0;
for(unsigned i = 0; i < N;i++)
{
mu+=values(i);
}
mu/=(T)N;
return mu;
}
///compute the variance of all values,
///normalization is done with n-1 (unbiased estimator)
template<typename T>
T var_value(const vec<T>& values)
{
unsigned N = values.size();
T mu=mean_value(values);
T v = 0;
for(unsigned i = 0; i < N;i++)
{
v+=(values(i)-mu)*(values(i)-mu);
}
if(N > 1)
v/=(T)(N-1);
return v;
}
///compute the range of all values
template<typename T>
T range_value(const vec<T>& values)
{
return max_value(values)-min_value(values);
}
///compute the median absolut deviation MAD
template<typename T>
T mad_value(const vec<T>& values)
{
return median_value(abs(values-median_value(values)));
}
///compute the standard deviation (sigma) of all values,
///normalization is done by n-1 (unbiased estimator)
template<typename T>
T std_value(const vec<T>& values)
{
T v = var_value(values);
return sqrt(v);
}
///compute the mean and the variance (sigma^2) of all values
template<typename T>
void var_and_mean_value(const vec<T>& values, T& mu, T&var)
{
unsigned N = values.size();
mu=0;
for(unsigned i = 0; i < N;i++)
{
mu+=values(i);
}
mu/=(T)N;
var = 0;
for(unsigned i = 0; i < N;i++)
{
var+=sqr(values(i)-mu);
}
var/=(T)(N-1);
}
///sort vector elements in ascending or descending order
template <typename T>
void sort_values(vec<T>& values, bool ascending=true)
{
if(ascending)
std::sort(&values(0),&values(values.size()-1)+1,std::less<T>());
else
std::sort(&values(0),&values(values.size()-1)+1,std::greater<T>());
}
///returns the sum of all entries
template <typename T>
T sum_values(const vec<T>& values)
{
T v =0;
for(unsigned i = 0; i < values.size(); i++)
v+=values(i);
return v;
}
///computes cumulative sums in cumsumvalues
///cumsumvalues[i] = values[0]+...+values[i-1]
///returns the sum of all entries
template <typename T>
T cumsum_values(const vec<T>& values, vec<T>& cumsumvalues)
{
cumsumvalues.resize(values.size());
T v =0;
for(unsigned i = 0; i < values.size(); i++)
{
cumsumvalues(i)=v;
v+=values(i);
}
return v;
}
///returns the product of all entries
template <typename T>
T prod_values(vec<T>& values)
{
T v =1;
for(unsigned i = 0; i < values.size(); i++)
v*=values(i);
return v;
}
///returns the kth-smallest value of values
///the input vector values will be rearranged to have this value in location arr[k],
///with all smaller elements moved to values[0..k-1] (in arbitrary order) and all
///larger elements in values[k+1..n] (also in arbitrary order).
template <typename T>
T select_value(unsigned k, vec<T>& values)
{
if (k >= values.size())
k = values.size()-1;
std::nth_element(&values(0),&values(k),&values(values.size()-1)+1);
return values(k);
}
///returns the value of values
///the input vector arr will be rearanged to have this value in location arr[k],
///with all smaller elements moved to values[0..k-1] (in arbitrary order) and all
///larger elements in values[k+1..n] (also in arbitrary order).
///if the number of components are even then the ceil((n+1)/2) entry is returned
template <typename T>
T select_median_value( vec<T>& values)
{
return select_value((values.size())/2,values);
}
///returns median element without modifying the given vector
template <typename T>
T median_value(const vec<T>& values)
{
vec<T> c = values;
return select_value((c.size())/2,c);
}
///create a linearly spaced vector with N values starting at first_val and ending ant last_val
template <typename T>
const vec<T> lin_space(const T& first_val, const T& last_val, unsigned N=10)
{
vec<T> lv(N);
if(N == 1)
{
lv(0) = last_val;
return lv;
}
T diff = last_val-first_val;
for(unsigned i = 0; i < N; i++)
{
lv(i) = first_val + i*diff/((T)N-(T)1.0);
}
return lv;
}
//create N chebychev sample points for interval [first_val,last_val]
template <typename T>
const vec<T> cheb_points(const T& first_val, const T& last_val,unsigned N=10)
{
vec<T> lv(N) ;
if(N == 1)
{
lv(0) = (T)(first_val+last_val)/2.0;
return lv;
}
T diff = (last_val-first_val)/(T)2.0;
for(unsigned i = 0; i < N; i++)
{
lv(i) = diff*((first_val+1.0)-cos((T)((2*i+1)*3.14159)/((T)(2.0*(N-1)+2))));
}
return lv;
}
///create a log spaced vector with N values starting at 10^first_pow_of_10 and
///ending at 10 last_val
template <typename T>
const vec<T> log_space(const T& first_pow_of_10, const T& last_pow_of_10, unsigned N=10)
{
vec<T> lv(N);
if(N == 1)
{
lv(0) = pow((T)10.0,last_pow_of_10);
return lv;
}
T diff = last_pow_of_10 - first_pow_of_10;
for(unsigned i = 0; i < N; i++)
{
lv(i) = pow((T)10.0,(T)first_pow_of_10 + (T)i*diff/((T)N-(T)1.0));
}
return lv;
}
///linear interpolation returns (1-t)*v1 + t*v2
template <typename T>
const vec<T> lerp(const vec<T>& v1, const vec<T>& v2, T t)
{
return (1-t)*v1+t*v2;
}
///linear interpolation returns (1-t)*v1 + t*v2
template <typename T>
const T lerp(const T& s1, const T& s2, T t)
{
return (1-t)*s1+t*s2;
}
///spherical linear interpolation
template <typename T>
const vec<T> slerp(const vec<T>& v0, const vec<T>& v1, T t)
{
T dotv0v1 = dot(v0,v1);
//clamp between [-1,1]
if(dotv0v1 < -1)
dotv0v1 = -1;
if(dotv0v1 > 1)
dotv0v1 = 1;
T theta = acos(dotv0v1)*t;
cgv::math::vec<T> v2 = normalize(v1 - (dotv0v1)*v0);
return cos(theta)*v0 + sin(theta)*v2;
}
}
}