DGtal 2.1.0
Loading...
Searching...
No Matches
Affine geometry of points and vectors
Author(s) of this documentation:
Jacques-Olivier Lachaud
Since
2.0

Part of the Geometry package.

This part of the manual describes how to perform some elementary affine geometry computations: affine dimension of a set of points, subset of maximum affine dimension, completion of a partial basis, computation of an orthogonal vector. This module is notably used in QuickHull algorithm.

The following programs are related to this documentation: testAffineGeometry.cpp exampleAffineGeometry.cpp testAffineBasis.cpp

See QuickHull algorithm in arbitrary dimension for convex hull and Delaunay cell complex computation

Generic functions for affine geometry

A set of generic functions is provided in header DGtal/geometry/tools/AffineGeometry.h for several affine geometry computations. They can be conveniently used since they deduce automatically the type of their parameters. All these functions support number types for points and vectors that are either integers (int32_t, int64_t, BigInteger) or floating-point numbers (float, double). The computations are exact when types are integral (up to integer overflow), while a tolerance can be provided for floating-point numbers (default tolerance: between -1e-12 and 1e-12 is zero).

Affine dimension and affine subset

Affine basis and independent vectors

The computed bases are in row echelon form (see Wikipedia ), potentially reduced if components are real-value and nnot integers, except when using completeBasis where the last vector may be asked to be orthogonal to all the others.

Affine basis of codimension 1

Orthogonal vector to basis of codimension 1

Utilities

  • functions::computeSimplifiedVector( const TPoint& v ) Given a vector, returns the aligned vector with its component simplified by the gcd of all components (when the components are integers) or the aligned vector with a maximum oo-norm of 1 (when the components are floating-point numbers).

This example (similar to exampleAffineGeometry.cpp) shows how to process the affine geometry of a set of points that is not full dimensional.

#include "DGtal/base/Common.h"
#include "DGtal/kernel/PointVector.h"
#include "DGtal/geometry/tools/AffineGeometry.h"
template <typename T> std::ostream&
operator<<( std::ostream& out, const std::vector< T >& object )
{ // to display vector<T>
out << "[";
for ( auto t : object ) out << " " << t;
out << " ]";
return out;
}
using namespace DGtal;
int main()
{
std::vector< Point > X = {
Point{21, -29, -21}, Point{-6, 14, 8}, Point{-19, 1, 9},
Point{39, 16, -12}, Point{-26, 29, 23}, Point{-4, 45, 19},
Point{6, 31, 9}, Point{9, 6, -2}, Point{8, 49, 15}
};
std::cout << "Dimension is " << Point::dimension << "\n";
std::cout << "X = " << X << "\n";
std::cout << "Expected dimension of affine set of points X is "
<< (Point::dimension-1) << "\n";
std::cout << "AffineDim(X) = " << functions::computeAffineDimension( X ) << "\n";
std::cout << "AffineSubset(X) = " << I << "\n";
Point o;
std::vector<Point> B;
std::cout << "AffineBasis(X) =: p+B = " << o << " + " << B << "\n";
std::cout << "Independent(X) =: e = " << e << "\n";
std::cout << "Orthogonal(X) =: n = " << n << "\n";
std::cout << "Orthogonal(X)/gcd =: ns = " << ns << "\n";
for ( auto i = 0; i < B.size(); i++ )
std::cout << "B[" << i << "] . ns = " << B[i] << " . " << ns
<< " == " << B[i].dot(ns) << " (should be 0)\n";
}
Aim: Implements basic operations that will be used in Point and Vector classes.
DGtal::int64_t computeAffineDimension(const std::vector< TPoint > &X, const double tolerance=1e-12)
void getAffineBasis(TInputPoint &o, std::vector< TPoint > &basis, const std::vector< TInputPoint > &X, const double tolerance=1e-12)
TPoint computeIndependentVector(const std::vector< TPoint > &basis, const double tolerance=1e-12)
static TPoint computeOrthogonalVectorToBasis(const std::vector< TPoint > &basis)
std::vector< std::size_t > computeAffineSubset(const std::vector< TPoint > &X, const double tolerance=1e-12)
TPoint computeSimplifiedVector(const TPoint &v)
DGtal is the top-level namespace which contains all DGtal functions and types.
std::ostream & operator<<(std::ostream &out, const ClosedIntegerHalfPlane< TSpace > &object)
int main()
Definition testBits.cpp:56
MyPointD Point

outputs

Dimension is 3
X = [ (-5, -25, 0) (19, 22, 7) (0, -19, 0) (-20, -17, 10) (20, 5, 0) (0, -6, 5) (9, 23, 12) (-14, -41, -2) (22, 10, 1) (34, -38, -23) (12, 11, 6) ]
Expected dimension of affine set of points X is 2
AffineDim(X) = 2
AffineSubset(X) = [ 0 1 2 ]
AffineBasis(X) =: p+B = (-5, -25, 0) + [ (24, 47, 7) (0, -13, -5) ]
Independent(X) =: e = (1, 0, 0)
Orthogonal(X) =: n = (-6, 5, -13)
Orthogonal(X)/gcd =: ns = (-6, 5, -13)
B[0] . ns = (24, 47, 7) . (-6, 5, -13) == 0 (should be 0)
B[1] . ns = (0, -13, -5) . (-6, 5, -13) == 0 (should be 0)

Using class AffineGeometry directly

If you need to finetune how affine geometry computations are performed, you may use the static methods of class AffineGeometry directly. The advantage is that you can specify a type for computations that is more precise than the type of input data.

typedef Space::Point Point;
typedef SpaceND<3, int64_t> ComputationSpace;
typedef ComputationSpace::Point ComputationPoint;
...
std::vector<Point> X = { Point{1, 0, 0}, Point{2, 1, 0}, Point{3, 2, 0},
Point{3, 1, 1}, Point{5, 2, 2}, Point{4, 2, 1} };
auto I = Affine::affineSubset( X );
auto B = Affine::affineBasis( X );
auto d = Affine::affineDimension( X );
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...

The same services are provided as AffineGeometry static methods:

affine dimension and affine subset

affine basis and independent vectors

The computed bases are in row echelon form (see Wikipedia ), even reduced row echelon form if components are real-valued and not integers, except when using completeBasis where the last vector may be asked to be orthogonal to all the others.

orthogonal vector to basis of codimension 1

utilities

Reducing a vector onto a basis is a Gaussian elimination but slightly modified to handle integers (in case of lattice points and vectors).

  • AffineGeometry::reductionOnBasis Reduces the vector v on the (partial or not) basis of vectors basis, and returns the part of v that cannot be expressed as a linear combination of vectors of basis, and hence a null vector if v is a linear combination of the vectors of the basis.
  • AffineGeometry::reduceVector Reduces vector w by the vector b, and returns the coefficients \( (\alpha,\beta) \) for reduction such that \( \alpha w - \beta b \) is the returned reduced vector, \( \alpha \ge 0 \).
  • AffineGeometry::simplifiedVector Given a vector, returns the aligned vector with its component simplified by the gcd of all components (when the components are integers) or the aligned vector with unit L2-norm (when the components are floating-point numbers).

Projecting points onto an affine basis

AffineBasis is a convenience class that represents an affine basis (integral or not) in a form chosen by the user: either echelon reduced (AffineBasis::Type::ECHELON_REDUCED) or LLL reduced (AffineBasis::Type::ECHELON_REDUCED). It is mostly useful for projecting points and vectors onto it, and providing a system of coordinates on the affine space.

Warning
For now, you cannot project onto the basis when it is LLL-reduced (AffineBasis::Type::LLL_REDUCED). Use AffineBasis::Type::ECHELON_REDUCED instead.

Constructors

You can construct an affine basis from a set of points or from an origin and arbitrary vectors, while choosing its form in AffineBasis::Type.

Standard services

Geometric services

Projection services

  • AffineBasis::decompose Decomposes a point p into a tuple \( (d,L,R) \), such that: \( d (p - o) = L \cdot B + R \), where R is independent from this basis \( B=(b_0, \ldots, b_i) \), with origin o. d is a scalar, \( L/d \) are the rational coordinates of \( (p-o) \) in the basis, R is the remainer vector. Note that R is not null whenever p does not belong to the affine space.
  • AffineBasis::decomposeVector Same as above but for a vector (ignores the origin).
  • AffineBasis::recompose and AffineBasis::recomposeVector are the inverse functions of the two previous ones.
  • AffineBasis::projectPoints Projects a range of points onto the affine basis and outputs it. It also returns the maximum dilation of projected rational coordinates which was used to create lattice coordinates.

The example below shows how to use AffineBasis to project 4D points onto a 2D affine subspace.

typedef SpaceND< 4, int64_t > Space4;
typedef Space4::Point Point4;
typedef SpaceND< 2, int64_t > Space2;
typedef Space2::Point Point2;
typedef AffineBasis< Point4 > Basis;
...
std::vector< Point4 > V = { Point{ 3, 4, 0, 2 }, Point{ -2, -1, 5, -7 } };
Point4 o( 1,4,2,-1 );
std::vector< Point4 > X = { o, o + V[0], o + V[1], o + 3*V[0] - V[1], o - V[0] + V[1] };
Basis B( X, Basis::Type::SHORTEST_ECHELON_REDUCED ); // affine basis of dimension 2
std::vector< Point2 > proj_X;
auto d = B.projectPoints( proj_X, X ); // proj_X contains the projection of X onto B
// d is the dilatation factor, hence proj_X/d corresponds to rational coordinates
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...
See also
testAffineBasis.cpp

Notes

Several functions that works with lattice vectors use functions specialized to integer computations (defined in math/linalg/IntegerMatrixFunctions.h: