411 lines
No EOL
12 KiB
C++
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();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
*/ |