/*
* This file is part of the GreasePad distribution (https://github.com/FraunhoferIOSB/GreasePad).
* Copyright (c) 2022 Jochen Meidow, Fraunhofer IOSB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "upoint.h"
#include "usegment.h"
#include "ustraightline.h"
#include
namespace Uncertain {
static const double T_ZERO = 1e-7;
// type-safe
template int sign(T val) {
return (T(0) < val) - (val < T(0));
}
//! Nullspace of row vector
Matrix BasicEntity2D::null( const Vector3d &xs ) const
{
// cf. PCV, eq. (A.120)
//if ( fabs(xs.norm()-1.) > T_ZERO )
// qDebug() << xs;
#ifdef Q_DEBUG
QString what = QStringLiteral("norm(x) = %1")
.arg( QString::number(xs.norm()) );
Q_ASSERT_X( std::fabs(xs.norm()-1.) <= T_ZERO,
Q_FUNC_INFO,
what.toStdString().data() ) ;
#endif
Eigen::Index N = xs.size();
VectorXd x0 = xs.head(N-1);
double xN = xs(N-1);
if ( xN < 0.0 ) {
x0 = -x0;
xN = -xN;
}
MatrixXd JJ( N, N-1);
JJ.topRows(N-1) = MatrixXd::Identity(N-1,N-1) -x0*x0.adjoint()/(1.+xN);
JJ.bottomRows(1) = -x0.adjoint();
VectorXd check = JJ.adjoint()*xs;
Q_ASSERT_X( check.norm() <= T_ZERO,
Q_FUNC_INFO,
"not a zero vector");
return JJ;
}
//! Transform uncertain entity via 3x3 transformation matrix
void BasicEntity2D::transform( const Matrix3d & TT )
{
m_val = TT*m_val;
m_cov = TT*m_cov*TT.adjoint();
this->normalizeSpherical();
}
//! Check if matrix MM is a proper covariance matrix
bool isCovMat( const MatrixXd & MM )
{
qDebug() << Q_FUNC_INFO;
Eigen::SelfAdjointEigenSolver eig(MM);
Eigen::VectorXcd ev = eig.eigenvalues();
//#ifdef Q_DEBUG
if ( (ev.real().array() < -DBL_EPSILON ).any() ) {
for ( Eigen::Index i=0; i< ev.size(); i++) {
qDebug() << QStringLiteral( "(%1,%2)")
.arg( ev(i).real() )
.arg( ev(i).imag() );
}
}
//#endif
return (ev.real().array() >= -DBL_EPSILON ).all();
}
//! Spherically normalize the entity
void BasicEntity2D::normalizeSpherical()
{
qDebug() << Q_FUNC_INFO;
const Matrix3d I = Matrix3d::Identity();
assert( m_val.norm()>0.0 );
Matrix3d Jac = (I - m_val*m_val.adjoint()/m_val.squaredNorm()) / m_val.norm();
m_cov = Jac*m_cov*Jac.adjoint();
m_val.normalize(); // x = x /norm(x)
}
//! Check if uncertainty entity is identical with uncertain entity 'us'
bool BasicEntity2D::isIdenticalTo( const BasicEntity2D & us,
const double T) const
{
BasicEntity2D a(*this);
BasicEntity2D b(us); // copies
// fix ambiguities
a.normalizeSpherical();
b.normalizeSpherical();
int idx; // visitor
a.v().cwiseAbs().maxCoeff( &idx ); // [~,idx] = max( abs(a) )
a.m_val *= sign( a.v()(idx) ); // a = a*sign( a(idx) );
b.m_val *= sign( b.v()(idx) ); // b = b*sign( b(idx) );
Matrix JJ = null( a.v() ); // (A.120)
Vector2d d = JJ.adjoint()*( a.v() -b.v() ); // (10.141)
Eigen::Matrix2d Cov_dd = JJ.adjoint()*( a.Cov()+b.Cov())*JJ;
return d.adjoint()*Cov_dd.inverse()*d < T; // dof = 2
}
std::pair uEndPoints( const Eigen::VectorXd & xi,
const Eigen::VectorXd & yi)
{
Q_ASSERT( xi.size()>0 );
Q_ASSERT( yi.size()==xi.size() );
const uStraightLine l(xi,yi);
const double phi = l.angle_rad();
const VectorXd zi = sin(phi)*xi -cos(phi)*yi;
int idx;
Vector3d x1;
zi.minCoeff( &idx);
x1 << xi(idx), yi(idx), 1;
Vector3d x2;
zi.maxCoeff( &idx);
x2 << xi(idx), yi(idx), 1;
const Matrix3d Zeros = Matrix3d::Zero(3,3);
Matrix3d Cov_xx = Matrix3d::Zero();
uDistance ud1 = uPoint(x1, Zeros).distanceEuclideanTo(l);
Cov_xx.diagonal() << ud1.var_d(), ud1.var_d(), 0.; // isotropic
uPoint first_ = l.project( uPoint( x1, Cov_xx) ) ;
uDistance ud2 = uPoint(x2,Zeros).distanceEuclideanTo(l);
Cov_xx.diagonal() << ud2.var_d(), ud2.var_d(), 0.;
uPoint second_ = l.project( uPoint( x2, Cov_xx) );
return { first_, second_};
}
//! Skew-symmetric cross product matrix S(x): a x b = S(a)*b
Matrix3d skew( const Vector3d & x)
{
return (Matrix3d() << 0.,-x(2),x(1), x(2),0.,-x(0), -x(1),x(0),0.).finished();
}
} // namespace Uncertain