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"
87 template <
typename TPo
int >
92 typedef typename Point::Coordinate
Scalar;
118 second.resize( Point::dimension );
119 for (
auto k = 0; k < Point::dimension; k++ )
120 second[ k ] = Point::base( k );
140 template <
typename TInputPo
int>
143 const double delta = 0.99,
144 const double tolerance = 1e-12 )
147 if ( points.size() == 0 )
return;
149 std::vector< TInputPoint >
basis( points.size() - 1 );
150 for ( std::size_t i = 0; i <
basis.size(); i++ )
177 template <
typename TInputPo
int>
179 const std::vector<TInputPoint>&
basis,
181 bool is_reduced =
false,
182 const double delta = 0.99,
183 const double tolerance = 1e-12 )
188 if ( ! is_reduced )
reduce( type, delta );
206 template <
typename TInputPo
int>
208 const TInputPoint& normal,
210 const double tolerance = 1e-12 )
237 std::vector< Point > X(
second.size()+1 );
239 for (
auto i = 0; i <
second.size(); i++ )
281 trace.
error() <<
"[AffineBasis::isParallel] Requires type=*_ECHELON_REDUCED\n"
283 for (
const auto& b : other.
second )
295 const auto [d, lambda, remainder] =
decompose( p );
296 return std::make_pair( d, lambda );
305 const auto [d, lambda, r] =
decompose( p );
306 return ! Affine::ScalarOps::isNonZero( r.normInfinity(),
epsilon );
316 return ! Affine::ScalarOps::isNonZero( r.normInfinity(),
epsilon );
338 const Point& r = Point::zero )
const
362 const Point& r = Point::zero )
const
365 for ( std::size_t i = 0; i <
second.size(); i++ )
366 w += lambda[ i ] *
second[ i ];
395 for (
auto i = 0; i <
second.size(); i++ )
397 std::pair< Scalar, Scalar > c
399 for (
auto j = 0; j < i; j++ )
405 ? std::make_tuple( alphas, r, w )
406 : std::make_tuple( -alphas, -r, -w );
420 template <
typename ProjectedPo
int>
425 std::vector< Scalar > denoms ( input.size() );
426 std::vector< Point > lambdas( input.size() );
429 for ( std::size_t i = 0; i < input.size(); i++ )
430 std::tie( denoms[ i ], lambdas[ i ], r ) =
decompose( input[ i ] );
432 for ( std::size_t i = 0; i < denoms.size(); i++ )
434 const Scalar d = denoms[ i ];
435 if ( d == 1 )
continue;
436 lcm = Affine::ScalarOps::lcmPositive( lcm, d );
439 result.resize( input.size() );
440 for ( std::size_t i = 0; i < input.size(); i++ )
450 template <
typename OtherPo
int>
454 BOOST_STATIC_ASSERT( OtherPoint::dimension <= Point::dimension );
455 typedef typename OtherPoint::Coordinate
Scalar;
456 for ( std::size_t i = 0; i < pp.dimension; ++i )
457 pp[ i ] =
Scalar( p[ i ] );
467 template <
typename OtherPo
int>
471 BOOST_STATIC_ASSERT( OtherPoint::dimension <= Point::dimension );
472 for ( std::size_t i = 0; i < pp.dimension; ++i )
473 pp[ i ] = m *
Scalar( p[ i ] );
488 out <<
"[ AffineBasis o=" <<
first
491 for (
auto b :
second ) std::cout <<
"\n " << b;
541 std::vector< bool > is_independent(
second.size(),
false );
542 std::vector< std::vector< Scalar > > U(
second.size() );
544 for ( std::size_t i = 0; i <
second.size(); i++ )
547 if ( row != i && row !=
second.size() )
551 is_independent[ i ] =
true;
552 for ( std::size_t j = 0; j < i; j++ )
553 if ( is_independent[ j ] )
555 if ( ! Affine::ScalarOps::isNonZero( w.normInfinity(),
epsilon ) )
556 is_independent[ i ] =
false;
564 for ( std::size_t i = 0; i <
second.size(); i++ )
565 if ( is_independent[ i ] )
566 new_basis.push_back(
second[ i ] );
567 std::swap(
second, new_basis );
579 for (
auto k = 0; k < Point::dimension; ++k )
581 bool v_non_null = Affine::ScalarOps::isNonZero( v[ k ],
epsilon );
582 bool w_non_null = Affine::ScalarOps::isNonZero( w[ k ],
epsilon );
583 if ( v_non_null && ! w_non_null )
return true;
584 else if ( ! v_non_null && w_non_null )
return false;
585 else if ( v_non_null && w_non_null )
return false;
601 if constexpr( std::is_floating_point< Scalar >::value == true )
604 <<
" It has no meaning to use LLL algorithm on matrix with double coefficients\n";
610 std::vector< std::vector< Scalar > >
B(
second.size() );
611 for (
auto i = 0; i <
second.size(); i++ )
613 B[ i ] = std::vector< Scalar >( Point::dimension );
614 for (
auto j = 0; j < Point::dimension; j++ )
615 B[ i ][ j ] =
second[ i ][ j ];
620 for ( std::size_t i = 0; i <
B.size(); i++ )
623 for (
auto j = 0; j < Point::dimension; j++ )
624 b[ j ] =
B[ i ][ j ];
625 if ( b != Point::zero )
636 template <
typename TInputPo
int>
640 for (
auto i = 0; i <
basis.size(); i++ )
643 if ( b != Point::zero )
second.push_back( b );
659 const auto n1_u = u.norm1();
660 const auto n1_v = v.norm1();
661 if ( n1_u < n1_v )
return true;
662 else if ( n1_v < n1_u )
return false;
663 const auto noo_u = u.normInfinity();
664 const auto noo_v = v.normInfinity();
665 if ( noo_u < noo_v )
return true;
666 else if ( noo_v < noo_u )
return false;
687 const std::vector< Point >&
basis )
689 ASSERT( !
basis.empty() );
690 ASSERT( k < Point::dimension );
691 std::size_t
index = i;
696 if ( Affine::ScalarOps::isNonZero( v,
epsilon ) )
699 for (
auto j =
index + 1; j <
basis.size(); j++ )
702 if ( vj != 0 && vj < v )
720template <
typename TPo
int>
724 B.selfDisplay( out );
731#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 ATu0v1< TKSpace, TLinearAlgebra > &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)