/*
* This file is part of the GreasePad distribution (https://github.com/FraunhoferIOSB/GreasePad).
* Copyright (c) 2022-2026 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 "matfun.h"
#include "statistics/iscov.h"
#include "udistance.h"
#include "uncertain/uelement.h"
#include "upoint.h"
#include "ustraightline.h"
#include
#include
#include "qassert.h"
#include "qtdeprecationdefinitions.h"
#include
#include
#include
using Eigen::Matrix;
using Eigen::Matrix2d;
using Eigen::Matrix3d;
using Eigen::Vector2d;
using Eigen::Vector3d;
using Matfun::sign;
using Matfun::cof3;
using Stats::isCovMat;
namespace Uncertain {
//! Construction of uncertain point via 3-vector x and its covariance matrix
uPoint::uPoint( const Vector3d & x, const Matrix3d & Sigma_xx)
: uElement (x, Sigma_xx)
{
// qDebug() << Q_FUNC_INFO;
}
//! confidence ellipse
Matrix3d uPoint::conicMatrix(const double k2) const
{
const uPoint ux = this->euclidean();
return cof3( k2*ux.Cov() -ux.v()*ux.v().transpose() );
}
//! Get axis-aligned bounding box
Aabb uPoint::bbox() const
{
const double uu = v(0);
const double vv = v(1);
const double ww = v(2);
const Matrix JJ {
{ 1/ww, 0, -uu/(ww*ww)},
{ 0, 1/ww, -vv/(ww*ww)} };
const Matrix2d Cov_xx = JJ * Cov() * JJ.transpose();
const double x = v(0) / v(2);
const double y = v(1) / v(2);
const double x_min = x - sqrt(Cov_xx(0, 0));
const double x_max = x + sqrt(Cov_xx(0, 0));
const double y_min = y - sqrt(Cov_xx(1, 1));
const double y_max = y + sqrt(Cov_xx(1, 1));
return Aabb{
Vector2d(x_min, y_min),
Vector2d(x_max, y_max)
};
}
//! Get Euclidean distance to uncertain straight line 'ul'
uDistance uPoint::distanceEuclideanTo( const uStraightLine & ul) const
{
const Vector3d l = ul.v();
const Vector3d x = v();
const double n = l.head(2).norm(); // ||l_h||
const double d_val = v().dot(l) / (abs( v(2))*n);
const double nax2 = n*fabs(x(2));
/* JJx(0) = l(0)/(abs(x(2))*n);
JJx(1) = l(1)/(abs(x(2))*n);
JJx(2) = l(2)/(abs(x(2))*n) -x.dot(l)*sign(x(2))/( abs(x(2))*abs(x(2)) *n);
JJl(0) = x(0)/(abs(x(2))*n) -x.dot(l)*l(0) / (abs(x(2)) *n*n*n);
JJl(1) = x(1)/(abs(x(2))*n) -x.dot(l)*l(1) / (abs(x(2)) *n*n*n);
JJl(2) = x(2)/(abs(x(2))*n);*/
Vector3d JJx;
JJx(0) = l(0)/nax2;
JJx(1) = l(1)/nax2;
JJx(2) = (-l(0)*x(0) -l(1)*x(1))/( x(2)*nax2 );
Vector3d JJl;
JJl(0) = ( (-l(0)*l(1)*x(1) -l(0)*l(2)*x(2) +l(1)*l(1)*x(0) ) *fabs(x(2))) / ( x(2)*x(2)*n*n*n);
JJl(1) = ( ( l(0)*l(0)*x(1) -l(0)*l(1)*x(0) -l(1)*l(2)*x(2) ) *fabs(x(2))) / ( x(2)*x(2)*n*n*n);
JJl(2) = x(2)/nax2;
const double d_var = JJx.dot( Cov() * JJx) + JJl.dot(ul.Cov() * JJl);
return {d_val,d_var};
}
//! Get uncertain point in homogeneous coordinates, Euclidean normalized
uPoint uPoint::euclidean() const
{
const double uu = v(0); // w'=u/w
const double vv = v(1); // v'=v/w
const double ww = v(2); // w'=w/w=1
const Matrix3d JJ {
{ 1/ww, 0, -uu/(ww*ww) },
{ 0, 1/ww, -vv/(ww*ww) },
{ 0, 0, 0 } };
return { v()/v(2), JJ*Cov()*JJ.adjoint() };
}
//! Get uncertain point, transformed via 3x3 transformation matrix
uPoint uPoint::transformed( const Matrix3d & TT) const
{
return {TT*v(), TT*Cov()*TT.adjoint() };
}
//! Check if uncertain straight line 'ul' is incident.
bool uPoint::isIncidentWith( const uStraightLine & ul,
const double T) const
{
const double d = v().dot(ul.v()); // d = x'*l
const double var_d = ul.v().dot(Cov() * ul.v()) + v().dot( ul.Cov() * v()); // uncorrelated
Q_ASSERT( var_d>0. );
return (d*d) / var_d < T;
}
//! Get algebraic distance of 'this' and straight line of 'ul'
uDistance uPoint::distanceAlgebraicTo( const uStraightLine & ul ) const
{
const double d = sign( v(2) ) * v().dot(ul.v());
const Vector3d JJx = ul.v().adjoint();
const Vector3d JJl = sign( v(2) ) * v().adjoint();
// JJ = [l', sign(x(3))*x'];
const double var_d = JJx.dot( Cov() * JJx) + JJl.dot(ul.Cov() * JJl); // uncorrelated
return {d, var_d};
}
//! Get uncertain point in homogeneous coordinates, spherically normalized
uPoint uPoint::sphericalNormalized() const
{
uPoint ux(*this);
ux.normalizeSpherical();
return ux; // Compiler invokes the copy constructor.
}
//! cross product of two vectors representing points, l=cross(x,y)
uStraightLine uPoint::cross( const uPoint & other) const
{
// qDebug() << Q_FUNC_INFO;
const Matrix3d Sx = skew( this->v() );
const Matrix3d Sy = skew( other.v());
const Vector3d m_val = Sx*other.v(); // cross(x,y)
const Matrix3d m_cov = -Sy*this->Cov()*Sy -Sx*other.Cov()*Sx; // S' = -S
Q_ASSERT_X( m_val.norm()>0, Q_FUNC_INFO, "identical points");
assert( isCovMat(m_cov) );
return {m_val, m_cov };
}
} // namespace Uncertain