#pragma once #include #include #include #include #include #include #include #include #include #ifdef max #undef max #endif #ifdef min #undef min #endif namespace cgv { namespace math { /// A column vector class. template 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 reverse_iterator; typedef std::reverse_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&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 vec(const vec& 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& operator = (const vec& 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& operator = (const T& s) { fill(s); return *this; } ///assignment of a vector v template vec& operator = (const vec& 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& operator += (const T& s) { for (unsigned i=0;i<_size;++i) _data[i] += s; return *this; } ///in place subtraction by scalar s vec& operator -= (const T& s) { for (unsigned i=0;i<_size; ++i) _data[i] -= s; return *this; } ///in place multiplication with s vec& operator *= (const T& s) { for (unsigned i=0;i<_size;++i) _data[i] *= s; return *this; } ///in place division by scalar s vec& operator /= (const T& s) { for (unsigned i=0;i<_size;++i) _data[i] /= s; return *this; } ///in place vector addition template vec& operator += (const vec& v) { assert(_size == v._size); for (unsigned i=0;i<_size;++i) _data[i] += v(i); return *this; } ///in place vector subtraction template vec& operator -= (const vec& v) { assert(_size == v._size); for (unsigned i=0;i<_size;++i) _data[i] -= v(i); return *this; } ///in place componentwise vector multiplication template vec& operator *= (const vec& v) { assert(_size == v._size); for (unsigned i=0;i<_size;++i) _data[i] *= v(i); return *this; } ///in place componentwise vector division template vec& operator /= (const vec& v) { assert(_size == v._size); for (unsigned i=0;i<_size;++i) _data[i] /= v(i); return *this; } ///vector addition template const vec operator + (const vec& v) const { vec r = *this; r += v; return r; } ///componentwise addition of scalar const vec operator + (const T& s) const { vec r = *this; r += s; return r; } ///componentwise subtraction of scalar const vec operator - (const T& s) const { vec r = *this; r -= s; return r; } ///vector subtraction template vec operator - (const vec& v) const { vec r = *this; r -= v; return r; } ///componentwise vector multiplication template const vec operator * (const vec& v) const { vec r = *this; r *= v; return r; } ///componentwise vector division template const vec operator / (const vec& v) const { vec r = *this; r /= v; return r; } ///negates the vector vec operator-(void) const { vec r=(*this); r=(T)(-1)*r; return r; } ///multiplication with scalar s vec operator * (const T& s) const { vec r = *this; r *= s; return r; } ///divides vector by scalar s vec operator / (const T& s)const { vec 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 bool operator == (const vec& v) const { for (unsigned i=0;i<_size;++i) if(operator()(i) != (T)v(i)) return false; return true; } ///test for inequality template bool operator != (const vec& 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::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 sub_vec(unsigned ifrom, unsigned size) const { vec 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& 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& 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 vec normalize(const vec& v) { vec r = v; r.normalize(); return r; } ///return the p-norm of the vector default is p == 1 template T p_norm(const vec& 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 T inf_norm(const vec& values) { vec r = abs(values); return max_value(r); } ///returns the length of v L2-norm template T length(const vec& v) { return v.length(); } ///returns the square length of v template T sqr_length(const vec& v) { return v.sqr_length(); } ///output of a vector template std::ostream& operator<<(std::ostream& out, const vec& v) { for (unsigned i=0;i std::istream& operator>>(std::istream& in, vec& v) { for (unsigned i=0;i> v(i); } return in; } ///returns the product of a scalar s and vector v template const vec operator * (const T& s, const vec& v) { vec r = v; r *= s; return r; } ///returns the dot product of vector v and w template inline T dot(const vec& v, const vec& w) { T r = 0; for (unsigned i=0;i inline vec cross(const vec& v, const vec& w) { vec 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 dbl_cross(const vec &a, const vec &b, vec &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 &a,const vec &b,const vec &c) { return dot(cross(a,b),c); } ///calculates the projection of v onto n template vec project(const vec &v, const vec &n) { return dot(v,n)/dot(n,n)*n; } ///calculates the reflected direction of v; n is the normal of the reflecting surface template vec reflect(const vec &v, const vec &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 vec refract(const vec &v,const vec &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 vec zeros(const unsigned dim) { vec v; v.zeros(dim); return v; } ///create a one vector template vec ones(const unsigned dim) { vec v; v.ones(dim); return v; } ///vector of componentwise floor values template vec floor(const vec &v) { vec 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 vec ceil(const vec &v) { vec r(v.size()); for(unsigned i = 0; i < v.size();i++) r(i)=::ceil(v(i)); return r; } ///vector of componentwise ceil values template vec round(const vec &v) { vec 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 vec abs(const vec &v) { vec r(v.size()); for(unsigned i = 0; i < v.size();i++) r(i)=std::abs(v(i)); return r; } ///returns the minimal entry template T min_value(const vec &v) { return *(std::min_element(&v(0),&v(v.size()-1)+1)); } ///returns the index of the smallest value template unsigned min_index(const vec &v) { return (unsigned) (std::min_element(&v(0),&v(v.size()-1)+1)-&v(0)); } ///return the index of the largest entry template unsigned max_index(const vec &v) { return (unsigned) (std::max_element(&v(0),&v(v.size()-1)+1)-&v(0)); } ///return the value of the largest entry template T max_value(const vec &v) { return *(std::max_element(&v(0),&v(v.size()-1)+1)); } ///compute the mean of all values template T mean_value(const vec& 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 T var_value(const vec& 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 T range_value(const vec& values) { return max_value(values)-min_value(values); } ///compute the median absolut deviation MAD template T mad_value(const vec& 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 T std_value(const vec& values) { T v = var_value(values); return sqrt(v); } ///compute the mean and the variance (sigma^2) of all values template void var_and_mean_value(const vec& 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 void sort_values(vec& values, bool ascending=true) { if(ascending) std::sort(&values(0),&values(values.size()-1)+1,std::less()); else std::sort(&values(0),&values(values.size()-1)+1,std::greater()); } ///returns the sum of all entries template T sum_values(const vec& 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 T cumsum_values(const vec& values, vec& 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 T prod_values(vec& 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 T select_value(unsigned k, vec& 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 T select_median_value( vec& values) { return select_value((values.size())/2,values); } ///returns median element without modifying the given vector template T median_value(const vec& values) { vec 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 const vec lin_space(const T& first_val, const T& last_val, unsigned N=10) { vec 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 const vec cheb_points(const T& first_val, const T& last_val,unsigned N=10) { vec 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 const vec log_space(const T& first_pow_of_10, const T& last_pow_of_10, unsigned N=10) { vec 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 const vec lerp(const vec& v1, const vec& v2, T t) { return (1-t)*v1+t*v2; } ///linear interpolation returns (1-t)*v1 + t*v2 template const T lerp(const T& s1, const T& s2, T t) { return (1-t)*s1+t*s2; } ///spherical linear interpolation template const vec slerp(const vec& v0, const vec& 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 v2 = normalize(v1 - (dotv0v1)*v0); return cos(theta)*v0 + sin(theta)*v2; } } }