/* * 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 "udistance.h" #include "upoint.h" #include "usegment.h" #include "ustraightline.h" #include #include #include #include #include using Eigen::Index; using Eigen::Matrix3d; using Eigen::VectorXi; using Eigen::Vector3d; using Eigen::VectorXd; using Eigen::Vector; namespace Uncertain { using Geometry::skew; using Matfun::sign; //! Get uncertain endpoint x=S(l)*m in homogeneous coordinates uPoint uStraightLineSegment::ux() const { const Matrix Sigma_lm = m_Cov_tt.topLeftCorner(6,6); const Matrix3d Sl = skew( hl() ); Matrix JJ; JJ << -skew( hm() ), Sl; // x = Sl*m: return { Sl*hm(), JJ*Sigma_lm*JJ.adjoint() }; } //! Get uncertain endpoint y=S(l)*n in homogeneous coordinates uPoint uStraightLineSegment::uy() const { const Matrix3d Sl = skew( hl() ); Matrix JJ; JJ << -skew( hn() ), Matrix3d::Zero(), Sl; return { Sl*hn(), JJ*Cov_tt()*JJ.adjoint() }; } uStraightLineSegment::uStraightLineSegment( Vector9d t, Matrix9d Sigma_tt) : m_t(std::move(t)), m_Cov_tt(std::move(Sigma_tt)) { m_bounding_box = ux().bbox().united( uy().bbox() ); } //! 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()) ) { static const Matrix3d CC = Vector3d(1,1,0).asDiagonal(); // (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(); assert( l.norm() > FLT_EPSILON && "identical points."); const double xh = ux.v(2); const double yh = uy.v(2); 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; const Matrix3d JJmx = -sign(yh) * (Sx*CC*Sy + skew((CC*l).eval()) ); const Matrix3d JJmy = +sign(yh) * UUx; const Matrix3d JJnx = -sign(xh)*UUy; const Matrix3d JJny = +sign(xh)*( Sy*CC*Sx -skew( (CC*l).eval() )); /* JJ = [ ... JJlx, JJly; ... JJmx, JJmy; ... JJnx, JJny]; */ Matrix JJ; JJ << -Sy, Sx, JJmx, JJmy, JJnx, JJny; Matrix Sigma_xy; Sigma_xy.setZero(); Sigma_xy.topLeftCorner(3,3) = ux.Cov(); Sigma_xy.bottomRightCorner(3,3) = uy.Cov(); m_Cov_tt = JJ*Sigma_xy*JJ.transpose(); } //! Check if the 'this' and the uncertain straight line segment 'ut' intersect (deterministic) bool uStraightLineSegment::intersects( const uStraightLineSegment &ut) const { const double d1 = ut.hx().dot( hl() ); const double d2 = ut.hy().dot( hl() ); if ( d1*d2 >= 0 ) { // same sign? return false; } const double d3 = hx().dot( ut.hl() ); const double d4 = hy().dot( ut.hl() ); return !(d3*d4 >=0 ); } //! 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; } const uDistance ud1 = ux.distanceAlgebraicTo( um() ); // dist(x,m) if ( !ud1.isLessThanZero(T_dist) ) { return false; } const 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 { const Matrix3d Sigma_ll = m_Cov_tt.topLeftCorner(3,3); return { m_t.head(3), Sigma_ll }; } //! Get the delimiting uncertain straight line m in homogeneous coordinates. uStraightLine uStraightLineSegment::um() const { const Matrix3d Sigma_mm = m_Cov_tt.block(3,3,3,3); return { m_t.segment(3,3), Sigma_mm}; } //! Get the delimiting uncertain straight line n in homogeneous coordinates. uStraightLine uStraightLineSegment::un() const { const Matrix3d Sigma_nn = m_Cov_tt.bottomRightCorner(3,3); return { m_t.tail(3), Sigma_nn}; } //! Get the endpoint x in homogeneous coordinates Vector3d uStraightLineSegment::hx() const { const Vector3d l = m_t.head(3); const Vector3d m = m_t.segment(3,3); return skew( l )*m; } //! Get the endpoint y in homogeneous coordinates Vector3d uStraightLineSegment::hy() const { const Vector3d l = m_t.head(3); const Vector3d n = m_t.tail(3); return skew( l )*n; } //! Move endpoint x along l to intersection point of m and l. bool uStraightLineSegment::move_x_to(const Vector3d &m) { const Vector3d l = hl().normalized(); const Vector3d z = l.cross( m.normalized() ); // intersection point z if ( z.norm() < FLT_EPSILON ) { return false; // l==m } const Vector2d dx = x() - z.head(2) / z(2); const Matrix3d HH { { 1, 0, dx(0)}, { 0, 1, dx(1)}, { 0, 0, 1 } }; 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 ............................ const Vector3d l = hl().normalized(); const Vector3d z = l.cross( n.normalized() ); if ( z.norm() < FLT_EPSILON) { return false; // l==n } const Vector2d dx = y() - z.head(2) / z(2); const Matrix3d HH { { 1, 0, dx(0)}, { 0, 1, dx(1)}, { 0, 0, 1 } }; Matrix9d TT = Matrix9d::Identity(); TT.block(6,6,3,3) = HH.adjoint(); // n transform( TT); return true; } //! 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(); } //! Create uncertain straight line segment (for deserialization) std::shared_ptr uStraightLineSegment::create() { return std::shared_ptr( new uStraightLineSegment() ); // return std::make_shared(); // Note from // https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared.html: // // std::shared_ptr(new T(args...)) may call a non-public constructor // of T if executed in context where it is accessible, while // std::make_shared requires public access to the selected constructor. } } // namespace Uncertain