215 lines
4.8 KiB
C++
215 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include "vec.h"
|
|
#include "mat.h"
|
|
#include "inv.h"
|
|
|
|
namespace cgv {
|
|
namespace math {
|
|
|
|
|
|
/// dimension independent implementation of quadric error metrics
|
|
template <typename T>
|
|
class qem : public vec<T>
|
|
{
|
|
public:
|
|
/// standard constructor initializes qem based on dimension
|
|
qem(int d = -1) : vec<T>((d+1)*(d+2)/2)
|
|
{
|
|
if (d>=0)
|
|
this->zeros();
|
|
}
|
|
/// construct from point and normal
|
|
qem(const vec<T>& p, const vec<T>& n) : vec<T>((p.size()+1)*(p.size()+2)/2)
|
|
{
|
|
set(n, -dot(p,n));
|
|
}
|
|
/// construct from normal and distance to origin
|
|
qem(const vec<T>& n, T d) : vec<T>((n.size()+1)*(n.size()+2)/2)
|
|
{
|
|
set(n,d);
|
|
}
|
|
/// set from normal and distance to origin
|
|
void set(const vec<T>& n, T d)
|
|
{
|
|
this->first() = d*d;
|
|
unsigned int i,j,k=n.size()+1;
|
|
for (i=0;i<n.size(); ++i) {
|
|
(*this)(i+1) = d*n(i);
|
|
for (j=i;j<n.size(); ++j, ++k)
|
|
(*this)(k) = n(i)*n(j);
|
|
}
|
|
}
|
|
///number of elements
|
|
unsigned dim() const
|
|
{
|
|
return (unsigned int)sqrt(2.0*this->size())-1;
|
|
}
|
|
///assignment of a vector v
|
|
qem<T>& operator = (const qem<T>& v)
|
|
{
|
|
*static_cast<vec<T>*>(this) = v;
|
|
return *this;
|
|
}
|
|
/// return the scalar part of the qem
|
|
const T& scalar_part() const
|
|
{
|
|
return this->first();
|
|
}
|
|
/// return the vector part of the qem
|
|
vec<T> vector_part() const
|
|
{
|
|
vec<T> v(dim());
|
|
for (unsigned int i=0; i<v.size(); ++i)
|
|
v(i) = (*this)(i+1);
|
|
return v;
|
|
}
|
|
/// return matrix part
|
|
mat<T> matrix_part() const
|
|
{
|
|
unsigned int d = dim();
|
|
mat<T> m(d,d);
|
|
unsigned int i,j,k=d+1;
|
|
for (i=0; i<d; ++i)
|
|
for (j=i; j<d; ++j,++k)
|
|
m(i,j) = m(j,i) = (*this)(k);
|
|
return m;
|
|
}
|
|
/// evaluate the quadric error metric at given location
|
|
T evaluate(const vec<T>& p) const
|
|
{
|
|
return dot(matrix_part()*p+2.0*vector_part(),p)+scalar_part();
|
|
}
|
|
static bool inside(const vec<T>& p, const vec<T>& minp, const vec<T>& maxp)
|
|
{
|
|
for (unsigned int i=0; i<p.size(); ++i) {
|
|
if (p(i) < minp(i))
|
|
return false;
|
|
if (p(i) > maxp(i))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/** compute point that minimizes distance to qem and is inside the sphere of radius max_distance
|
|
around p_ref. If max_distance is -1, no sphere inclusion test is performed.
|
|
relative_epsilon gives the absolute value of the fraction betweenan eigenvalue and the
|
|
largest eigenvalue before it is set to zero. epsilon is a global limit on the absolute
|
|
value of a singular value before accepted as non zero. */
|
|
vec<T> minarg(const vec<T>& p_ref, T relative_epsilon, T max_distance = -1, T epsilon = 1e-10) const
|
|
{
|
|
unsigned int d = p_ref.size();
|
|
assert(d == dim());
|
|
T max_distance2 = max_distance*max_distance;
|
|
mat<T> U,V,A = matrix_part();
|
|
diag_mat<T> W,iW;
|
|
svd(A,U,W,V);
|
|
U.transpose();
|
|
iW = inv(W);
|
|
vec<T> y_solve = -(inv(W)*(U*vector_part()));
|
|
vec<T> y_ref = transpose(V)*p_ref;
|
|
vec<T> y(3);
|
|
for (unsigned int i = d; i > 0; ) {
|
|
--i;
|
|
if (fabs(W(i)) > epsilon && fabs(W(i)*iW(0)) > relative_epsilon) {
|
|
unsigned int j;
|
|
for (j = 0; j <= i; ++j)
|
|
y(j) = y_solve(j);
|
|
for (; j < d; ++j)
|
|
y(j) = y_ref(j);
|
|
vec<T> p = V*y;
|
|
if (max_distance != -1 && (p-p_ref).sqr_length() <= max_distance2)
|
|
return p;
|
|
}
|
|
}
|
|
return p_ref;
|
|
}
|
|
/// in place qem addition
|
|
template <typename S>
|
|
qem<T>& operator += (const qem<S>& v)
|
|
{
|
|
assert(this->size() == v.size());
|
|
for (unsigned i=0;i<this->size();++i) (*this)(i) += v(i); return *this;
|
|
}
|
|
|
|
///in place qem subtraction
|
|
template <typename S>
|
|
qem<T>& operator -= (const qem<S>& v)
|
|
{
|
|
assert(this->size() == v.size());
|
|
for (unsigned i=0;i<this->size();++i) (*this)(i) -= v(i); return *this;
|
|
}
|
|
|
|
///qem addition
|
|
template <typename S>
|
|
const qem<T> operator + (const qem<S>& v) const
|
|
{
|
|
vec<T> r = *this; r += v; return r;
|
|
}
|
|
|
|
///qem subtraction
|
|
template <typename S>
|
|
qem<T> operator - (const qem<S>& v) const
|
|
{
|
|
qem<T> r = *this; r -= v; return r;
|
|
}
|
|
|
|
///negates the qem
|
|
qem<T> operator-(void) const
|
|
{
|
|
qem<T> r=(*this);
|
|
r=(T)(-1)*r;
|
|
return r;
|
|
}
|
|
|
|
///multiplication with scalar s
|
|
qem<T> operator * (const T& s) const
|
|
{
|
|
qem<T> r = *this; r *= s; return r;
|
|
}
|
|
|
|
|
|
///divides vector by scalar s
|
|
qem<T> operator / (const T& s)const
|
|
{
|
|
qem<T> r = *this;
|
|
r /= s;
|
|
return r;
|
|
}
|
|
|
|
///resize the vector
|
|
void resize(unsigned d)
|
|
{
|
|
vec<T>::resize((d+1)*(d+2)/2);
|
|
}
|
|
|
|
///test for equality
|
|
template <typename S>
|
|
bool operator == (const qem<S>& v) const
|
|
{
|
|
for (unsigned i=0;i<this->size();++i)
|
|
if((*this)(i) != (T)v(i)) return false;
|
|
return true;
|
|
}
|
|
|
|
///test for inequality
|
|
template <typename S>
|
|
bool operator != (const qem<S>& v) const
|
|
{
|
|
for (unsigned i=0;i<this->size();++i)
|
|
if((*this)(i) != (T)v(i)) return true;
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
///returns the product of a scalar s and qem v
|
|
template <typename T>
|
|
const qem<T> operator * (const T& s, const qem<T>& v)
|
|
{
|
|
qem<T> r = v; r *= s; return r;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|