Loading [MathJax]/extensions/TeX/AMSsymbols.js
DGtal 2.0.0
DGtal::QuickHull< TKernel > Struct Template Reference

Aim: Implements the quickhull algorithm by Barber et al. [9], a famous arbitrary dimensional convex hull computation algorithm. It relies on dedicated geometric kernels for computing and comparing facet geometries. More...

#include <DGtal/geometry/tools/QuickHull.h>

Inheritance diagram for DGtal::QuickHull< TKernel >:
[legend]

Data Structures

struct  Facet

Public Types

enum  { UNASSIGNED = (Index) -1 }
 Label for points that are not assigned to any facet. More...
enum class  Status {
  Uninitialized = 0 , InputInitialized = 1 , SimplexCompleted = 2 , FacetsCompleted = 3 ,
  VerticesCompleted = 4 , AllCompleted = 5 , NotFullDimensional = 10 , InvalidRidge = 11 ,
  InvalidConvexHull = 12
}
 Represents the status of a QuickHull object. More...
typedef TKernel Kernel
typedef Kernel::CoordinatePoint Point
typedef Kernel::CoordinateVector Vector
typedef Kernel::CoordinateScalar Scalar
typedef Kernel::InternalScalar InternalScalar
typedef std::size_t Index
typedef std::size_t Size
typedef std::vector< IndexIndexRange
typedef Kernel::HalfSpace HalfSpace
typedef Kernel::CombinatorialPlaneSimplex CombinatorialPlaneSimplex
typedef std::pair< Index, IndexRidge

Public Member Functions

 BOOST_STATIC_ASSERT ((Point::dimension==Vector::dimension))
Standard services (construction, initialization, accessors)
 QuickHull (const Kernel &K=Kernel(), int dbg=0)
Status status () const
void clear ()
 Clears the object.
Size memory () const
Size nbPoints () const
Size nbFacets () const
Size nbVertices () const
Size nbFiniteFacets () const
Size nbInfiniteFacets () const
Initialization services
template<typename InputPoint>
bool setInput (const std::vector< InputPoint > &input_points, bool remove_duplicates=true)
bool setInitialSimplex (const IndexRange &full_splx)
Convex hull services
bool computeConvexHull (Status target=Status::VerticesCompleted)
bool computeInitialSimplex ()
bool computeFacets ()
bool computeVertices ()
Output services
template<typename OutputPoint>
bool getVertexPositions (std::vector< OutputPoint > &vertex_positions)
bool getVertex2Point (IndexRange &vertex_to_point)
bool getPoint2Vertex (IndexRange &point_to_vertex)
bool getFacetVertices (std::vector< IndexRange > &facet_vertices) const
bool getFacetHalfSpaces (std::vector< HalfSpace > &facet_halfspaces)
Check hull services
bool check ()
bool checkFacets ()
bool checkHull ()
Interface
void selfDisplay (std::ostream &out) const
bool isValid () const

Data Fields

public datas
Kernel kernel
 Kernel that is duplicated for computing facet geometries.
int debug_level
 debug_level from 0:no to 2
std::vector< Pointpoints
 the set of points, indexed as in the array.
IndexRange input2comp
IndexRange comp2input
IndexRange processed_points
 Points already processed (and within the convex hull).
std::vector< Indexassignment
 assignment of points to facets
std::vector< Facetfacets
 the current set of facets.
std::set< Indexdeleted_facets
 set of deleted facets
IndexRange p2v
 point index -> vertex index (or UNASSIGNED)
IndexRange v2p
 vertex index -> point index
Size nb_finite_facets
 Number of finite facets.
Size nb_infinite_facets
 Number of infinite facets (!= 0 only for specific kernels)
std::vector< double > timings
 Timings of the different phases: 0: init, 1: facets, 2: vertices.
std::vector< Sizefacet_counter
 Counts the number of facets with a given number of vertices.

Static Public Attributes

static const Size dimension = Point::dimension

Protected Attributes

protected datas
Status myStatus

protected services

InternalScalar height (const Facet &F, const Point &p) const
bool above (const Facet &F, const Point &p) const
bool aboveOrOn (const Facet &F, const Point &p) const
bool on (const Facet &F, const Point &p) const
void cleanFacets ()
void renumberInfiniteFacets ()
bool processFacet (std::queue< Index > &Q)
bool checkFacet (Index f) const
Index newFacet ()
void deleteFacet (Index f)
void makeNeighbors (const Index if1, const Index if2)
void unmakeNeighbors (const Index if1, const Index if2)
Index mergeParallelFacets (const Index if1, const Index if2)
bool areFacetsParallel (const Index if1, const Index if2) const
bool areFacetsNeighbor (const Index if1, const Index if2) const
Facet makeFacet (const IndexRange &base, Index below) const
IndexRange pointsOnRidge (const Ridge &R) const
IndexRange orientedFacetPoints (Index f) const
void filterVerticesOnFacet (const Index f)
IndexRange pickInitialSimplex () const
bool computeSimplexConfiguration (const IndexRange &full_simplex)
static IndexRange pickIntegers (const Size d, const Size n)

Detailed Description

template<typename TKernel>
struct DGtal::QuickHull< TKernel >

Aim: Implements the quickhull algorithm by Barber et al. [9], a famous arbitrary dimensional convex hull computation algorithm. It relies on dedicated geometric kernels for computing and comparing facet geometries.

Description of template class 'QuickHull'

You can use it to build convex hulls of points with integral coordinate (using kernel ConvexHullIntegralKernel), convex hulls with rational coordinates (using kernel ConvexHullRationalKernel) or to build Delaunay triangulations (using kernels DelaunayIntegralKernel and DelaunayRationalKernel).

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

Below is a complete example that computes the convex hull of points randomly defined in a ball, builds a 3D mesh out of it and output it as an OBJ file.

#include "DGtal/base/Common.h"
#include "DGtal/kernel/PointVector.h"
#include "DGtal/shapes/SurfaceMesh.h"
#include "DGtal/io/writers/SurfaceMeshWriter.h"
#include "QuickHull.h"
using namespace DGtal::Z3i;
int main( int argc, char* argv[] )
{
int nb = argc > 1 ? atoi( argv[ 1 ] ) : 100; // nb points
int R = argc > 2 ? atoi( argv[ 2 ] ) : 10; // x-radius of ellipsoid
// (0) typedefs
typedef DGtal::QuickHull< Kernel3D > QuickHull3D;
// (1) create range of random points in ball
std::vector< Point > V;
const auto R2 = R
for ( int i = 0; i < nb; ) {
Point p( rand() % (2*R+1) - R, rand() % (2*R+1) - R, rand() % (2*R+1) - R );
if ( p.squaredNorm() < R2 ) { V.push_back( p ); i++; }
}
// (2) compute convex hull
QuickHull3D hull;
hull.setInput( V );
std::cout << "#points=" << hull.nbPoints()
<< " #vertices=" << hull.nbVertices()
<< " #facets=" << hull.nbFacets() << std::endl;
// (3) build mesh
std::vector< RealPoint > positions;
hull.getVertexPositions( positions );
std::vector< std::vector< std::size_t > > facets;
SMesh mesh( positions.cbegin(), positions.cend(), facets.cbegin(), facets.cend() );
// (4) output result as OBJ file
std::ofstream out( "qhull.obj" );
::writeOBJ( out, mesh );
out.close();
return 0;
}
SurfaceMesh< RealPoint, RealVector > SMesh
Z3i this namespace gathers the standard of types for 3D imagery.
bool setInput(const std::vector< InputPoint > &input_points, bool remove_duplicates=true)
Definition QuickHull.h:382
std::vector< Facet > facets
the current set of facets.
Definition QuickHull.h:814
bool getFacetVertices(std::vector< IndexRange > &facet_vertices) const
Definition QuickHull.h:666
Kernel::CoordinatePoint Point
Definition QuickHull.h:142
Size nbVertices() const
Definition QuickHull.h:337
bool getVertexPositions(std::vector< OutputPoint > &vertex_positions)
Definition QuickHull.h:612
Size nbFacets() const
Definition QuickHull.h:328
bool computeConvexHull(Status target=Status::VerticesCompleted)
Definition QuickHull.h:460
Size nbPoints() const
Definition QuickHull.h:323
Aim: An helper class for writing mesh file formats (Waverfront OBJ at this point) and creating a Surf...
Aim: Represents an embedded mesh as faces and a list of vertices. Vertices may be shared among faces ...
Definition SurfaceMesh.h:92
int main()
Definition testBits.cpp:56
Note
In opposition with the usual QuickHull implementation, this class uses a kernel that can be chosen in order to provide exact computations. This is the case for lattice points.
In opposition with CGAL 3D convex hull package, or with the arbitrary dimensional dD Triangulation package, this algorithm does not build a simplicial convex hull. Facets may not be trangles or simplices in higher dimensions.
This version is generally more than twice faster than CGAL convex_hull_3 for the usual CGAL kernels Cartesian and Exact_predicates_inexact_constructions_kernel.
However this implementation is not tailored for incremental dynamic convex hull computations.
Template Parameters
TKernelany type of QuickHull kernel, like ConvexHullIntegralKernel.
Examples
geometry/tools/checkLatticeBallQuickHull.cpp, and geometry/tools/exampleLatticeBallDelaunay2D.cpp.

Definition at line 139 of file QuickHull.h.

Member Typedef Documentation

◆ CombinatorialPlaneSimplex

template<typename TKernel>
typedef Kernel::CombinatorialPlaneSimplex DGtal::QuickHull< TKernel >::CombinatorialPlaneSimplex

Definition at line 151 of file QuickHull.h.

◆ HalfSpace

template<typename TKernel>
typedef Kernel::HalfSpace DGtal::QuickHull< TKernel >::HalfSpace

Definition at line 150 of file QuickHull.h.

◆ Index

template<typename TKernel>
typedef std::size_t DGtal::QuickHull< TKernel >::Index

Definition at line 146 of file QuickHull.h.

◆ IndexRange

template<typename TKernel>
typedef std::vector< Index > DGtal::QuickHull< TKernel >::IndexRange

Definition at line 149 of file QuickHull.h.

◆ InternalScalar

template<typename TKernel>
typedef Kernel::InternalScalar DGtal::QuickHull< TKernel >::InternalScalar

Definition at line 145 of file QuickHull.h.

◆ Kernel

template<typename TKernel>
typedef TKernel DGtal::QuickHull< TKernel >::Kernel

Definition at line 141 of file QuickHull.h.

◆ Point

template<typename TKernel>
typedef Kernel::CoordinatePoint DGtal::QuickHull< TKernel >::Point

Definition at line 142 of file QuickHull.h.

◆ Ridge

template<typename TKernel>
typedef std::pair< Index, Index > DGtal::QuickHull< TKernel >::Ridge

A ridge for point p is a pair of facets, such that p is visible from first facet, but not from second facet.

Definition at line 236 of file QuickHull.h.

◆ Scalar

template<typename TKernel>
typedef Kernel::CoordinateScalar DGtal::QuickHull< TKernel >::Scalar

Definition at line 144 of file QuickHull.h.

◆ Size

template<typename TKernel>
typedef std::size_t DGtal::QuickHull< TKernel >::Size

Definition at line 147 of file QuickHull.h.

◆ Vector

template<typename TKernel>
typedef Kernel::CoordinateVector DGtal::QuickHull< TKernel >::Vector

Definition at line 143 of file QuickHull.h.

Member Enumeration Documentation

◆ anonymous enum

template<typename TKernel>
anonymous enum

Label for points that are not assigned to any facet.

Enumerator
UNASSIGNED 

Definition at line 155 of file QuickHull.h.

155{ UNASSIGNED = (Index) -1 };
std::size_t Index
Definition QuickHull.h:146

◆ Status

template<typename TKernel>
enum class DGtal::QuickHull::Status
strong

Represents the status of a QuickHull object.

Enumerator
Uninitialized 

QuickHull is empty and has just been instantiated.

InputInitialized 

A range of input points has been given to QuickHull.

SimplexCompleted 

An initial full-dimensional simplex has been found. QuickHull core algorithm can start.

FacetsCompleted 

All facets of the convex hull are identified.

VerticesCompleted 

All vertices of the convex hull are determined.

AllCompleted 

Same as VerticesCompleted.

NotFullDimensional 

Error: the initial simplex is not full dimensional.

InvalidRidge 

Error: some ridge is not consistent (probably integer overflow).

InvalidConvexHull 

Error: the convex hull does not contain all its points (probably integer overflow).

Definition at line 239 of file QuickHull.h.

239 {
240 Uninitialized = 0,
241 InputInitialized = 1,
242 SimplexCompleted = 2,
243 FacetsCompleted = 3,
244 VerticesCompleted = 4,
245 AllCompleted = 5,
246 NotFullDimensional= 10,
247 InvalidRidge = 11,
248 InvalidConvexHull = 12
249 };

Constructor & Destructor Documentation

◆ QuickHull()

template<typename TKernel>
DGtal::QuickHull< TKernel >::QuickHull ( const Kernel & K = Kernel(),
int dbg = 0 )
inline

Default constructor

Parameters
[in]Ka kernel for computing facet geometries.
[in]dbgthe trace level, from 0 (no) to 3 (very verbose).

Definition at line 259 of file QuickHull.h.

261 {}
Kernel kernel
Kernel that is duplicated for computing facet geometries.
Definition QuickHull.h:798
int debug_level
debug_level from 0:no to 2
Definition QuickHull.h:800
@ Uninitialized
QuickHull is empty and has just been instantiated.
Definition QuickHull.h:240

Member Function Documentation

◆ above()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::above ( const Facet & F,
const Point & p ) const
inlineprotected
Parameters
Fany valid facet
pany point
Returns
'true' iff p is above F.

Definition at line 856 of file QuickHull.h.

857 { return kernel.above( F.H, p ); }

Referenced by DGtal::QuickHull< Kernel3D >::checkFacet(), DGtal::QuickHull< Kernel3D >::checkHull(), DGtal::QuickHull< Kernel3D >::computeSimplexConfiguration(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ aboveOrOn()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::aboveOrOn ( const Facet & F,
const Point & p ) const
inlineprotected
Parameters
Fany valid facet
pany point
Returns
'true' iff p is above F or on F.

Definition at line 862 of file QuickHull.h.

863 { return kernel.aboveOrOn( F.H, p ); }

Referenced by DGtal::QuickHull< Kernel3D >::checkFacet(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ areFacetsNeighbor()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::areFacetsNeighbor ( const Index if1,
const Index if2 ) const
inlineprotected

Checks if two facets are neighbors by looking at the points on their boundary.

Parameters
if1a valid facet index
if2a valid facet index
Returns
'true' if the two facets have enough common points to be direct neighbors.

Definition at line 1267 of file QuickHull.h.

1268 {
1269 const Facet& f1 = facets[ if1 ];
1270 const Facet& f2 = facets[ if2 ];
1271 Index nb = 0;
1272 for ( Index i1 = 0, i2 = 0; i1 < f1.on_set.size() && i2 < f2.on_set.size(); )
1273 {
1274 if ( f1.on_set[ i1 ] == f2.on_set[ i2 ] ) { nb++; i1++; i2++; }
1275 else if ( f1.on_set[ i1 ] < f2.on_set[ i2 ] ) i1++;
1276 else i2++;
1277 }
1278 return nb >= ( dimension - 1 );
1279 }
static const Size dimension
Definition QuickHull.h:152

Referenced by DGtal::QuickHull< Kernel3D >::checkFacet(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ areFacetsParallel()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::areFacetsParallel ( const Index if1,
const Index if2 ) const
inlineprotected

Checks if two distinct facets are parallel (i.e. should be merged).

Parameters
if1a valid facet index
if2a valid facet index
Returns
'true' if the two facets are parallel.

Definition at line 1248 of file QuickHull.h.

1249 {
1250 ASSERT( if1 != if2 );
1251 const Facet& f1 = facets[ if1 ];
1252 const Facet& f2 = facets[ if2 ];
1253 if ( kernel.equal( f1.H, f2.H ) ) return true;
1254 // Need to check if one N is a multiple of the other.
1255 for ( auto&& v : f1.on_set )
1256 if ( ! on( f2, points[ v ] ) ) return false;
1257 return true;
1258 }
bool on(const Facet &F, const Point &p) const
Definition QuickHull.h:868
std::vector< Point > points
the set of points, indexed as in the array.
Definition QuickHull.h:802

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ BOOST_STATIC_ASSERT()

template<typename TKernel>
DGtal::QuickHull< TKernel >::BOOST_STATIC_ASSERT ( (Point::dimension==Vector::dimension) )

◆ check()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::check ( )
inline

Global validity check of the convex hull after processing.

Note
Be careful, this function is much slower than computing the convex hull. It can take a long time since its complexity is \( O(n f ) \), where n is the number of input points and f the number of facets.

Definition at line 715 of file QuickHull.h.

716 {
717 bool ok = true;
719 trace.warning() << "[Quickhull::check] invalid status="
720 << (int)status() << std::endl;
721 ok = false;
722 }
723 if ( processed_points.size() != points.size() ) {
724 trace.warning() << "[Quickhull::check] not all points processed: "
725 << processed_points.size() << " / " << points.size()
726 << std::endl;
727 ok = false;
728 }
729 if ( ! checkHull() ) {
730 trace.warning() << "[Quickhull::check] Check hull is invalid. "
731 << std::endl;
732 ok = false;
733 }
734 if ( ! checkFacets() ) {
735 trace.warning() << "[Quickhull::check] Check facets is invalid. "
736 << std::endl;
737 ok = false;
738 }
739 return ok;
740 }
IndexRange processed_points
Points already processed (and within the convex hull).
Definition QuickHull.h:810
Status status() const
Definition QuickHull.h:266
@ FacetsCompleted
All facets of the convex hull are identified.
Definition QuickHull.h:243
@ AllCompleted
Same as VerticesCompleted.
Definition QuickHull.h:245

◆ checkFacet()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::checkFacet ( Index f) const
inlineprotected
Returns
true if the facet is valid

Definition at line 1136 of file QuickHull.h.

1137 {
1138 const Facet& F = facets[ f ];
1139 bool ok = F.on_set.size() >= dimension;
1140 for ( auto v : F.on_set )
1141 if ( ! on( F, points[ v ] ) ) {
1142 trace.error() << "[QuickHull::checkFacet( " << f
1143 << ") Invalid 'on' vertex " << v << std::endl;
1144 ok = false;
1145 }
1146 if ( F.neighbors.size() < dimension ) {
1147 trace.error() << "[QuickHull::checkFacet( " << f
1148 << ") Not enough neighbors " << F.neighbors.size() << std::endl;
1149 ok = false;
1150 }
1151 for ( auto nf : F.neighbors )
1152 if ( ! areFacetsNeighbor( f, nf ) ) {
1153 trace.error() << "[QuickHull::checkFacet( " << f
1154 << ") Invalid neighbor " << nf << std::endl;
1155 ok = false;
1156 }
1157 if ( aboveOrOn( F, points[ F.below ] ) ) {
1158 trace.error() << "[QuickHull::checkFacet( " << f
1159 << ") Bad below point " << F.below << std::endl;
1160 ok = false;
1161 }
1162 for ( auto ov : F.outside_set )
1163 if ( ! above( F, points[ ov ] ) ) {
1164 trace.error() << "[QuickHull::checkFacet( " << f
1165 << ") Bad outside point " << ov << std::endl;
1166 ok = false;
1167 }
1168 for ( auto && v : F.on_set ) {
1169 Size n = 0;
1170 for ( auto&& N : facets[ f ].neighbors )
1171 if ( on( facets[ N ], points[ v ] ) ) n += 1;
1172 if ( n < dimension-1 ) {
1173 trace.error() << "[QuickHull::checkFacet( " << f << ") 'on' point " << v
1174 << " is a vertex of " << n << " facets "
1175 << "(should be >= " << dimension-1 << ")" << std::endl;
1176 ok = false;
1177 }
1178 }
1179 return ok;
1180 }
bool areFacetsNeighbor(const Index if1, const Index if2) const
Definition QuickHull.h:1267
std::size_t Size
Definition QuickHull.h:147
bool aboveOrOn(const Facet &F, const Point &p) const
Definition QuickHull.h:862
bool above(const Facet &F, const Point &p) const
Definition QuickHull.h:856

Referenced by DGtal::QuickHull< Kernel3D >::checkFacets(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ checkFacets()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::checkFacets ( )
inline
Returns
'true' if all facets are consistent with their neighors

Definition at line 743 of file QuickHull.h.

744 {
745 Size nb = 0;
746 Size nbok = 0;
747 for ( Index f = 0; f < facets.size(); ++f )
748 if ( deleted_facets.count( f ) == 0 ) {
749 bool ok = checkFacet( f );
750 nbok += ok ? 1 : 0;
751 nb += 1;
752 }
753 return nb == nbok;
754 }
bool checkFacet(Index f) const
Definition QuickHull.h:1136
std::set< Index > deleted_facets
set of deleted facets
Definition QuickHull.h:816

Referenced by DGtal::QuickHull< Kernel3D >::check(), DGtal::QuickHull< Kernel3D >::computeSimplexConfiguration(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ checkHull()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::checkHull ( )
inline
Returns
'true' iff the current set of facets encloses all the points
Note
Be careful, this function is much slower than computing the convex hull. It can take a long time since its complexity is \( O(n f ) \), where n is the number of input points and f the number of facets.

Definition at line 762 of file QuickHull.h.

763 {
764 Index nbok = 0;
765 // for ( Index v = 0; v < points.size(); ++v ) {
766 for ( auto v : processed_points ) {
767 bool ok = true;
768 for ( Index f = 0; f < facets.size(); ++f )
769 if ( deleted_facets.count( f ) == 0 ) {
770 if ( above( facets[ f ], points[ v ] ) ) {
771 ok = false;
772 trace.error() << "- bad vertex " << v << " " << points[ v ]
773 << " dist="
774 << ( kernel.height( facets[ f ].H, points[ v ] ) )
775 << std::endl;
776 break;
777 }
778 }
779 nbok += ok ? 1 : 0;
780 }
781 if ( debug_level >= 2 ) {
782 trace.info() << nbok << "/"
783 << processed_points.size() << " vertices inside convex hull."
784 << std::endl;
785 }
787 return nbok == processed_points.size();
788 }
@ InvalidConvexHull
Error: the convex hull does not contain all its points (probably integer overflow).
Definition QuickHull.h:248

Referenced by DGtal::QuickHull< Kernel3D >::check(), DGtal::QuickHull< Kernel3D >::computeSimplexConfiguration(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ cleanFacets()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::cleanFacets ( )
inlineprotected

Cleans and renumber the facets so that no one belongs to deleted_facets.

Definition at line 873 of file QuickHull.h.

874 {
875 if ( deleted_facets.empty() ) return;
876 IndexRange renumbering( facets.size() );
877 Index i = 0;
878 Index j = 0;
879 for ( auto& l : renumbering ) {
880 if ( ! deleted_facets.count( j ) ) l = i++;
881 else l = UNASSIGNED;
882 j++;
883 }
884 const Index nf = facets.size() - deleted_facets.size();
885 deleted_facets.clear();
886 for ( Index f = 0; f < facets.size(); f++ )
887 if ( ( renumbering[ f ] != UNASSIGNED ) && ( f != renumbering[ f ] ) )
888 facets[ renumbering[ f ] ] = facets[ f ];
889 facets.resize( nf );
890 for ( auto& F : facets ) {
891 for ( auto& N : F.neighbors ) {
892 if ( renumbering[ N ] == UNASSIGNED )
893 trace.error() << "Invalid deleted neighboring facet." << std::endl;
894 else N = renumbering[ N ];
895 }
896 }
897 }
std::vector< Index > IndexRange
Definition QuickHull.h:149

Referenced by DGtal::QuickHull< Kernel3D >::computeFacets().

◆ clear()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::clear ( )
inline

Clears the object.

Definition at line 270 of file QuickHull.h.

271 {
273 points.clear();
274 processed_points.clear();
275 input2comp.clear();
276 comp2input.clear();
277 assignment.clear();
278 facets.clear();
279 deleted_facets.clear();
280 p2v.clear();
281 v2p.clear();
282 timings.clear();
283 }
IndexRange v2p
vertex index -> point index
Definition QuickHull.h:820
IndexRange input2comp
Definition QuickHull.h:805
std::vector< Index > assignment
assignment of points to facets
Definition QuickHull.h:812
IndexRange p2v
point index -> vertex index (or UNASSIGNED)
Definition QuickHull.h:818
IndexRange comp2input
Definition QuickHull.h:808
std::vector< double > timings
Timings of the different phases: 0: init, 1: facets, 2: vertices.
Definition QuickHull.h:826

Referenced by DGtal::QuickHull< Kernel3D >::setInput().

◆ computeConvexHull()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::computeConvexHull ( Status target = Status::VerticesCompleted)
inline

Computes the convex hull of the given range of points until a specified target:

  • Status::SimplexCompleted: an initial full dimensional simplex is determined.
  • Status::FacetsCompleted: all the facets of the convex hull are extracted (core of quickhull). You can stop here if you only need an H-representation of the output polytope.
  • Status::VerticesCompleted: all the vertices of the hull are determined and are consistently ordered on each facet. You need to stop here if you need a V-representation of the output polytope.
Precondition
status() must be at least Status::InputInitialized
Parameters
[in]targetthe computation target in Status::SimplexCompleted, Status::FacetsCompleted, Status::VerticesCompleted.
Returns
'true' if the computation target has been successfully achieved, 'false' if the achieved status is not the one specified.

Definition at line 460 of file QuickHull.h.

461 {
463 return false;
464 Clock tic;
466 { // Initialization
467 tic.startClock();
468 bool ok1 = computeInitialSimplex();
469 timings.push_back( tic.stopClock() );
470 if ( ! ok1 ) return false;
471 if ( status() == target ) return true;
472 }
474 { // Computes facets
475 tic.startClock();
476 bool ok2 = computeFacets();
477 timings.push_back( tic.stopClock() );
478 if ( ! ok2 ) return false;
479 if ( status() == target ) return true;
480 }
482 { // Computes vertices
483 tic.startClock();
484 bool ok3 = computeVertices();
485 timings.push_back( tic.stopClock() );
486 if ( ! ok3 ) return false;
487 if ( status() == target ) return true;
488 }
491 { // for now, Status::VerticesCompleted and
492 // Status::AllCompleted are the same.
494 return true;
495 }
496 return false;
497 }
bool computeInitialSimplex()
Definition QuickHull.h:504
bool computeFacets()
Definition QuickHull.h:523
bool computeVertices()
Definition QuickHull.h:553
@ SimplexCompleted
An initial full-dimensional simplex has been found. QuickHull core algorithm can start.
Definition QuickHull.h:242
@ VerticesCompleted
All vertices of the convex hull are determined.
Definition QuickHull.h:244
@ InputInitialized
A range of input points has been given to QuickHull.
Definition QuickHull.h:241

Referenced by main().

◆ computeFacets()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::computeFacets ( )
inline

Computes the facets of the convex hull using Quickhull algorithm. If everything went well, the status is Status::FacetsCompleted afterwards.

Precondition
the status shoud be Status::SimplexCompleted (computeInitialSimplex should have been called).
Returns
'true' except if the status is not Initialized when called.

Definition at line 523 of file QuickHull.h.

524 {
525 if ( status() != Status::SimplexCompleted ) return false;
527 for ( Index fi = 0; fi < facets.size(); ++fi )
528 Q.push( fi );
529 Index n = 0;
530 while ( processFacet( Q ) ) {
531 if ( debug_level >= 1 )
532 trace.info() << "---- Iteration " << n++ << " #Q=" << Q.size() << std::endl;
533 }
534 cleanFacets();
535 if ( debug_level >= 2 ) {
536 trace.info() << ".... #facets=" << facets.size()
537 << " #deleted=" << deleted_facets.size() << std::endl;
538 }
540 return true;
541 }
bool processFacet(std::queue< Index > &Q)
Definition QuickHull.h:944

Referenced by DGtal::QuickHull< Kernel3D >::computeConvexHull().

◆ computeInitialSimplex()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::computeInitialSimplex ( )
inline

Computes the initial full dimensional simplex from the input data.

Returns
'true' iff the input data contains d+1 points in general position, the object has then the status SimplexCompleted, otherwise returns 'false' and the status is NotFullDimensional.

Definition at line 504 of file QuickHull.h.

505 {
506 const auto full_simplex = pickInitialSimplex();
507 if ( full_simplex.empty() ) {
509 return false;
510 }
512 }
bool computeSimplexConfiguration(const IndexRange &full_simplex)
Definition QuickHull.h:1429
IndexRange pickInitialSimplex() const
Definition QuickHull.h:1372
@ NotFullDimensional
Error: the initial simplex is not full dimensional.
Definition QuickHull.h:246

Referenced by DGtal::QuickHull< Kernel3D >::computeConvexHull().

◆ computeSimplexConfiguration()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::computeSimplexConfiguration ( const IndexRange & full_simplex)
inlineprotected

Computes the initial configuration induced by the given full dimensional simplex. Follows Status::InputInitialized and and terminate with Status::SimplexCompleted if everything went well.

Returns
'true' iff the input data contains d+1 points in general position, the object has then the status SimplexCompleted, otherwise returns 'false' and the status is NotFullDimensional.

Definition at line 1429 of file QuickHull.h.

1430 {
1432 facets.resize( dimension + 1 );
1433 deleted_facets.clear();
1434 for ( Index j = 0; j < full_simplex.size(); ++j )
1435 {
1438 Index s = 0;
1439 for ( Index i = 0; i <= dimension; i++ )
1440 if ( i != j ) {
1441 lsimplex[ s ] = i;
1442 isimplex[ s ] = full_simplex[ i ];
1443 s++;
1444 }
1446 facets[ j ].neighbors = lsimplex;
1447 for ( auto&& v : isimplex ) facets[ j ].on_set.push_back( v );
1448 std::sort( facets[ j ].on_set.begin(), facets[ j ].on_set.end() );
1449 }
1450 // List of unassigned vertices
1451 for ( Index fi = 0; fi < facets.size(); ++fi ) {
1452 Facet& f = facets[ fi ];
1453 for ( Index v = 0; v < points.size(); v++ )
1454 {
1455 if ( assignment[ v ] == UNASSIGNED && above( f, points[ v ] ) ) {
1456 f.outside_set.push_back( v );
1457 assignment[ v ] = fi;
1458 }
1459 }
1460 }
1461 for ( Index v = 0; v < points.size(); v++ )
1462 if ( assignment[ v ] == UNASSIGNED )
1463 processed_points.push_back( v );
1464
1465 // Display some information
1466 if ( debug_level >= 2 ) {
1467 for ( auto&& f : facets ) f.display( trace.info() );
1468 }
1470 if ( debug_level >= 1 ) {
1471 trace.info() << "[CHECK INVARIANT] " << processed_points.size()
1472 << " / " << points.size() << " points processed." << std::endl;
1473 bool okh = checkHull();
1474 if ( ! okh )
1475 trace.error() << "[computeInitialSimplex] Invalid convex hull" << std::endl;
1476 bool okf = checkFacets();
1477 if ( ! okf )
1478 trace.error() << "[computeInitialSimplex] Invalid facets" << std::endl;
1479 if ( ! ( okh && okf ) ) myStatus = Status::InvalidConvexHull;
1480 }
1481 return status() == Status::SimplexCompleted;
1482 }
Facet makeFacet(const IndexRange &base, Index below) const
Definition QuickHull.h:1292

Referenced by DGtal::QuickHull< Kernel3D >::computeInitialSimplex(), and DGtal::QuickHull< Kernel3D >::setInitialSimplex().

◆ computeVertices()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::computeVertices ( )
inline

Computes the vertices of the convex hull once the facets have been computed. It computes for each facet its vertices and reorder them so that, taken in order, their orientation matches the orientation of the facet. If everything went well, the status is Status::VerticesCompleted afterwards.

Precondition
the status shoud be Status::FacetsCompleted (computeFacets should have been called).
Returns
'true' except if the status is not FacetsCompleted when called.

Definition at line 553 of file QuickHull.h.

554 {
555 static const int MAX_NB_VPF = 10 * dimension;
556 if ( status() != Status::FacetsCompleted ) return false;
557
558 // Renumber infinite facets in case of Delaunay triangulation computation.
560
561 // Builds the maps v2p: vertex -> point, and p2v : point -> vertex.
563 v2p.clear();
564 p2v.resize( points.size() );
566 for ( Index f = 0; f < facets.size(); ++f ) {
567 for ( auto&& p : facets[ f ].on_set ) p2f[ p ].push_back( f );
568 }
569
570 // vertices belong to at least d facets
571 Index v = 0;
572 for ( Index p = 0; p < points.size(); ++p ) {
573 const auto nbf = p2f[ p ].size();
574 facet_counter[ std::min( (int) nbf, MAX_NB_VPF-1 ) ] += 1;
575 if ( nbf >= dimension ) {
576 v2p.push_back( p );
577 p2v[ p ] = v++;
578 }
579 else p2v[ p ] = UNASSIGNED;
580 }
581
582 // Display debug informations
583 if ( debug_level >= 1 ) {
584 trace.info() << "#vertices=" << v2p.size() << " #facets=" << facets.size()
585 << std::endl;
586 trace.info() << "#inc_facets/point= ";
587 for ( auto n : facet_counter ) trace.info() << n << " ";
588 trace.info() << std::endl;
589 }
591 return true;
592 }
std::vector< Size > facet_counter
Counts the number of facets with a given number of vertices.
Definition QuickHull.h:828
void renumberInfiniteFacets()
Definition QuickHull.h:901

Referenced by DGtal::QuickHull< Kernel3D >::computeConvexHull().

◆ deleteFacet()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::deleteFacet ( Index f)
inlineprotected

Deletes the given facet f.

Parameters
fa valid facet index

Definition at line 1193 of file QuickHull.h.

1194 {
1195 for ( auto n : facets[ f ].neighbors )
1196 facets[ n ].subNeighbor( f );
1197 deleted_facets.insert( f );
1198 facets[ f ].clear();
1199 }

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ filterVerticesOnFacet()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::filterVerticesOnFacet ( const Index f)
inlineprotected

Filters each vertex on the facet f to keep only the ones that are on or below the neighboring facets

Note
intended for debugging purposes.
Parameters
[in]fany valid facet index.

Definition at line 1352 of file QuickHull.h.

1353 {
1354 auto & on_set = facets[ f ].on_set;
1355 for ( Index i = 0; i < on_set.size(); )
1356 {
1357 Index v = on_set[ i ];
1358 Size n = 0;
1359 for ( auto&& N : facets[ f ].neighbors )
1360 if ( on( facets[ N ], points[ v ] ) ) n += 1;
1361 if ( n >= dimension-1 ) i++;
1362 else {
1363 on_set[ i ] = on_set.back();
1364 on_set.pop_back();
1365 }
1366 }
1367 std::sort( on_set.begin(), on_set.end() );
1368 }

◆ getFacetHalfSpaces()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::getFacetHalfSpaces ( std::vector< HalfSpace > & facet_halfspaces)
inline

This methods return the halfspaces corresponding to each facet. It is useful to build a polytope.

Parameters
[out]facet_halfspacesthe range giving for each facet its halfspace as a pair (normal, intercept).
Returns
'true' if the convex hull was computed before and status() was Status::FacetsCompleted, Status::VerticesCompleted or Status::AllCompleted, 'false' otherwise.

Definition at line 690 of file QuickHull.h.

691 {
693 if ( ! ( status() >= Status::FacetsCompleted
694 && status() <= Status::AllCompleted ) ) return false;
695 facet_halfspaces.reserve( nbFacets() );
696 for ( Index f = 0; f < nbFacets(); ++f ) {
697 facet_halfspaces.push_back( facets[ f ].H );
698 }
699 return true;
700 }
void clear()
Clears the object.
Definition QuickHull.h:270

◆ getFacetVertices()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::getFacetVertices ( std::vector< IndexRange > & facet_vertices) const
inline
Parameters
[out]facet_verticesthe range giving for each facet the indices of its vertices.
Returns
'true' if the convex hull was computed before and status() was Status::VerticesCompleted or Status::AllCompleted, 'false' otherwise.

Definition at line 666 of file QuickHull.h.

667 {
670 && status() <= Status::AllCompleted ) ) return false;
671 facet_vertices.reserve( nbFacets() );
672 for ( Index f = 0; f < nbFacets(); ++f ) {
674 for ( auto& v : ofacet ) v = p2v[ v ];
675 facet_vertices.push_back( ofacet );
676 }
677 return true;
678 }
IndexRange orientedFacetPoints(Index f) const
Definition QuickHull.h:1323

Referenced by main().

◆ getPoint2Vertex()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::getPoint2Vertex ( IndexRange & point_to_vertex)
inline

Gets for each point its index in the output range of vertices (or UNASSIGNED if the point is not part of the convex hull)

Parameters
[out]point_to_vertexthe range giving for each point its index in the output range of vertices (or UNASSIGNED if the point is not part of the convex hull)
Returns
'true' if the convex hull was computed before and status() was Status::VerticesCompleted or Status::AllCompleted, 'false' otherwise.

Definition at line 651 of file QuickHull.h.

652 {
655 && status() <= Status::AllCompleted ) ) return false;
657 return true;
658 }

◆ getVertex2Point()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::getVertex2Point ( IndexRange & vertex_to_point)
inline

Gets for each vertex its index in the input range of points.

Parameters
[out]vertex_to_pointthe range giving for each vertex its index in the input range of points.
Returns
'true' if the convex hull was computed before and status() was Status::VerticesCompleted or Status::AllCompleted, 'false' otherwise.

Definition at line 632 of file QuickHull.h.

633 {
636 && status() <= Status::AllCompleted ) ) return false;
638 return true;
639 }

◆ getVertexPositions()

template<typename TKernel>
template<typename OutputPoint>
bool DGtal::QuickHull< TKernel >::getVertexPositions ( std::vector< OutputPoint > & vertex_positions)
inline

Gets the positions of the convex hull vertices.

Template Parameters
OutputPointa model of point such that the Point datatype is convertible to it.
Parameters
[out]vertex_positionsthe range of vertex positions.
Returns
'true' if the convex hull was computed before and status() was Status::VerticesCompleted or Status::AllCompleted, 'false' otherwise.

Definition at line 612 of file QuickHull.h.

613 {
616 && status() <= Status::AllCompleted ) ) return false;
617 vertex_positions.resize( v2p.size() );
618 for ( Index i = 0; i < v2p.size(); i++ ) {
619 kernel.convertPointTo( points[ v2p[ i ] ], vertex_positions[ i ] );
620 }
621 return true;
622 }

Referenced by main().

◆ height()

template<typename TKernel>
InternalScalar DGtal::QuickHull< TKernel >::height ( const Facet & F,
const Point & p ) const
inlineprotected
Parameters
Fany valid facet
pany point
Returns
the height of p wrt F (0: on, >0: above ).

Definition at line 850 of file QuickHull.h.

851 { return kernel.height( F.H, p ); }

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ isValid()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::isValid ( ) const
inline

Checks the validity/consistency of the object.

Returns
'true' if the object is valid, 'false' otherwise.

Definition at line 1515 of file QuickHull.h.

1516 {
1517 return status() >= Status::Uninitialized
1519 }

◆ makeFacet()

template<typename TKernel>
Facet DGtal::QuickHull< TKernel >::makeFacet ( const IndexRange & base,
Index below ) const
inlineprotected

Builds a facet from a base convex set of at least d different points and a point below.

Parameters
[in]basea range containing at least d distinct points in general position.
[in]belowa point below the hyperplane containing simplex.
Returns
a facet object of normal and c parameter such as the points of simplex lies on the facet hyperplane while point below lies under.

Definition at line 1292 of file QuickHull.h.

1293 {
1295 for ( Size i = 0; i < dimension; i++ ) simplex[ i ] = base[ i ];
1296 auto plane = kernel.compute( points, simplex, below );
1297 return Facet( plane, below );
1298 }
Kernel::CombinatorialPlaneSimplex CombinatorialPlaneSimplex
Definition QuickHull.h:151

Referenced by DGtal::QuickHull< Kernel3D >::computeSimplexConfiguration(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ makeNeighbors()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::makeNeighbors ( const Index if1,
const Index if2 )
inlineprotected

Makes two distinct facets if1 and if2 as neighbors

Parameters
if1a valid facet index
if2a valid facet index

Definition at line 1204 of file QuickHull.h.

1205 {
1206 facets[ if1 ].addNeighbor( if2 );
1207 facets[ if2 ].addNeighbor( if1 );
1208 }

Referenced by DGtal::QuickHull< Kernel3D >::mergeParallelFacets(), and DGtal::QuickHull< Kernel3D >::processFacet().

◆ memory()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::memory ( ) const
inline
Returns
an estimation of the current memory occupation of this object.

Definition at line 287 of file QuickHull.h.

288 {
289 // int debug_level;
290 Size M = sizeof( kernel ) + sizeof( int );
291 // std::vector< Point > points;
292 M += sizeof( std::vector< Point > )
293 + points.capacity() * sizeof( Point );
294 M += sizeof( std::vector< Index > )
295 + processed_points.capacity() * sizeof( Index );
296 M += sizeof( std::vector< Index > )
297 + input2comp.capacity() * sizeof( Index );
298 M += sizeof( std::vector< Index > )
299 + comp2input.capacity() * sizeof( Index );
300 // std::vector< Index > assignment;
301 M += sizeof( std::vector< Index > )
302 + assignment.capacity() * sizeof( Index );
303 // std::vector< Facet > facets;
304 M += sizeof( std::vector< Facet > )
305 + facets.capacity() * sizeof( Facet );
306 for ( const auto& f : facets ) M += f.variableMemory();
307 // std::set< Index > deleted_facets;
308 M += sizeof( std::set< Index > )
309 + deleted_facets.size() * ( sizeof( Index ) + 2*sizeof(Index*) );
310 // IndexRange p2v;
311 M += sizeof( std::vector< Index > )
312 + p2v.capacity() * sizeof( Index );
313 // IndexRange v2p;
314 M += sizeof( std::vector< Index > )
315 + v2p.capacity() * sizeof( Index );
316 // std::vector< double > timings;
317 M += sizeof( std::vector< double > )
318 + timings.capacity() * sizeof( double );
319 return M;
320 }

◆ mergeParallelFacets()

template<typename TKernel>
Index DGtal::QuickHull< TKernel >::mergeParallelFacets ( const Index if1,
const Index if2 )
inlineprotected

Merge the two facets and return the index of the second one, which is the one deleted.

Parameters
if1a valid facet index
if2a valid facet index
Precondition
the two facets should be distinct and parallel

Definition at line 1225 of file QuickHull.h.

1226 {
1227 Facet& f1 = facets[ if1 ];
1228 Facet& f2 = facets[ if2 ];
1229 std::copy( f2.outside_set.cbegin(), f2.outside_set.cend(),
1230 std::back_inserter( f1.outside_set ) );
1232 std::set_union( f1.on_set.cbegin(), f1.on_set.cend(),
1233 f2.on_set.cbegin(), f2.on_set.cend(),
1235 f1.on_set.swap( merge_idx );
1236 for ( auto && nf2 : f2.neighbors ) {
1237 if ( nf2 == if1 ) continue;
1238 facets[ nf2 ].subNeighbor( if2 );
1239 makeNeighbors( if1, nf2 );
1240 }
1241 return if2;
1242 }
void makeNeighbors(const Index if1, const Index if2)
Definition QuickHull.h:1204

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ nbFacets()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nbFacets ( ) const
inline
Returns
the number of facets of the convex hull.
Precondition
status() >= Status::FacetsCompleted

Definition at line 328 of file QuickHull.h.

329 {
332 return facets.size();
333 }

Referenced by DGtal::QuickHull< Kernel3D >::getFacetHalfSpaces(), DGtal::QuickHull< Kernel3D >::getFacetVertices(), main(), and DGtal::QuickHull< Kernel3D >::selfDisplay().

◆ nbFiniteFacets()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nbFiniteFacets ( ) const
inline
Returns
the number of finite facets of the convex hull.
Precondition
status() >= Status::VerticesCompleted

Definition at line 346 of file QuickHull.h.

347 {
350 return nb_finite_facets;
351 }
Size nb_finite_facets
Number of finite facets.
Definition QuickHull.h:822

◆ nbInfiniteFacets()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nbInfiniteFacets ( ) const
inline
Returns
the number of infinite facets of the convex hull.
Precondition
status() >= Status::VerticesCompleted

Definition at line 355 of file QuickHull.h.

356 {
359 return nb_infinite_facets;
360 }
Size nb_infinite_facets
Number of infinite facets (!= 0 only for specific kernels)
Definition QuickHull.h:824

◆ nbPoints()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nbPoints ( ) const
inline
Returns
the number of points used as input.

Definition at line 323 of file QuickHull.h.

324 { return points.size(); }

Referenced by main(), and DGtal::QuickHull< Kernel3D >::selfDisplay().

◆ nbVertices()

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nbVertices ( ) const
inline
Returns
the number of vertices of the convex hull.
Precondition
status() >= Status::VerticesCompleted

Definition at line 337 of file QuickHull.h.

338 {
341 return v2p.size();
342 }

Referenced by main(), and DGtal::QuickHull< Kernel3D >::selfDisplay().

◆ newFacet()

template<typename TKernel>
Index DGtal::QuickHull< TKernel >::newFacet ( )
inlineprotected
Returns
an unused facet index

Definition at line 1183 of file QuickHull.h.

1184 {
1185 // SLightly faster to postpone deletion of intermediate facets.
1186 const Index f = facets.size();
1187 facets.push_back( Facet() );
1188 return f;
1189 }

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ on()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::on ( const Facet & F,
const Point & p ) const
inlineprotected
Parameters
Fany valid facet
pany point
Returns
'true' iff p lies on F.

Definition at line 868 of file QuickHull.h.

869 { return kernel.on( F.H, p ); }

Referenced by DGtal::QuickHull< Kernel3D >::areFacetsParallel(), DGtal::QuickHull< Kernel3D >::checkFacet(), and DGtal::QuickHull< Kernel3D >::filterVerticesOnFacet().

◆ orientedFacetPoints()

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::orientedFacetPoints ( Index f) const
inlineprotected

Given a facet index f, return its points oriented consistently with respect to the normal.

Parameters
fany valid facet index
Returns
the range of point indices that support this facet, in a consistent ordering.
Note
the order of points is consistent if, picking any d-simplex in order in this range, their associated half-spaces have all the same orientation.

Definition at line 1323 of file QuickHull.h.

1324 {
1325 const Facet& F = facets[ f ];
1326 IndexRange result = F.on_set;
1327 // Sort a facet such that its points, taken in order, have
1328 // always the same orientation of the facet. More precisely,
1329 // facets span a `dimension-1` vector space. There are thus
1330 // dimension-2 fixed points, and the last ones (at least two)
1331 // may be reordered.
1333 for ( Dimension k = 0; k < dimension-2; k++ )
1334 splx[ k ] = result[ k ];
1335 std::sort( result.begin()+dimension-2, result.end(),
1336 [&] ( Index i, Index j )
1337 {
1338 splx[ dimension-2 ] = i;
1339 splx[ dimension-1 ] = j;
1340 const auto H = kernel.compute( points, splx );
1341 const auto orient = kernel.dot( F.H, H );
1342 return orient > 0;
1343 } );
1344 return result;
1345 }

Referenced by DGtal::QuickHull< Kernel3D >::getFacetVertices().

◆ pickInitialSimplex()

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::pickInitialSimplex ( ) const
inlineprotected
Returns
a full dimensional simplex as a vector of d + 1 distinct indices of input points, or an empty vector if none was found.

Definition at line 1372 of file QuickHull.h.

1373 {
1374 const Size nb = points.size();
1375 if ( nb < dimension + 1 ) return IndexRange();
1378 for ( Index j = 0; j < dimension; ++j ) splx[ j ] = best[ j ];
1379 const auto first_H = kernel.compute( points, splx, best.back() );
1380 auto best_volume = kernel.volume ( first_H, points[ best.back() ] );
1381 const Size nbtries = std::min( (Size) 10, 1 + nb / 10 );
1382 const Size max_nbtries = std::max( (Size) 10, 2 * nb );
1383 for ( Size i = 0; i < max_nbtries; i++ )
1384 {
1386 for ( Index j = 0; j < dimension; ++j ) splx[ j ] = tmp[ j ];
1387 const auto tmp_H = kernel.compute( points, splx, tmp.back() );
1388 const auto tmp_volume = kernel.volume ( tmp_H, points[ tmp.back() ] );
1389 if ( best_volume < tmp_volume ) {
1390 if ( debug_level >= 1 ) {
1391 trace.info() << "(" << i << ")"
1392 << " new_volume = " << tmp_volume
1393 << " > " << best_volume << std::endl;
1394 }
1395 best = tmp;
1397 }
1398 if ( i >= nbtries && best_volume > 0 ) return best;
1399 }
1400 return IndexRange();
1401 }
static IndexRange pickIntegers(const Size d, const Size n)
Definition QuickHull.h:1406

Referenced by DGtal::QuickHull< Kernel3D >::computeInitialSimplex().

◆ pickIntegers()

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::pickIntegers ( const Size d,
const Size n )
inlinestaticprotected
Returns
a vector of d distinct integers in {0, 1, ..., n-1} randomly chosen.
Parameters
[in]dthe number of returned integers
[in]nthe range of possible integers {0, 1, ..., n-1}

Definition at line 1406 of file QuickHull.h.

1407 {
1408 IndexRange result( d );
1409 bool distinct = false;
1410 while ( ! distinct )
1411 {
1412 distinct = true;
1413 for ( Index i = 0; i < d; i++ ) result[ i ] = rand() % n;
1414 std::sort( result.begin(), result.end() );
1415 for ( Index i = 1; distinct && i < d; i++ )
1416 distinct = result[ i-1 ] != result[ i ];
1417 }
1418 return result;
1419 }

Referenced by DGtal::QuickHull< Kernel3D >::pickInitialSimplex().

◆ pointsOnRidge()

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::pointsOnRidge ( const Ridge & R) const
inlineprotected
Parameters
[in]Ra ridge between two facets (a pair of facets).
Returns
the points lying on a ridge.

Definition at line 1302 of file QuickHull.h.

1303 {
1304 // Slightly faster to look at points instead at true geometry.
1306 const Facet& f1 = facets[ R.first ];
1307 const Facet& f2 = facets[ R.second ];
1308 std::set_intersection( f1.on_set.cbegin(), f1.on_set.cend(),
1309 f2.on_set.cbegin(), f2.on_set.cend(),
1311 return result;
1312 }

Referenced by DGtal::QuickHull< Kernel3D >::processFacet().

◆ processFacet()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::processFacet ( std::queue< Index > & Q)
inlineprotected

Process top facet in queue Q as in Quickhull algorithm, and updates the queue accordingly (top facet poped, new facets pushed).

Parameters
[in,out]Qa queue of facet index to process. which is updated by the method.
Returns
'true' if there is still work to do, 'false' when finished
Note
Core of Quickhull algorithm.

Definition at line 944 of file QuickHull.h.

945 {
946 // If Q empty, we are done
947 if ( Q.empty() ) return false;
948 Index F = Q.front();
949 Q.pop();
950 // If F is already deleted, proceed to next in queue.
951 if ( deleted_facets.count( F ) ) return true;
952 // Take car of current facet.
953 const Facet& facet = facets[ F ];
954 if ( debug_level >= 3 ) {
955 trace.info() << "---------------------------------------------" << std::endl;
956 trace.info() << "---- ACTIVE FACETS---------------------------" << std::endl;
957 bool ok = true;
958 for ( Index i = 0; i < facets.size(); i++ )
959 if ( ! deleted_facets.count( i ) ) {
960 trace.info() << "- facet " << i << " ";
961 facets[ i ].display( trace.info() );
962 ok = ok && checkFacet( i );
963 }
964 if ( ! ok ) { // should not happen.
966 return false;
967 }
968 }
969 if ( debug_level >= 2 ) {
970 trace.info() << "---------------------------------------------" << std::endl;
971 trace.info() << "Processing facet " << F << " ";
972 facet.display( trace.info() );
973 }
974 if ( facet.outside_set.empty() ) return true;
975 // Selects furthest vertex
976 Index furthest_v = facet.outside_set[ 0 ];
978 for ( Index v = 1; v < facet.outside_set.size(); v++ ) {
979 auto h = height( facet, points[ facet.outside_set[ v ] ] );
980 if ( h > furthest_h ) {
981 furthest_h = h;
982 furthest_v = facet.outside_set[ v ];
983 }
984 }
985 const Point& p = points[ furthest_v ];
986 // Extracts Visible facets V and Horizon Ridges H
987 std::vector< Index > V; // visible facets
988 std::set< Index > M; // marked facets (are in E or were in E)
989 std::queue< Index > E; // queue to extract visible facets
990 std::vector< Ridge > H; // visible facets
991 E.push ( F );
992 M.insert( F );
993 while ( ! E.empty() ) {
994 Index G = E.front(); E.pop();
995 V.push_back( G );
996 for ( auto& N : facets[ G ].neighbors ) {
997 if ( aboveOrOn( facets[ N ], p ) ) {
998 if ( M.count( N ) ) continue;
999 E.push( N );
1000 } else {
1001 H.push_back( { G, N } );
1002 }
1003 M.insert( N );
1004 }
1005 } // while ( ! E.empty() )
1006 if ( debug_level >= 1 ) {
1007 trace.info() << "#Visible=" << V.size() << " #Horizon=" << H.size()
1008 << " furthest_v=" << furthest_v << std::endl;
1009 }
1010 // Create new facets
1012 // For each ridge R in H
1013 for ( Index i = 0; i < H.size(); i++ )
1014 {
1015 // Create a new facet from R and p
1017 if ( debug_level >= 3 ) {
1018 trace.info() << "Ridge (" << H[i].first << "," << H[i].second << ") = {";
1019 for ( auto&& r : ridge ) trace.info() << " " << r;
1020 trace.info() << " } furthest_v=" << furthest_v << std::endl;
1021 }
1022 IndexRange base( 1 + ridge.size() );
1023 Index j = 0;
1024 base[ j++ ] = furthest_v;
1025 for ( auto&& v : ridge ) base[ j++ ] = v;
1026 if ( j < dimension ) {
1027 trace.error() << "Bad ridge between " << std::endl
1028 << "- facet " << H[i].first << " ";
1029 facets[ H[i].first ].display( trace.error() );
1030 trace.error() << "- facet " << H[i].second << " ";
1031 facets[ H[i].second ].display( trace.error() );
1032 }
1033 Index nf = newFacet();
1034 new_facets.push_back( nf );
1035 facets[ nf ] = makeFacet( base, facets[ H[i].first ].below );
1036 facets[ nf ].on_set = IndexRange { base.cbegin(), base.cend() };
1037 std::sort( facets[ nf ].on_set.begin(), facets[ nf ].on_set.end() );
1038 makeNeighbors( nf, H[ i ].second );
1039 if ( debug_level >= 3 ) {
1040 trace.info() << "* New facet " << nf << " ";
1041 facets[ nf ].display( trace.info() );
1042 }
1043 // Checks that the facet is not parallel to another in the Horizon
1044 for ( Index k = 0; k < new_facets.size() - 1; k++ )
1045 if ( areFacetsParallel( new_facets[ k ], nf ) ) {
1046 if ( debug_level >= 1 ) {
1047 trace.info() << "Facets " << new_facets[ k ] << " and " << nf
1048 << " are parallel => merge." << std::endl;
1049 }
1051 new_facets.pop_back();
1052 deleteFacet( nf );
1053 if ( debug_level >= 3 ) {
1054 facets[ new_facets[ k ] ].display( trace.info() );
1055 }
1056 }
1057 }
1058 // For each new facet
1059 for ( Index i = 0; i < new_facets.size(); i++ )
1060 { // link the new facet to its neighbors
1061 for ( Index j = i + 1; j < new_facets.size(); j++ )
1062 {
1063 const Index nfi = new_facets[ i ];
1064 const Index nfj = new_facets[ j ];
1065 if ( areFacetsNeighbor( nfi, nfj ) )
1066 makeNeighbors( nfi, nfj );
1067 }
1068 }
1069 // Extracts all outside points from visible facets V
1071 for ( auto&& vf : V ) {
1072 for ( auto&& v : facets[ vf ].outside_set ) {
1073 if ( v != furthest_v ) {
1074 outside_pts.push_back( v );
1075 assignment[ v ] = UNASSIGNED;
1076 }
1077 }
1078 }
1079 // For each new facet F'
1080 for ( Index i = 0; i < new_facets.size(); i++ ) {
1081 Facet& Fp = facets[ new_facets[ i ] ];
1082 Index max_j = outside_pts.size();
1083 for ( Index j = 0; j < max_j; ) {
1084 const Index v = outside_pts[ j ];
1085 if ( above( Fp, points[ v ] ) ) {
1086 Fp.outside_set.push_back( v );
1087 assignment[ v ] = new_facets[ i ];
1088 outside_pts[ j ] = outside_pts.back();
1089 outside_pts.pop_back();
1090 max_j--;
1091 } else j++;
1092 }
1093 if ( debug_level >= 3 ) {
1094 trace.info() << "- New facet " << new_facets[ i ] << " ";
1095 Fp.display( trace.info() );
1096 }
1097 }
1098 // Update processed points
1099 processed_points.push_back( furthest_v );
1100 for ( auto v : outside_pts ) processed_points.push_back( v );
1101
1102 // Delete the facets in V
1103 for ( auto&& v : V ) {
1104 if ( debug_level >= 2 ) {
1105 trace.info() << "Delete facet " << v << " ";
1106 facets[ v ].display( trace.info() );
1107 }
1108 deleteFacet( v );
1109 }
1110
1111 // Add new facets to queue
1112 for ( Index i = 0; i < new_facets.size(); i++ )
1113 Q.push( new_facets[ i ] );
1114 if ( debug_level >= 1 ) {
1115 trace.info() << "#facets=" << facets.size()
1116 << " #deleted=" << deleted_facets.size() << std::endl;
1117 }
1118
1119 // Checks that everything is ok.
1120 if ( debug_level >= 1 ) {
1121 trace.info() << "[CHECK INVARIANT] " << processed_points.size()
1122 << " / " << points.size() << " points processed." << std::endl;
1123 bool okh = checkHull();
1124 if ( ! okh )
1125 trace.error() << "[computeFacet] Invalid convex hull" << std::endl;
1126 bool okf = checkFacets();
1127 if ( ! okf )
1128 trace.error() << "[computeFacet] Invalid facets" << std::endl;
1129 if ( ! ( okh && okf ) ) myStatus = Status::InvalidConvexHull;
1130 }
1131
1132 return status() == Status::SimplexCompleted;
1133 }
IndexRange pointsOnRidge(const Ridge &R) const
Definition QuickHull.h:1302
bool areFacetsParallel(const Index if1, const Index if2) const
Definition QuickHull.h:1248
void deleteFacet(Index f)
Definition QuickHull.h:1193
InternalScalar height(const Facet &F, const Point &p) const
Definition QuickHull.h:850
Index mergeParallelFacets(const Index if1, const Index if2)
Definition QuickHull.h:1225

Referenced by DGtal::QuickHull< Kernel3D >::computeFacets().

◆ renumberInfiniteFacets()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::renumberInfiniteFacets ( )
inlineprotected

Determine infinite facets and renumber them so that finite facets come first and infinite facets come after.

Definition at line 901 of file QuickHull.h.

902 {
903 nb_finite_facets = facets.size();
905 if ( ! kernel.hasInfiniteFacets() ) return;
906 IndexRange renumbering( facets.size() );
907 Index i = 0;
908 Index k = facets.size();
909 Index j = 0;
910 for ( auto& l : renumbering ) {
911 if ( ! kernel.isHalfSpaceFacetInfinite( facets[ j ].H ) ) l = i++;
912 else l = --k;
913 j++;
914 }
915 if ( i != k )
916 trace.error() << "[Quickhull::renumberInfiniteFacets]"
917 << " Error renumbering infinite facets "
918 << " up finite=" << i << " low infinite=" << k << std::endl;
920 for ( Index f = 0; f < facets.size(); f++ )
921 new_facets[ renumbering[ f ] ].swap( facets[ f ] );
922 facets.swap( new_facets );
923 for ( auto& F : facets ) {
924 for ( auto& N : F.neighbors ) {
925 N = renumbering[ N ];
926 }
927 }
928 // Assign correct number of facets.
931 }
void swap(UnorderedSetByBlock< Key, TSplitter, Hash, KeyEqual, UnorderedMapAllocator > &s1, UnorderedSetByBlock< Key, TSplitter, Hash, KeyEqual, UnorderedMapAllocator > &s2) noexcept

Referenced by DGtal::QuickHull< Kernel3D >::computeVertices().

◆ selfDisplay()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::selfDisplay ( std::ostream & out) const
inline

Writes/Displays the object on an output stream.

Parameters
outthe output stream where the object is written.

Definition at line 1494 of file QuickHull.h.

1495 {
1496 out << "[QuickHull " << dimension << "D"
1497 // << " status=" << status()
1498 << " #P=" << nbPoints();
1500 out << " #F=" << nbFacets();
1502 out << " #V=" << nbVertices();
1503 out << "]";
1505 && nbFacets() == 24 ) {
1506 for ( auto f : facets ) f.display( out );
1507 for ( auto v : v2p ) out << points[ v2p[ v ] ] << std::endl;
1508 }
1509 }

◆ setInitialSimplex()

template<typename TKernel>
bool DGtal::QuickHull< TKernel >::setInitialSimplex ( const IndexRange & full_splx)
inline

Sets the initial full dimensional simplex

Precondition
status() must be Status::InputInitialized
Parameters
full_splxa dimension+1-simplex specified as indices in the vector of input point.
Returns
'true' iff this initial simplex is full dimensional, the object has then the status SimplexCompleted, otherwise returns 'false' and the status is NotFullDimensional.

Definition at line 410 of file QuickHull.h.

411 {
412 if ( status() != Status::InputInitialized ) return false;
413 if ( full_splx.size() != dimension + 1 )
414 {
415 trace.error() << "[QuickHull::setInitialSimplex]"
416 << " not a full dimensional simplex" << std::endl;
418 return false;
419 }
421 for ( Index j = 0; j < dimension; ++j )
422 splx[ j ] = full_splx[ j ];
423 const auto H = kernel.compute( points, splx, full_splx.back() );
424 const auto volume = kernel.volume( H, points[ full_splx.back() ] );
425 if ( volume > 0 )
428 return false;
429 }

◆ setInput()

template<typename TKernel>
template<typename InputPoint>
bool DGtal::QuickHull< TKernel >::setInput ( const std::vector< InputPoint > & input_points,
bool remove_duplicates = true )
inline

Sets the input data for the QuickHull convex hull algorithm, which is a range of points.

Template Parameters
InputPointa model of point that is convertible to Point datatype.
Parameters
[in]input_pointsthe range of input points.
[in]remove_duplicatesshould be set to 'true' if the input data has duplicates.
Returns
'true' if the object is successfully initialized, status must be Status::InputInitialized, 'false' otherwise.
Examples
geometry/tools/exampleLatticeBallDelaunay2D.cpp.

Definition at line 382 of file QuickHull.h.

384 {
385 Clock tic;
386 tic.startClock();
387 clear();
388 timings.clear();
389 kernel.makeInput( points, input2comp, comp2input,
391 timings.push_back( tic.stopClock() );
392 if ( points.size() <= dimension ) {
394 return false;
395 }
397 return true;
398 }

Referenced by main().

◆ status()

◆ unmakeNeighbors()

template<typename TKernel>
void DGtal::QuickHull< TKernel >::unmakeNeighbors ( const Index if1,
const Index if2 )
inlineprotected

Makes two distinct facets if1 and if2 no more neighbors

Parameters
if1a valid facet index
if2a valid facet index

Definition at line 1213 of file QuickHull.h.

1214 {
1215 facets[ if1 ].subNeighbor( if2 );
1216 facets[ if2 ].subNeighbor( if1 );
1217 }

Field Documentation

◆ assignment

template<typename TKernel>
std::vector< Index > DGtal::QuickHull< TKernel >::assignment

assignment of points to facets

Definition at line 812 of file QuickHull.h.

◆ comp2input

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::comp2input

the injective mapping between the convex hull point range and the input range.

Definition at line 808 of file QuickHull.h.

◆ debug_level

template<typename TKernel>
int DGtal::QuickHull< TKernel >::debug_level

debug_level from 0:no to 2

Definition at line 800 of file QuickHull.h.

◆ deleted_facets

template<typename TKernel>
std::set< Index > DGtal::QuickHull< TKernel >::deleted_facets

set of deleted facets

Definition at line 816 of file QuickHull.h.

◆ dimension

template<typename TKernel>
const Size DGtal::QuickHull< TKernel >::dimension = Point::dimension
static

Definition at line 152 of file QuickHull.h.

◆ facet_counter

template<typename TKernel>
std::vector< Size > DGtal::QuickHull< TKernel >::facet_counter

Counts the number of facets with a given number of vertices.

Definition at line 828 of file QuickHull.h.

◆ facets

template<typename TKernel>
std::vector< Facet > DGtal::QuickHull< TKernel >::facets

the current set of facets.

Definition at line 814 of file QuickHull.h.

◆ input2comp

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::input2comp

the surjective mapping between the input range and the output range used for convex hull computation.

Definition at line 805 of file QuickHull.h.

◆ kernel

template<typename TKernel>
Kernel DGtal::QuickHull< TKernel >::kernel
mutable

Kernel that is duplicated for computing facet geometries.

Definition at line 798 of file QuickHull.h.

◆ myStatus

template<typename TKernel>
Status DGtal::QuickHull< TKernel >::myStatus
protected

The status of the object: Uninitialized, InputInitialized, SimplexCompleted, FacetsCompleted, VerticesCompleted, InvalidRidge, InvalidConvexHull, NotFullDimensional

Definition at line 839 of file QuickHull.h.

◆ nb_finite_facets

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nb_finite_facets

Number of finite facets.

Definition at line 822 of file QuickHull.h.

◆ nb_infinite_facets

template<typename TKernel>
Size DGtal::QuickHull< TKernel >::nb_infinite_facets

Number of infinite facets (!= 0 only for specific kernels)

Definition at line 824 of file QuickHull.h.

◆ p2v

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::p2v

point index -> vertex index (or UNASSIGNED)

Definition at line 818 of file QuickHull.h.

◆ points

template<typename TKernel>
std::vector< Point > DGtal::QuickHull< TKernel >::points

the set of points, indexed as in the array.

Definition at line 802 of file QuickHull.h.

◆ processed_points

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::processed_points

Points already processed (and within the convex hull).

Definition at line 810 of file QuickHull.h.

◆ timings

template<typename TKernel>
std::vector< double > DGtal::QuickHull< TKernel >::timings

Timings of the different phases: 0: init, 1: facets, 2: vertices.

Definition at line 826 of file QuickHull.h.

Referenced by main().

◆ v2p

template<typename TKernel>
IndexRange DGtal::QuickHull< TKernel >::v2p

vertex index -> point index

Definition at line 820 of file QuickHull.h.


The documentation for this struct was generated from the following file: