/*
* 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
using Eigen::Matrix3d;
using Eigen::VectorXi;
using Eigen::Vector3d;
using Eigen::VectorXd;
static const double T_ZERO = 1e-7;
namespace Uncertain {
class uPoint;
//! Input operator
QDataStream & operator<< (QDataStream & out, const Aabb & bbox);
//! Output operator
QDataStream & operator>> (QDataStream & in, Aabb & bbox);
Matrix3d uStraightLineSegment::CC()
{
static Matrix3d tmp = ( Matrix3d() << 1,0,0,0,1,0,0,0,0 ).finished();
return tmp;
}
//! Get uncertain endpoint x in homogeneous coordinates
uPoint uStraightLineSegment::ux() const
{
Matrix JJ;
Matrix Cov = m_Cov_tt.topLeftCorner(6,6);
Matrix3d Sl = skew( hl() );
JJ.leftCols(3) = -skew( hm() );
JJ.rightCols(3) = Sl;
// x = Sl*m:
return { Sl*hm(), JJ*Cov*JJ.adjoint() };
}
//! Get uncertain endpoint y in homogeneous coordinates
uPoint uStraightLineSegment::uy() const
{
Matrix JJ;
Matrix3d Sl = skew( hl() );
JJ << -skew( hn() ), Matrix3d::Zero(), Sl;
return { Sl*hn(), JJ*Cov_tt()*JJ.adjoint() };
}
//! Construction of an uncertain straight line segment via two uncorrelated endpoints
uStraightLineSegment::uStraightLineSegment( const uPoint & ux,
const uPoint & uy)
: m_bounding_box( ux.bbox().united( uy.bbox()) )
{
// (1) 9-parameter vector t = [l; m; n];
const Matrix3d Sx = skew( ux.v() );
const Matrix3d Sy = skew( uy.v() );
const Matrix3d UUx = Sx*CC()*Sx;
const Matrix3d UUy = Sy*CC()*Sy;
const Vector3d l = Sx*uy.v();
Q_ASSERT( fabs( l.norm() ) > T_ZERO );
assert( fabs( l.norm() ) > T_ZERO && "identical points.");
double xh = ux.v()(2);
double yh = uy.v()(2);
// Vector9d t;
m_t.segment( 0, 3) = l;
m_t.segment( 3, 3) = +sign(yh)*UUx*uy.v();
m_t.segment( 6, 3) = -sign(xh)*UUy*ux.v();
// (2) 9x9 covariance matrix
//Matrix3d JJlx = -Sy;
//Matrix3d JJly = Sx;
Matrix3d JJmx = -sign(yh)*( Sx*CC()*Sy + skew( CC()*l ));
Matrix3d JJmy = +sign(yh)*UUx;
Matrix3d JJnx = -sign(xh)*UUy;
Matrix3d JJny = +sign(xh)*( Sy*CC()*Sx -skew( CC()*l ));
/* JJ = [ ...
JJlx, JJly; ...
JJmx, JJmy; ...
JJnx, JJny]; */
Matrix JJ;
JJ.block(0,0,3,3) = -Sy; // = JJlx
JJ.block(0,3,3,3) = Sx; // = JJly;
JJ.block(3,0,3,3) = JJmx;
JJ.block(3,3,3,3) = JJmy;
JJ.block(6,0,3,3) = JJnx;
JJ.block(6,3,3,3) = JJny;
Matrix Cov_pp;
Cov_pp.setZero();
Cov_pp.block(0,0,3,3) = ux.Cov();
Cov_pp.block(3,3,3,3) = uy.Cov();
m_Cov_tt = JJ*Cov_pp*JJ.transpose();
// return { t, JJ*Cov_pp*JJ.transpose()};
}
//! Check if the 'this' and the uncertain straight line segment 'ut' intersect (deterministic)
bool uStraightLineSegment::intersects( const uStraightLineSegment & ut) const
{
double d1 = ut.hx().dot( hl() );
double d2 = ut.hy().dot( hl() );
if ( sameSign(d1,d2) ) {
return false;
}
double d3 = hx().dot( ut.hl() );
double d4 = hy().dot( ut.hl() );
// redundant boolean literal in conditional return statement:
/* if ( sameSign( d3,d4) )
return false;
return true; */
return !sameSign(d3,d4);
}
//! Check if one of the endpoints of the uncertain straight line segment 'other' is incident.
bool uStraightLineSegment::touches( const uStraightLineSegment & other,
const double T_dist,
const double T_in) const
{
if ( other.touchedBy( ux(), T_dist, T_in) ) {
return true;
}
if ( other.touchedBy( uy(), T_dist, T_in) ) {
return true;
}
return false;
}
//! Check if the uncertain point 'ux' is incident.
bool uStraightLineSegment::touchedBy( const uPoint & ux,
const double T_dist,
const double T_in) const
{
if ( !ux.isIncidentWith( ul(), T_in ) ) { // dist(x,l)
return false;
}
uDistance ud1 = ux.distanceAlgebraicTo( um() ); // dist(x,m)
if ( !ud1.isLessThanZero(T_dist) ) {
return false;
}
uDistance ud2 = ux.distanceAlgebraicTo( un() ); // dist(x,n)
if ( !ud2.isGreaterThanZero(T_dist) ) {
return false;
}
return true;
}
//! Get the endpoints connecting uncertain straight line l = S(x)*y
uStraightLine uStraightLineSegment::ul() const
{
Matrix3d Cov_ll = m_Cov_tt.topLeftCorner(3,3);
return { m_t.head(3), Cov_ll };
}
//! Get the delimiting uncertain straight line m in homogeneous coordinates.
uStraightLine uStraightLineSegment::um() const
{
Matrix3d Cov_mm = m_Cov_tt.block(3,3,3,3);
return { m_t.segment(3,3), Cov_mm};
}
//! Get the delimiting uncertain straight line n in homogeneous coordinates.
uStraightLine uStraightLineSegment::un() const
{
Matrix3d Cov_nn = m_Cov_tt.bottomRightCorner(3,3);
return { m_t.tail(3), Cov_nn};
}
//! Get the endpoint x in homogeneous coordinates
Vector3d uStraightLineSegment::hx() const
{
Vector3d l = m_t.head(3);
Vector3d m = m_t.segment(3,3);
return skew( l )*m;
}
//! Get the endpoint y in homogeneous coordinates
Vector3d uStraightLineSegment::hy() const
{
Vector3d l = m_t.head(3);
Vector3d n = m_t.tail(3);
return skew( l )*n;
}
//! Check if uncertain straight line segment is orthogonal to uncertaint straight line segment 'ut'
bool uStraightLineSegment::isOrthogonalTo( const uStraightLineSegment & ut,
const double T_q) const
{
return ul().isOrthogonalTo( ut.ul(), T_q );
}
//! Check if uncertain straight line segment is parallel to uncertaint straight line segment 'ut'
bool uStraightLineSegment::isParallelTo( const uStraightLineSegment & ut,
const double T) const
{
return ul().isParallelTo( ut.ul(), T );
}
//! Check if uncertain straight lines 'this' and 'ut' are identical
bool uStraightLineSegment::straightLineIsIdenticalTo( const uStraightLineSegment & ut,
const double T) const
{
return ul().isIdenticalTo( ut.ul(), T );
}
//! Move endpoint x along l to intersection point of m and l.
bool uStraightLineSegment::move_x_to( const Vector3d & m)
{
Vector3d l = hl().normalized();
Vector3d z = l.cross( m.normalized() ); // intersection point z
if ( z.norm() T_ZERO, "move x", "l == m.");
Vector2d dx = x() -z.head(2)/z(2);
Matrix3d HH = ( Matrix3d() << 1,0,dx(0), 0,1,dx(1), 0,0,1).finished();
Matrix9d TT = Matrix9d::Identity();
TT.block(3,3,3,3) = HH.adjoint(); // m
transform( TT);
return true;
}
//! Move endpoint y along l to intersection point of n and l.
bool uStraightLineSegment::move_y_to( const Vector3d & n )
{
// intersection point z ............................
Vector3d l = hl().normalized();
Vector3d z = l.cross( n.normalized() );
if ( z.norm() < T_ZERO) {
return false; // l==n
}
// Q_ASSERT_X( z.norm() > T_ZERO, "move y", "l == n.");
Vector2d dx = y() -z.head(2)/z(2);
Matrix3d HH = (Matrix3d() << 1,0,dx(0), 0,1,dx(1), 0,0,1).finished();
Matrix9d TT = Matrix9d::Identity();
TT.block(6,6,3,3) = HH.adjoint(); // n
transform( TT);
return true;
}
//! Check if the uncertain straight line of 'this' is copunctual with the two uncertaint straight lines of 'us' and 'ut'
bool uStraightLineSegment::isCopunctualWith( const uStraightLineSegment & us,
const uStraightLineSegment & ut,
const double T_det) const
{
return ul().isCopunctualWith( us.ul(), ut.ul(), T_det );
}
//! Transform uncertain straight line segment via 9x9 transformation matrix for t = [l',m',n']'.
void uStraightLineSegment::transform( const Matrix9d & TT)
{
m_t = TT*m_t;
m_Cov_tt = TT*m_Cov_tt*TT.adjoint();
}
/* Matlab: [~,idx] = sort(x);
VectorXi uStraightLineSegment::indices_of_sorting( const VectorXd &v)
{
// size_t N = v.size();
// std::vector idx( N );
// std::generate( idx.begin(), idx.end(),
// [n=N-1] () mutable { return n--; } );
// auto comparator = [&v](unsigned int a, unsigned int b){ return v[a] < v[b]; };
// std::sort( idx.begin(), idx.end(), comparator);
// return idx;
Eigen::Index N = v.size();
VectorXi idx = VectorXi::LinSpaced( N,0,static_cast(N-1) ); // [0,1,...,N-1]
auto comparator = [&v](unsigned int a, unsigned int b){ return v[a] < v[b]; };
std::sort( idx.begin(), idx.end(), comparator);
return idx;
}*/
QDataStream & operator<< (QDataStream & out, const Aabb & bbox)
{
out << bbox.x_min() << bbox.x_max()
<< bbox.y_min() << bbox.y_max();
return out;
}
QDataStream & operator>> (QDataStream & in, Aabb & bbox)
{
double x_min;
double x_max;
double y_min;
double y_max;
in >> x_min >> x_max >> y_min >> y_max;
bbox = Aabb( x_min, x_max, y_min, y_max);
return in;
}
QDataStream & operator>> ( QDataStream & in, Eigen::Matrix & v);
//! Overloaded >>operator for 9-vectors
QDataStream & operator>> ( QDataStream & in, Eigen::Matrix & v)
{
for ( int i=0; i<9; i++) { in >> v[i]; }
return in;
}
QDataStream & operator>> ( QDataStream & in, Eigen::Matrix & MM);
//! Overloaded >>operator for 9x9 matrices
QDataStream & operator>> ( QDataStream & in, Eigen::Matrix & MM)
{
for ( int i=0; i<9; i++) {
for ( int j=0; j<9; j++) {
in >> MM(i,j);
}
}
return in;
}
//QDebug & operator<< ( QDebug & out, const Eigen::VectorXd &v);
//QDebug & operator<< ( QDebug & out, const Eigen::VectorXd &v)
//{
// qDebug() << Q_FUNC_INFO;
// for ( int i=0; i &v);
//! Overloaded < &v)
{
//qDebug() << Q_FUNC_INFO;
for ( int i=0; i<9; i++) { out << v[i]; }
return out;
}
QDataStream & operator<< ( QDataStream & out, const Eigen::Matrix &MM);
//! Overloaded < &MM)
{
qDebug() << Q_FUNC_INFO;
for ( int i=0; i<9; i++) {
for (int j=0; j<9; j++) {
out << MM(i,j);
}
}
return out;
}
//! Serialization of the uncertain straight line segment t=[l',m',n']' and its bounding box
void uStraightLineSegment::serialize( QDataStream & out ) const
{
qDebug() << Q_FUNC_INFO;
out << m_t;
out << m_Cov_tt;
out << m_bounding_box;
}
//! Deserialization of uncertain straight line segment and its bounding box
bool uStraightLineSegment::deserialize( QDataStream & in )
{
qDebug() << Q_FUNC_INFO;
in >> m_t;
in >> m_Cov_tt;
in >> m_bounding_box;
return in.status()==0;
}
//! Create uncertain straight line segment (for deserialization)
std::shared_ptr
uStraightLineSegment::create()
{
return std::shared_ptr(
new uStraightLineSegment()
);
// TODO(meijoc)
// return std::make_shared(); // why not?
}
} // namespace Uncertain