31#if defined(AffineBasis_RECURSES)
32#error Recursive header files inclusion detected in AffineBasis.h
35#define AffineBasis_RECURSES
37#if !defined AffineBasis_h
45#include "DGtal/base/Common.h"
46#include "DGtal/geometry/tools/AffineGeometry.h"
110 template <
typename TPo
int >
115 typedef typename Point::Coordinate
Scalar;
141 second.resize( Point::dimension );
142 for (
auto k = 0; k < Point::dimension; k++ )
143 second[ k ] = Point::base( k );
163 template <
typename TInputPo
int>
166 const double delta = 0.99,
167 const double tolerance = 1e-12 )
170 if ( points.size() == 0 )
return;
172 std::vector< TInputPoint >
basis( points.size() - 1 );
173 for ( std::size_t i = 0; i <
basis.size(); i++ )
200 template <
typename TInputPo
int>
202 const std::vector<TInputPoint>&
basis,
204 bool is_reduced =
false,
205 const double delta = 0.99,
206 const double tolerance = 1e-12 )
211 if ( ! is_reduced )
reduce( type, delta );
229 template <
typename TInputPo
int>
231 const TInputPoint& normal,
233 const double tolerance = 1e-12 )
260 std::vector< Point > X(
second.size()+1 );
262 for (
auto i = 0; i <
second.size(); i++ )
304 trace.
error() <<
"[AffineBasis::isParallel] Requires type=*_ECHELON_REDUCED\n"
306 for (
const auto& b : other.
second )
318 const auto [d, lambda, remainder] =
decompose( p );
319 return std::make_pair( d, lambda );
328 const auto [d, lambda, r] =
decompose( p );
329 return ! Affine::ScalarOps::isNonZero( r.normInfinity(),
epsilon );
339 return ! Affine::ScalarOps::isNonZero( r.normInfinity(),
epsilon );
361 const Point& r = Point::zero )
const
385 const Point& r = Point::zero )
const
388 for ( std::size_t i = 0; i <
second.size(); i++ )
389 w += lambda[ i ] *
second[ i ];
418 for (
auto i = 0; i <
second.size(); i++ )
420 std::pair< Scalar, Scalar > c
422 for (
auto j = 0; j < i; j++ )
428 ? std::make_tuple( alphas, r, w )
429 : std::make_tuple( -alphas, -r, -w );
443 template <
typename ProjectedPo
int>
448 std::vector< Scalar > denoms ( input.size() );
449 std::vector< Point > lambdas( input.size() );
452 for ( std::size_t i = 0; i < input.size(); i++ )
453 std::tie( denoms[ i ], lambdas[ i ], r ) =
decompose( input[ i ] );
455 for ( std::size_t i = 0; i < denoms.size(); i++ )
457 const Scalar d = denoms[ i ];
458 if ( d == 1 )
continue;
459 lcm = Affine::ScalarOps::lcmPositive( lcm, d );
462 result.resize( input.size() );
463 for ( std::size_t i = 0; i < input.size(); i++ )
473 template <
typename OtherPo
int>
477 BOOST_STATIC_ASSERT( OtherPoint::dimension <= Point::dimension );
478 typedef typename OtherPoint::Coordinate
Scalar;
479 for ( std::size_t i = 0; i < pp.dimension; ++i )
480 pp[ i ] =
Scalar( p[ i ] );
490 template <
typename OtherPo
int>
494 BOOST_STATIC_ASSERT( OtherPoint::dimension <= Point::dimension );
495 for ( std::size_t i = 0; i < pp.dimension; ++i )
496 pp[ i ] = m *
Scalar( p[ i ] );
511 out <<
"[ AffineBasis o=" <<
first
514 for (
auto b :
second ) std::cout <<
"\n " << b;
564 std::vector< bool > is_independent(
second.size(),
false );
565 std::vector< std::vector< Scalar > > U(
second.size() );
567 for ( std::size_t i = 0; i <
second.size(); i++ )
570 if ( row != i && row !=
second.size() )
574 is_independent[ i ] =
true;
575 for ( std::size_t j = 0; j < i; j++ )
576 if ( is_independent[ j ] )
578 if ( ! Affine::ScalarOps::isNonZero( w.normInfinity(),
epsilon ) )
579 is_independent[ i ] =
false;
587 for ( std::size_t i = 0; i <
second.size(); i++ )
588 if ( is_independent[ i ] )
589 new_basis.push_back(
second[ i ] );
590 std::swap(
second, new_basis );
602 for (
auto k = 0; k < Point::dimension; ++k )
604 bool v_non_null = Affine::ScalarOps::isNonZero( v[ k ],
epsilon );
605 bool w_non_null = Affine::ScalarOps::isNonZero( w[ k ],
epsilon );
606 if ( v_non_null && ! w_non_null )
return true;
607 else if ( ! v_non_null && w_non_null )
return false;
608 else if ( v_non_null && w_non_null )
return false;
624 if constexpr( std::is_floating_point< Scalar >::value == true )
627 <<
" It has no meaning to use LLL algorithm on matrix with double coefficients\n";
633 std::vector< std::vector< Scalar > >
B(
second.size() );
634 for (
auto i = 0; i <
second.size(); i++ )
636 B[ i ] = std::vector< Scalar >( Point::dimension );
637 for (
auto j = 0; j < Point::dimension; j++ )
638 B[ i ][ j ] =
second[ i ][ j ];
643 for ( std::size_t i = 0; i <
B.size(); i++ )
646 for (
auto j = 0; j < Point::dimension; j++ )
647 b[ j ] =
B[ i ][ j ];
648 if ( b != Point::zero )
659 template <
typename TInputPo
int>
663 for (
auto i = 0; i <
basis.size(); i++ )
666 if ( b != Point::zero )
second.push_back( b );
682 const auto n1_u = u.norm1();
683 const auto n1_v = v.norm1();
684 if ( n1_u < n1_v )
return true;
685 else if ( n1_v < n1_u )
return false;
686 const auto noo_u = u.normInfinity();
687 const auto noo_v = v.normInfinity();
688 if ( noo_u < noo_v )
return true;
689 else if ( noo_v < noo_u )
return false;
710 const std::vector< Point >&
basis )
712 ASSERT( !
basis.empty() );
713 ASSERT( k < Point::dimension );
714 std::size_t
index = i;
719 if ( Affine::ScalarOps::isNonZero( v,
epsilon ) )
722 for (
auto j =
index + 1; j <
basis.size(); j++ )
725 if ( vj != 0 && vj < v )
743template <
typename TPo
int>
747 B.selfDisplay( out );
754#undef AffineBasis_RECURSES
void reduceBasisWithLLL(std::vector< std::vector< TComponent > > &B, TDouble delta=0.75)
DGtal is the top-level namespace which contains all DGtal functions and types.
std::ostream & operator<<(std::ostream &out, const ClosedIntegerHalfPlane< TSpace > &object)
DGtal::uint32_t Dimension
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...
AffineBasis(const TInputPoint &origin, const std::vector< TInputPoint > &basis, AffineBasis::Type type, bool is_reduced=false, const double delta=0.99, const double tolerance=1e-12)
bool isParallel(const Self &other) const
Point recomposeVector(Scalar d, const Point &lambda, const Point &r=Point::zero) const
void reduce(AffineBasis::Type type, double delta)
AffineBasis::Type _type
the type of reduction of the basis.
std::tuple< Scalar, Point, Point > decompose(const Point &p) const
Dimension dimension() const
const Point & origin() const
void selfDisplay(std::ostream &out) const
AffineGeometry< Point > Affine
Points second
the vector basis
AffineBasis< TPoint > Self
std::vector< Point > Points
AffineBasis(const std::vector< TInputPoint > &points, AffineBasis::Type type, const double delta=0.99, const double tolerance=1e-12)
std::tuple< Scalar, Point, Point > decomposeVector(Point w) const
bool isParallel(const Point &w) const
double epsilon
the accepted value below which a floating-point number is 0.
void orderEchelonBasis()
Guarantees that the basis is in echelon form.
static void dilatedTransform(OtherPoint &pp, const Point &p, Scalar m)
AffineBasis(const TInputPoint &origin, const TInputPoint &normal, AffineBasis::Type type=Type::ECHELON_REDUCED, const double tolerance=1e-12)
Point first
the origin of the affine basis
std::size_t findIndexWithSmallestNonNullComponent(Dimension k, std::size_t i, const std::vector< Point > &basis)
@ SHORTEST_ECHELON_REDUCED
echelon matrix starting from shortest vectors
@ LLL_REDUCED
delta-LLL reduced matrix
@ ECHELON_REDUCED
echelon matrix
std::string reductionTypeName() const
Scalar projectPoints(std::vector< ProjectedPoint > &result, const Points &input)
static void transform(OtherPoint &pp, const Point &p)
void reduceAsEchelon(Type type)
Point recompose(Scalar d, const Point &lambda, const Point &r=Point::zero) const
const Points & basis() const
AffineBasis(const double tolerance=1e-12)
std::pair< Scalar, Point > rationalCoordinates(const Point &p) const
bool isOnAffineSpace(const Point &p) const
void initBasis(const std::vector< TInputPoint > &basis)
void reduceAsLLL(double delta, Scalar)
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...
static const Point & transform(const Point &w)
static std::pair< Scalar, Scalar > reduceVector(Point &w, const Point &b, const double tolerance)
static std::vector< Point > orthogonalLatticeBasis(const TInputPoint &N, bool shortened=false)
static Point simplifiedVector(Point v)
static std::pair< Point, Points > affineBasis(const std::vector< TInputPoint > &X, const double tolerance=1e-12)
unsigned int index(DGtal::uint32_t n, unsigned int b)
bool compare(const Range1 &pts, const Range2 &groundTruth)