diff --git a/ChangeLog.md b/ChangeLog.md index f4d79432fc..31b9d94eba 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,10 @@ - *Configuration/General* - Simplifying Travis CI scripts (David Coeurjolly, [#1371](https://github.com/DGtal-team/DGtal/pull/1371)) +- *Topology* + - Remove the internal object from VoxelComplex, improving performance + (Pablo Hernandez, [#1369](https://github.com/DGtal-team/DGtal/pull/1369)) + ## Bug Fixes - *Configuration/General* - Continuous integration AppVeyor fix diff --git a/examples/topology/generateVoxelComplexTables.cpp b/examples/topology/generateVoxelComplexTables.cpp index 4656055585..15f28b67e3 100644 --- a/examples/topology/generateVoxelComplexTables.cpp +++ b/examples/topology/generateVoxelComplexTables.cpp @@ -63,10 +63,7 @@ int main( int argc, char** argv ) typedef std::bitset<67108864> ConfigMap; // 2^26 using namespace Z3i; - using DigitalSet = DigitalSetByAssociativeContainer< - Domain, std::unordered_set< typename Domain::Point> >; - using Object = Object; - using VoxelComplex = VoxelComplex; + using VoxelComplex = VoxelComplex; std::function< bool( const VoxelComplex & , @@ -74,9 +71,9 @@ int main( int argc, char** argv ) > skelFunction; string error_message( "Provide one of the following arguments for select function:\n" - "- skelIsthmus \n " - "- oneIsthmus \n " - "- twoIsthmus \n "); + "- skelIsthmus \n" + "- oneIsthmus \n" + "- twoIsthmus \n"); if (argc != 2 ){ cout << error_message << std::endl; return 1; diff --git a/src/DGtal/topology/VoxelComplex.h b/src/DGtal/topology/VoxelComplex.h index 47cbd2474b..5713107d87 100644 --- a/src/DGtal/topology/VoxelComplex.h +++ b/src/DGtal/topology/VoxelComplex.h @@ -48,17 +48,17 @@ namespace DGtal { // Forward definitions. -template +template class VoxelComplex; namespace functions { -template -VoxelComplex & -operator-=(VoxelComplex &, - const VoxelComplex &); -template -VoxelComplex -operator-(const VoxelComplex &, - const VoxelComplex &); +template +VoxelComplex & +operator-=(VoxelComplex &, + const VoxelComplex &); +template +VoxelComplex +operator-(const VoxelComplex &, + const VoxelComplex &); } // namespace functions ///////////////////////////////////////////////////////////////////////////// @@ -87,16 +87,12 @@ operator-(const VoxelComplex &, * */ -template ::Type > class VoxelComplex : public CubicalComplex { public: - // The TObject::DigitalSet::Container must be associative. - BOOST_CONCEPT_ASSERT((concepts::CSTLAssociativeContainer< - typename TObject::DigitalSet::Container>)); - /** Type of this instance of VoxelComplex. */ - using Self = VoxelComplex; + using Self = VoxelComplex; friend Self &DGtal::functions::operator-=<>(Self &, const Self &); friend Self DGtal::functions::operator-<>(const Self &, const Self &); @@ -109,10 +105,6 @@ class VoxelComplex : public CubicalComplex { using CellContainer = TCellContainer; /** Type of data associated to each cell. */ using Data = typename CellContainer::mapped_type; - /** Type for input Object storing the digital set of spels with a topology*/ - using Object = TObject; - /** Type of the associated DigitalTopology of Object. */ - using DigitalTopology = typename TObject::DigitalTopology; /// The dimension of the embedding space. static const Dimension dimension = KSpace::dimension; @@ -172,12 +164,13 @@ class VoxelComplex : public CubicalComplex { Self &operator=(const Self &other); /** - * Construct the VoxelComplex with target \a obj + * Construct the VoxelComplex with target \a input_set * - * @param obj input object to copy to the complex. + * @param input_set input set to construct the complex. * */ - void construct(const TObject &obj); + template < typename TDigitalSet > + void construct(const TDigitalSet &input_set); /** * Construct from digital set and precomputed look up table for simplicity. @@ -193,7 +186,8 @@ class VoxelComplex : public CubicalComplex { * * @see LookUpTableFunctions.h */ - void construct(const typename Object::DigitalSet &input_set, + template < typename TDigitalSet > + void construct(const TDigitalSet &input_set, const Alias input_table); /** @@ -205,6 +199,14 @@ class VoxelComplex : public CubicalComplex { */ void setSimplicityTable(const Alias input_table); + /** + * Copy table variables from other Complex. + * + * @param other complex to copy table from + * + */ + void copySimplicityTable(const Self & other); + /** * Get const reference to table[conf]->bool for simplicity. * @@ -268,21 +270,22 @@ class VoxelComplex : public CubicalComplex { void insertVoxelPoint(const Point &dig_point, const bool &close_it = true, const Data &data = Data()); + /** + * Dump the voxels (kcell with dimension 3) into a input container. + * + * @tparam TDigitalSet the type of the container + * @param in_out_set input and output digital set, voxels gets inserted in the set. + * Note that the input digital set is not cleared in this function before inserting. + */ + template + void dumpVoxels(TDigitalSet & in_out_set); + /** * Clears the voxel complex, which becomes empty. * This includes the khalmisky cells and also the object points. */ void clear(); - /** - * Get reference to a point in the DigitalSet of myObject - * corresponding to input voxel - * - * @param voxel input voxel - * - * @return A point in myObject - */ - const typename Object::Point &objPointFromVoxel(const Cell &voxel) const; //------ Spels ------// /** * Get pointels that are Faces of input_cell. @@ -308,6 +311,27 @@ class VoxelComplex : public CubicalComplex { */ void spelsFromCell(std::set &spels_out, const Cell &input_cell) const; + /** + * Return the neighbor spels of input_cell + * + * @param input_cell center of the neighborhood + * + * @return neighborhood of input_cell + */ + std::set neighborhoodVoxels(const Cell &input_cell) const; + + /** + * Return a set of of voxels forming the properNeighborhood of the inputCell. + * + * @param input_cell center of the neighborhood + * + * @sa neighborhoodVoxels + * @sa Kneighborhood + * + * @return properNeighborhood + */ + std::set properNeighborhoodVoxels(const Cell &input_cell) const; + /** * Get a clique holding the K-neighborhood of the input cell. * The K-neighborhood is calculated first, getting the pointels @@ -321,13 +345,18 @@ class VoxelComplex : public CubicalComplex { Clique Kneighborhood(const Cell &input_cell) const; /** - * Populate this complex object from the spels belonging to - * the Khalimsky space. + * Use thinning to check if cell is simple. + * First create a CubicalComplex from the neighbor voxels on input_cell. + * This does not include input_cell itself, close the new clique and apply + * a collapse operation. + * A input_spel is simple in the complex, if after the collapse on the proper + * neighborhood clique, there is only one pointel. + * + * @param input_spel input spel for checking its simplicity. * - * @return const reference to object(). + * @return true if input_spell can be removed without altering the topology. */ - const Object &populateObjectFromCells(); - + bool isSimpleByThinning(const Cell &input_spel) const; /** * Check if the input_spel from khalimsky space is simple using * object properties. @@ -343,34 +372,6 @@ class VoxelComplex : public CubicalComplex { */ bool isSimple(const Cell &input_spel) const; - /** - * @return true if object is connected, false if disconnected. - * - * @note connectedness::unkwown is not possible. - * - * @see Object::computeConnectedness. - */ - bool isConnected() const; - - /** - * @return Object representing the spels. - */ - Object &object(); - /** - * @return Object representing the spels, read only. - */ - const Object &object() const; - - /** - * @return digitalSet of Object representing the spels. - */ - typename Object::DigitalSet &objectSet(); - - /** - * @return digitalSet of Object representing the spels, read only. - */ - const typename Object::DigitalSet &objectSet() const; - //------ Cliques ------// // Cliques, union of adjacent spels. // The intersection of all spels of the clique define the type. @@ -390,7 +391,7 @@ class VoxelComplex : public CubicalComplex { /** * Return all critical cliques for \b cubical. - * It calls criticalCliquesForD() + * It calls @ref criticalCliquePairForD * * @param cubical target complex to get critical cliques. * @param verbose print messages @@ -415,7 +416,7 @@ class VoxelComplex : public CubicalComplex { return criticals; } /** - * Helper. Call @ref criticalCliques() of this VoxelComplex. + * Helper. Call @ref criticalCliques of this VoxelComplex. * * @param verbose print messages * @@ -428,7 +429,7 @@ class VoxelComplex : public CubicalComplex { /** * Main method to iterate over cells of selected dimension in a complex, - * returning critical cliques. Uses @ref criticalCliquePair(). + * returning critical cliques. Uses @ref criticalCliquePair. * * @param d dimension of cell. * @param cubical target complex to get critical cliques. @@ -466,8 +467,8 @@ class VoxelComplex : public CubicalComplex { * * @return */ - std::pair K_2(const typename Object::Point &A, - const typename Object::Point &B, + std::pair K_2(const typename KSpace::Point &A, + const typename KSpace::Point &B, bool verbose = false) const; /** @@ -535,8 +536,6 @@ class VoxelComplex : public CubicalComplex { /*------------- Data --------------*/ protected: - /** Object with a topology representing spels. */ - Object myObject; /** Look Up Table to speed computations of @ref isSimple. */ CountedPtrOrPtr myTablePtr; /** ConfigurationMask (LUT table). */ @@ -546,22 +545,14 @@ class VoxelComplex : public CubicalComplex { /*------------- Internal Methods --------------*/ /** * pointToMask map, used internally in @ref VoxelComplex::isSimple for - * @ref functions::getSpelNeighborhoodConfigurationOccupancy + * @ref LookUpTableFunctions.h::getSpelNeighborhoodConfigurationOccupancy * - * @return reference to @ref PointToMaskMap member. + * @return reference to pointToMaskMap member. * - * @see pointToBitMaskMap() + * @see LookUpTableFunctions.h::pointToBitMaskMap() */ const PointToMaskMap &pointToMask() const; - /** - * Populate myObject member with an empty set with valid domain and - * topology. Used in @ref VoxelComplex::construct with digital sets. - * - * @param dig_set input digital set. - */ - void instantiateEmptyObject(const typename Object::DigitalSet &dig_set); - // ----------------------- Interface -------------------------------------- public: /** @@ -591,10 +582,10 @@ class VoxelComplex : public CubicalComplex { * @param object the object of class 'VoxelComplex' to write. * @return the output stream after the writing. */ -template +template std::ostream & operator<<(std::ostream &out, - const VoxelComplex &object); + const VoxelComplex &object); } // namespace DGtal diff --git a/src/DGtal/topology/VoxelComplex.ih b/src/DGtal/topology/VoxelComplex.ih index 2bb6007128..892eb83efe 100644 --- a/src/DGtal/topology/VoxelComplex.ih +++ b/src/DGtal/topology/VoxelComplex.ih @@ -35,21 +35,22 @@ #include #include #ifdef WITH_OPENMP +// #include #include #endif ////////////////////////////////////////////////////////////////////////////// // Default constructor: -template -inline DGtal::VoxelComplex::VoxelComplex() - : Parent(), myObject(), +template +inline DGtal::VoxelComplex::VoxelComplex() + : Parent(), myTablePtr(nullptr), myPointToMaskPtr(nullptr), myIsTableLoaded(false) {} // Copy constructor: -template -inline DGtal::VoxelComplex::VoxelComplex( +template +inline DGtal::VoxelComplex::VoxelComplex( const VoxelComplex &other) - : Parent(other), myObject(other.myObject), + : Parent(other), myTablePtr(other.myTablePtr), myPointToMaskPtr(other.myPointToMaskPtr), myIsTableLoaded(other.myIsTableLoaded) {} @@ -58,14 +59,13 @@ inline DGtal::VoxelComplex::VoxelComplex( // IMPLEMENTATION of inline methods. /////////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- -template -inline DGtal::VoxelComplex & -DGtal::VoxelComplex:: +template +inline DGtal::VoxelComplex & +DGtal::VoxelComplex:: operator=(const Self &other) { if (this != &other) { this->myKSpace = other.myKSpace; this->myCells = other.myCells; - myObject = other.myObject; myTablePtr = other.myTablePtr; myPointToMaskPtr = other.myPointToMaskPtr; myIsTableLoaded = other.myIsTableLoaded; @@ -80,91 +80,38 @@ operator=(const Self &other) { /////////////////////////////////////////////////////////////////////////////// // Interface - Voxel : //--------------------------------------------------------------------------- -template -const typename DGtal::VoxelComplex::Object::Point & -DGtal::VoxelComplex::objPointFromVoxel( - const Cell &voxel) const { - ASSERT(isSpel(voxel) == true); - ASSERT(this->belongs(voxel)); - auto &ks = this->space(); - return *(myObject.pointSet().find(ks.uCoords(voxel))); -} - -//--------------------------------------------------------------------------- -template -typename DGtal::VoxelComplex::Object & -DGtal::VoxelComplex::object() { - return myObject; -} +// template +// const typename DGtal::VoxelComplex::Object::Point & +// DGtal::VoxelComplex::objPointFromVoxel( +// const Cell &voxel) const { +// ASSERT(isSpel(voxel) == true); +// ASSERT(this->belongs(voxel)); +// auto &ks = this->space(); +// return *(myObject.pointSet().find(ks.uCoords(voxel))); +// } -template -const typename DGtal::VoxelComplex::Object & -DGtal::VoxelComplex::object() const { - return myObject; -} //----------------------------------------------------------------------------- -template -typename DGtal::VoxelComplex::Object::DigitalSet & -DGtal::VoxelComplex::objectSet() { - return myObject.pointSet(); -} - -template -const typename DGtal::VoxelComplex::Object::DigitalSet & -DGtal::VoxelComplex::objectSet() const { - return myObject.pointSet(); -} -/////////////////////////////////////////////////////////////////////////////// -// Construct methods - VoxelComplex : -template -inline void DGtal::VoxelComplex::construct( - const TObject &obj) { - using TDigitalSet = typename TObject::DigitalSet; - assert(TDigitalSet::Domain::dimension == dimension); - // Save the voxel object in VoxelComplex. - this->myObject = obj; - - for (typename TDigitalSet::ConstIterator it = - this->myObject.pointSet().begin(); - it != this->myObject.pointSet().end(); ++it) { - typedef typename TKSpace::Cells CellsCollection; - typename Parent::KSpace::Cell cell = this->myKSpace->uSpel(*it); - this->insertCell(cell); - CellsCollection n = this->myKSpace->uFaces(cell); - for (typename CellsCollection::ConstIterator itt = n.begin(); - itt < n.end(); ++itt) - this->insertCell(*itt); - } +template +template +inline void DGtal::VoxelComplex::construct( + const TDigitalSet &input_set) { + Parent::construct(input_set); } -template -inline void DGtal::VoxelComplex::construct( - const typename TObject::DigitalSet &input_set, +template +template +inline void DGtal::VoxelComplex::construct( + const TDigitalSet &input_set, const Alias input_table) { Parent::construct(input_set); setSimplicityTable(input_table); - instantiateEmptyObject(input_set); } -template -inline void -DGtal::VoxelComplex::instantiateEmptyObject( - const typename TObject::DigitalSet &dig_set) { - typename TObject::DigitalTopology::ForegroundAdjacency adjF; - typename TObject::DigitalTopology::BackgroundAdjacency adjB; - typename TObject::DigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - typename TObject::DigitalSet empty_set(dig_set.domain()); - this->myObject = TObject(topo, empty_set); -} - -template -void DGtal::VoxelComplex::setSimplicityTable( +template +void DGtal::VoxelComplex::setSimplicityTable( const Alias input_table) { this->myTablePtr = input_table; this->myPointToMaskPtr = @@ -172,28 +119,36 @@ void DGtal::VoxelComplex::setSimplicityTable( this->myIsTableLoaded = true; } -template -const typename DGtal::VoxelComplex +void DGtal::VoxelComplex::copySimplicityTable( + const Self & other) { + myTablePtr = other.myTablePtr; + myPointToMaskPtr = other.myPointToMaskPtr; + myIsTableLoaded = other.myIsTableLoaded; +} + +template +const typename DGtal::VoxelComplex::ConfigMap & -DGtal::VoxelComplex::table() const { +DGtal::VoxelComplex::table() const { return *myTablePtr; } -template +template const bool & -DGtal::VoxelComplex::isTableLoaded() const { +DGtal::VoxelComplex::isTableLoaded() const { return myIsTableLoaded; } -template -const typename DGtal::VoxelComplex +const typename DGtal::VoxelComplex::PointToMaskMap & -DGtal::VoxelComplex::pointToMask() const { +DGtal::VoxelComplex::pointToMask() const { return *myPointToMaskPtr; } //--------------------------------------------------------------------------- -template -inline void DGtal::VoxelComplex::voxelClose( +template +inline void DGtal::VoxelComplex::voxelClose( const Cell &kcell) { auto &ks = this->space(); ASSERT(ks.uDim(kcell) == 3); @@ -207,8 +162,8 @@ inline void DGtal::VoxelComplex::voxelClose( cellsClose(l, direct_faces); } //--------------------------------------------------------------------------- -template -inline void DGtal::VoxelComplex::cellsClose( +template +inline void DGtal::VoxelComplex::cellsClose( Dimension k, const Cells &cells) { if (k <= 0) return; @@ -227,38 +182,47 @@ inline void DGtal::VoxelComplex::cellsClose( } } //--------------------------------------------------------------------------- -template +template inline void -DGtal::VoxelComplex::insertVoxelCell( +DGtal::VoxelComplex::insertVoxelCell( const Cell &kcell, const bool &close_it, const Data &data) { auto &ks = this->space(); ASSERT(ks.uDim(kcell) == 3); this->insertCell(3, kcell, data); - this->objectSet().insert(ks.uCoords(kcell)); if (close_it) voxelClose(kcell); } //--------------------------------------------------------------------------- -template +template inline void -DGtal::VoxelComplex::insertVoxelPoint( +DGtal::VoxelComplex::insertVoxelPoint( const Point &dig_point, const bool &close_it, const Data &data) { auto &ks = this->space(); insertVoxelCell(ks.uSpel(dig_point), close_it, data); } + //--------------------------------------------------------------------------- -template -inline void DGtal::VoxelComplex::clear() { +template +template +inline void +DGtal::VoxelComplex::dumpVoxels(TDigitalSet & in_out_set) { + auto &ks = this->space(); + for (auto it = this->begin(3), itE = this->end(3) ; it != itE ; ++it ){ + in_out_set.insertNew(ks.uCoords(it->first)); + } +} +//--------------------------------------------------------------------------- +template +inline void DGtal::VoxelComplex::clear() { for (Dimension d = 0; d <= dimension; ++d) this->Parent::clear(d); - objectSet().clear(); } //--------------------------------------------------------------------------- -template -void DGtal::VoxelComplex::pointelsFromCell( +template +void DGtal::VoxelComplex::pointelsFromCell( std::set &pointels_out, const Cell &input_cell) const { auto input_dim = this->space().uDim(input_cell); if (input_dim == 0) { @@ -272,8 +236,8 @@ void DGtal::VoxelComplex::pointelsFromCell( } //--------------------------------------------------------------------------- -template -void DGtal::VoxelComplex::spelsFromCell( +template +void DGtal::VoxelComplex::spelsFromCell( std::set &spels_out, const Cell &input_cell) const { auto input_dim = this->space().uDim(input_cell); if (input_dim == this->dimension) { @@ -290,16 +254,12 @@ void DGtal::VoxelComplex::spelsFromCell( } //--------------------------------------------------------------------------- -template -typename DGtal::VoxelComplex::Clique -DGtal::VoxelComplex::Kneighborhood( +template +typename DGtal::VoxelComplex::Clique +DGtal::VoxelComplex::Kneighborhood( const Cell &input_cell) const { - std::set pointels_out; - std::set spels_out; - pointelsFromCell(pointels_out, input_cell); - for (const auto &p : pointels_out) - spelsFromCell(spels_out, p); + auto spels_out = neighborhoodVoxels(input_cell); auto &ks = this->space(); Clique clique(ks); @@ -309,35 +269,43 @@ DGtal::VoxelComplex::Kneighborhood( return clique; } -//--------------------------------------------------------------------------- -template -const TObject &DGtal::VoxelComplex::populateObjectFromCells() { - typename TObject::DigitalTopology::ForegroundAdjacency adjF; - typename TObject::DigitalTopology::BackgroundAdjacency adjB; - typename TObject::DigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); +template +std::set +DGtal::VoxelComplex::neighborhoodVoxels( + const Cell &input_spel) const { - auto &ks = this->space(); - typename TObject::Domain domain(ks.lowerBound(), ks.upperBound()); - myObject = TObject(topo, domain); - for (auto it = this->begin(3), itE = this->end(3); it != itE; ++it) - myObject.pointSet().insertNew(ks.uCoords(it->first)); + std::set pointels_out; + std::set spels_out; + pointelsFromCell(pointels_out, input_spel); + for (const auto &p : pointels_out) + spelsFromCell(spels_out, p); + return spels_out; +} - return myObject; +template +std::set +DGtal::VoxelComplex::properNeighborhoodVoxels( + const Cell &input_spel) const { + + auto spels_out = neighborhoodVoxels(input_spel); + auto search = spels_out.find(input_spel); + if (search != spels_out.end()) { + spels_out.erase(search); + } + return spels_out; } //--------------------------------------------------------------------------- -template -bool DGtal::VoxelComplex::isSpel( +template +bool DGtal::VoxelComplex::isSpel( const Cell &b) const { return (this->space().uDim(b) == this->space().DIM); } //--------------------------------------------------------------------------- -template -typename DGtal::VoxelComplex::Cell -DGtal::VoxelComplex +typename DGtal::VoxelComplex::Cell +DGtal::VoxelComplex::surfelBetweenAdjacentSpels(const Cell &A, const Cell &B) const { @@ -353,14 +321,12 @@ DGtal::VoxelComplex -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_2( - const typename DGtal::VoxelComplex::Object::Point &A, - const typename DGtal::VoxelComplex::Object::Point &B, +DGtal::VoxelComplex::K_2( + const typename KSpace::Point &A, + const typename KSpace::Point &B, bool verbose) const { auto &ks = this->space(); auto orientation_vector = B - A; @@ -468,7 +434,12 @@ DGtal::VoxelComplex::K_2( // Check connectedness using object if not empty bool is_disconnected{false}; if (!is_empty) { - auto new_obj = objectFromSpels(k2_crit); + using DigitalTopology = DGtal::Z3i::DT26_6; + using DigitalSet = DGtal::DigitalSetByAssociativeContainer< + DGtal::Z3i::Domain, + std::unordered_set>; + using NewObject = DGtal::Object; + auto new_obj = objectFromSpels(k2_crit); auto con = new_obj->computeConnectedness(); is_disconnected = (con == DISCONNECTED); } @@ -510,10 +481,10 @@ DGtal::VoxelComplex::K_2( } //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_2(const Cell &A, +DGtal::VoxelComplex::K_2(const Cell &A, const Cell &B, bool verbose) const { // Precondition: @@ -527,10 +498,10 @@ DGtal::VoxelComplex::K_2(const Cell &A, } //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_2(const Cell &face2, +DGtal::VoxelComplex::K_2(const Cell &face2, bool verbose) const { auto &ks = this->space(); ASSERT(ks.uIsSurfel(face2)); @@ -546,10 +517,10 @@ DGtal::VoxelComplex::K_2(const Cell &face2, } //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_1(const Cell &face1, +DGtal::VoxelComplex::K_1(const Cell &face1, bool verbose) const { auto &ks = this->space(); ASSERT(ks.uDim(face1) == 1); @@ -668,10 +639,10 @@ DGtal::VoxelComplex::K_1(const Cell &face1, } //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_0(const Cell &face0, +DGtal::VoxelComplex::K_0(const Cell &face0, bool verbose) const { auto &ks = this->space(); ASSERT(ks.uDim(face0) == 0); @@ -758,10 +729,10 @@ DGtal::VoxelComplex::K_0(const Cell &face0, } //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::K_3(const Cell &voxel, +DGtal::VoxelComplex::K_3(const Cell &voxel, bool verbose) const { auto &ks = this->space(); ASSERT(ks.uDim(voxel) == 3); @@ -782,33 +753,33 @@ DGtal::VoxelComplex::K_3(const Cell &voxel, /* BUG workaround: MSVC compiler error C2244. * It doesn't see the definition of these declarations (Moved to header) -template +template std::array< - typename DGtal::VoxelComplex::CliqueContainer, DGtal::VoxelComplex::CliqueContainer, DGtal::VoxelComplex::dimension + 1 > -DGtal::VoxelComplex::criticalCliques( +DGtal::VoxelComplex::criticalCliques( const Parent & cubical, bool verbose ) const -template +template std::array< - typename DGtal::VoxelComplex::CliqueContainer, DGtal::VoxelComplex::CliqueContainer, DGtal::VoxelComplex::dimension + 1 > -DGtal::VoxelComplex::criticalCliques( +DGtal::VoxelComplex::criticalCliques( bool verbose ) const */ //--------------------------------------------------------------------------- -template -std::pair +std::pair::Clique> -DGtal::VoxelComplex::criticalCliquePair( +DGtal::VoxelComplex::criticalCliquePair( const Dimension d, const CellMapConstIterator &cellMapIterator) const { auto &it = cellMapIterator; auto &cell = it->first; @@ -829,9 +800,9 @@ DGtal::VoxelComplex::criticalCliquePair( } //--------------------------------------------------------------------------- -template -typename DGtal::VoxelComplex::CliqueContainer -DGtal::VoxelComplex::criticalCliquesForD( +template +typename DGtal::VoxelComplex::CliqueContainer +DGtal::VoxelComplex::criticalCliquesForD( const Dimension d, const Parent &cubical, bool verbose) const { #ifdef WITH_OPENMP @@ -890,9 +861,30 @@ return critical; } //--------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////// +template +bool DGtal::VoxelComplex::isSimpleByThinning( + const Cell &input_spel) const { + // x = input_spel ; X = VoxelComplex ~ occupancy of khalimsky space + // a) Get the neighborhood (voxels) of input_spel intersected + // with the voxel complex. -- N^{*}(x) intersection X -- + ASSERT(this->space().uDim(input_spel) == 3); + auto spels_out = this->properNeighborhoodVoxels(input_spel); + auto &ks = this->space(); + Clique clique(ks); + for (const auto &v : spels_out) + clique.insertCell(v); + clique.close(); + // b) Apply a thinning on the result of a) + typename Parent::DefaultCellMapIteratorPriority default_priority; + bool clique_is_closed = true; + functions::collapse( clique, spels_out.begin(), spels_out.end(), default_priority, false /* spels_out is not closed */, clique_is_closed, false /*verbose*/); + // c) If the result is a single pointel, it is reducible + return clique.size() == 1; +} + // Object wrappers : -template -bool DGtal::VoxelComplex::isSimple( +template +bool DGtal::VoxelComplex::isSimple( const Cell &input_cell) const { ASSERT(isSpel(input_cell) == true); @@ -901,16 +893,8 @@ bool DGtal::VoxelComplex::isSimple( *this, this->space().uCoords(input_cell), this->pointToMask()); return (*myTablePtr)[conf]; } else - return myObject.isSimple(objPointFromVoxel(input_cell)); + return isSimpleByThinning(input_cell); } -//--------------------------------------------------------------------------- - -template -bool DGtal::VoxelComplex::isConnected() - const { - return myObject.computeConnectedness() == DGtal::Connectedness::CONNECTED; -} - //--------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////// // Interface - public : @@ -919,12 +903,11 @@ bool DGtal::VoxelComplex::isConnected() * Writes/Displays the object on an output stream. * @param out the output stream where the object is written. */ -template -inline void DGtal::VoxelComplex::selfDisplay( +template +inline void DGtal::VoxelComplex::selfDisplay( std::ostream &out) const { out << "[VoxelComplex dim=" << this->dim() << " chi=" << this->euler(); out << " isTableLoaded? " << ((isTableLoaded()) ? "True" : "False"); - out << " Object.pointSet() size: " << myObject.pointSet().size(); } //--------------------------------------------------------------------------- @@ -932,26 +915,26 @@ inline void DGtal::VoxelComplex::selfDisplay( * Checks the validity/consistency of the object. * @return 'true' if the object is valid, 'false' otherwise. */ -template +template inline bool -DGtal::VoxelComplex::isValid() const { +DGtal::VoxelComplex::isValid() const { return true; } //----------------------------------------------------------------------------- -template +template inline std::string -DGtal::VoxelComplex::className() const { +DGtal::VoxelComplex::className() const { return "VoxelComplex"; } /////////////////////////////////////////////////////////////////////////////// // Implementation of inline functions // -template +template inline std::ostream &DGtal:: operator<<(std::ostream &out, - const VoxelComplex &object) { + const VoxelComplex &object) { object.selfDisplay(out); return out; } diff --git a/src/DGtal/topology/VoxelComplexFunctions.h b/src/DGtal/topology/VoxelComplexFunctions.h index 6b0162bbbf..dbad23f0aa 100644 --- a/src/DGtal/topology/VoxelComplexFunctions.h +++ b/src/DGtal/topology/VoxelComplexFunctions.h @@ -180,7 +180,7 @@ namespace DGtal const typename TComplex::Cell & cell); /** - * Check if input cell only has one neighbor, using @ref Object::topology. + * Check if input cell only has one neighbor, using @ref Object::Topology. * * @tparam TComplex VoxelComplex * @param vc input voxel complex. @@ -353,6 +353,10 @@ namespace DGtal /** * Get all connected components of the input object. * + * @tparam TObject Object Type + * @param input_obj input object + * @param verbose flag to be verbose at execution + * * @return vector of TObject containing the different * connected components of the object. * @@ -369,7 +373,6 @@ namespace DGtal /** * Voxel Complex difference operation. Updates the voxel complex S1 as S1 - S2. * @tparam TKSpace the digital space in which lives the voxel complex. - * @tparam TObject the object type to store voxels and its connectivity. * @tparam TCellContainer the associative container used to store cells within the voxel complex. * * @param[in,out] S1 an input voxel complex, \a S1 - \a S2 as output. @@ -377,30 +380,20 @@ namespace DGtal * * @return a reference to the modified voxel complex S1. */ - template - inline VoxelComplex< TKSpace, TObject, TCellContainer >& - operator-=( VoxelComplex< TKSpace, TObject, TCellContainer >& S1, - const VoxelComplex< TKSpace, TObject, TCellContainer >& S2 ) + template + inline VoxelComplex< TKSpace, TCellContainer >& + operator-=( VoxelComplex< TKSpace, TCellContainer >& S1, + const VoxelComplex< TKSpace, TCellContainer >& S2 ) { - typedef VoxelComplex< TKSpace, TObject, TCellContainer > VC; + typedef VoxelComplex< TKSpace, TCellContainer > VC; for ( Dimension i = 0; i <= VC::dimension; ++i ) setops::operator-=( S1.myCells[ i ],S2.myCells[ i ] ); - // Update Object. Assuming is an AssociativeContainer - auto & S1ObjPoints = S1.myObject.pointSet(); - const auto & S2ObjPoints = S2.myObject.pointSet(); - for(auto it2 = S2ObjPoints.begin(); it2 != S2ObjPoints.end(); ++it2) - { - const auto it_search = S1ObjPoints.find(*it2); - if(it_search != S1ObjPoints.end()) - S1ObjPoints.erase(it_search); - } return S1; } /** * Voxel Complex difference operation. Returns the difference of \a S1 - \a S2. * @tparam TKSpace the digital space in which lives the voxel complex. - * @tparam TObject the object type to store voxels and its connectivity. * @tparam TCellContainer the associative container used to store cells within the voxel complex. * * @param[in] S1 an input voxel complex @@ -408,24 +401,15 @@ namespace DGtal * * @return the voxel complex \a S1 - \a S2. */ - template - inline VoxelComplex< TKSpace, TObject, TCellContainer > - operator-( const VoxelComplex< TKSpace, TObject, TCellContainer >& S1, - const VoxelComplex< TKSpace, TObject, TCellContainer >& S2 ) + template + inline VoxelComplex< TKSpace, TCellContainer > + operator-( const VoxelComplex< TKSpace, TCellContainer >& S1, + const VoxelComplex< TKSpace, TCellContainer >& S2 ) { - typedef VoxelComplex< TKSpace, TObject, TCellContainer > VC; - VC S = S1; + typedef VoxelComplex< TKSpace, TCellContainer > VC; + VC S(S1); for ( Dimension i = 0; i <= VC::dimension; ++i ) setops::operator-=( S.myCells[ i ],S2.myCells[ i ] ); - // Update Object. Assuming is an AssociativeContainer - auto & SObjPoints = S.myObject.pointSet(); - const auto & S2ObjPoints = S2.myObject.pointSet(); - for(auto it2 = S2ObjPoints.begin(); it2 != S2ObjPoints.end(); ++it2) - { - auto it_search = SObjPoints.find(*it2); - if(it_search != SObjPoints.end()) - SObjPoints.erase(it_search); - } return S; } diff --git a/src/DGtal/topology/VoxelComplexFunctions.ih b/src/DGtal/topology/VoxelComplexFunctions.ih index a81419f856..5c50e418b0 100644 --- a/src/DGtal/topology/VoxelComplexFunctions.ih +++ b/src/DGtal/topology/VoxelComplexFunctions.ih @@ -59,7 +59,6 @@ asymetricThinningScheme( using Cell = typename TComplex::Cell; using Data = typename TComplex::Data; - using Object = typename TComplex::Object; // Initialize K set, and VoxelComplex containers; struct FirstComparator @@ -70,16 +69,15 @@ asymetricThinningScheme( } }; std::set, FirstComparator> selected_voxels_per_dim; - Object empty_obj(vc.object().topology(), vc.object().domain()); TComplex already_selected_voxels(vc.space()); - already_selected_voxels.construct(empty_obj); TComplex constraint_set(vc.space()); - constraint_set.construct(empty_obj); auto & Z = selected_voxels_per_dim; auto & Y = already_selected_voxels; auto & K = constraint_set; auto X = vc; + Y.copySimplicityTable(vc); + K.copySimplicityTable(vc); typename TComplex::Parent x_y(vc.space()); typename TComplex::Parent x_k(vc.space()); @@ -180,7 +178,6 @@ persistenceAsymetricThinningScheme( using Cell = typename TComplex::Cell; using Data = typename TComplex::Data; - using Object = typename TComplex::Object; // Initialize Z set, and VoxelComplex containers; struct FirstComparator @@ -190,17 +187,16 @@ persistenceAsymetricThinningScheme( return lhs.first < rhs.first; } }; - Object empty_obj(vc.object().topology(), vc.object().domain()); TComplex already_selected_voxels(vc.space()); - already_selected_voxels.construct(empty_obj); TComplex constraint_set(vc.space()); - constraint_set.construct(empty_obj); auto & Y = already_selected_voxels; auto & K = constraint_set; TComplex X = vc; TComplex x_y(vc.space()); - x_y.construct(empty_obj); + Y.copySimplicityTable(vc); + K.copySimplicityTable(vc); + x_y.copySimplicityTable(vc); bool stability{false}; uint64_t generation{0}; @@ -366,8 +362,7 @@ bool DGtal::functions::skelEnd( const TComplex & vc, const typename TComplex::Cell & cell) { - const auto &ks = vc.space(); - const auto &pnsize = vc.object().properNeighborhoodSize(ks.uCoords(cell)); + const auto pnsize = vc.properNeighborhoodVoxels(cell).size(); return (pnsize == 1); } @@ -376,8 +371,6 @@ bool DGtal::functions::skelSimple( const TComplex & vc, const typename TComplex::Cell & cell) { - // const auto &ks = vc.space(); - // return vc.object().isSimple(ks.uCoords(cell)); return vc.isSimple(cell); } @@ -402,26 +395,40 @@ DGtal::functions::oneIsthmus(const TComplex & vc, auto &ks = vc.space(); auto point_cell = ks.uCoords(cell); - auto spN = vc.object().properNeighborhood(point_cell); - if (isZeroSurface(spN)) return true; + // Create an object from the set. + using DigitalTopology = DGtal::Z3i::DT26_6; + using DigitalSet = DGtal::DigitalSetByAssociativeContainer< + DGtal::Z3i::Domain, + std::unordered_set>; + using Object = DGtal::Object; + DigitalTopology::ForegroundAdjacency adjF; + DigitalTopology::BackgroundAdjacency adjB; + auto domain = DGtal::Z3i::Domain(ks.lowerBound(), ks.upperBound()); + DigitalTopology topo( + adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); + Object object(topo, domain); + for(auto & properNeighborhoodVoxel : vc.properNeighborhoodVoxels(cell)) + { + object.pointSet().insertNew(ks.uCoords(properNeighborhoodVoxel)); + } - // else thinning - // From TComplex::Object::SmallObject to TComplex::Object - typename TComplex::Object pN( - vc.object().topology(), - vc.object().domain()); - for(auto it = spN.begin(), itE = spN.end() ; it != itE ; ++it) - pN.pointSet().insertNew(*it); + // auto spN = vc.object().properNeighborhood(point_cell); + if (isZeroSurface(object)) return true; + // else thinning TComplex pre_thin(ks); - pre_thin.construct(pN); - + pre_thin.construct(object.pointSet()); auto after_thin = asymetricThinningScheme( pre_thin, selectFirst, skelUltimate); - return isZeroSurface(after_thin.object()); + object.pointSet().clear(); + for (auto it = after_thin.begin(3), itE = after_thin.end(3) ; it != itE ; ++it ){ + object.pointSet().insertNew(ks.uCoords(it->first)); + } + + return isZeroSurface(object); } template < typename TComplex > @@ -431,26 +438,38 @@ DGtal::functions::twoIsthmus( const TComplex & vc, { auto &ks = vc.space(); auto point_cell = ks.uCoords(cell); - auto spN = vc.object().properNeighborhood(point_cell); - if (isOneSurface(spN)) return true; + // Create an object from the set. + using DigitalTopology = DGtal::Z3i::DT26_6; + using DigitalSet = DGtal::DigitalSetByAssociativeContainer< + DGtal::Z3i::Domain, + std::unordered_set>; + using Object = DGtal::Object; + DigitalTopology::ForegroundAdjacency adjF; + DigitalTopology::BackgroundAdjacency adjB; + auto domain = DGtal::Z3i::Domain(ks.lowerBound(), ks.upperBound()); + DigitalTopology topo( + adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); + Object object(topo, domain); + for(auto & properNeighborhoodVoxel : vc.properNeighborhoodVoxels(cell)) + { + object.pointSet().insertNew(ks.uCoords(properNeighborhoodVoxel)); + } + if (isOneSurface(object)) return true; // else thinning - // From TComplex::Object::SmallObject to TComplex::Object - typename TComplex::Object pN( - vc.object().topology(), - vc.object().domain()); - for(auto it = spN.begin(), itE = spN.end() ; it != itE ; ++it) - pN.pointSet().insertNew(*it); - TComplex pre_thin(ks); - pre_thin.construct(pN); - + pre_thin.construct(object.pointSet()); - auto after_thin = asymetricThinningScheme(pre_thin, + auto after_thin = asymetricThinningScheme( pre_thin, selectFirst, skelUltimate); - return isOneSurface(after_thin.object()); + object.pointSet().clear(); + for (auto it = after_thin.begin(3), itE = after_thin.end(3) ; it != itE ; ++it ){ + object.pointSet().insertNew(ks.uCoords(it->first)); + } + + return isOneSurface(object); } template < typename TComplex > diff --git a/src/DGtal/topology/doc/moduleVoxelComplex.dox b/src/DGtal/topology/doc/moduleVoxelComplex.dox index 4bb1665e86..6e991bb48e 100644 --- a/src/DGtal/topology/doc/moduleVoxelComplex.dox +++ b/src/DGtal/topology/doc/moduleVoxelComplex.dox @@ -15,7 +15,7 @@ namespace DGtal { Part of the \ref packageTopology. This part of the manual describes how to represent and process -arbitrary voxel complexes, which are cubical complexes with an associated DigitalObject. +arbitrary voxel complexes, which are cubical complexes specialized to work with voxels. [TOC] @@ -31,12 +31,6 @@ This is an implementation of the Critical Kernel framework based on M.Couprie an DGtalTools has an associated command line interface executable: criticalKernelsThinning3D. -VoxelComplex inherits from CubicalComplex, adding an Object member storing -the voxels(spels) of an input image. This allows -the use of the isSimple method from Object ( Object::isSimple ), and also the ObjectBoostGraphInterface.h. -At the cost of more memory and slower runtime. Future work here might try to use a isSimple -method using exclusively CubicalComplex framework. - @section dgtal_vcomplex_sec2 Definitions Summary of definitions used, but highly recommended to read the original @@ -87,8 +81,7 @@ Here we use \a critical \a kernels to ensure the same homotopy type after thinni @section dgtal_vcomplex_sec3 Initializing a voxel complex. -A \b voxel \b complex \a V is a \b cubical \b complex (living in a Khalimsky space) -with a member of type Object. +A \b voxel \b complex \a V is a \b cubical \b complex (living in a Khalimsky space). To create a VoxelComplex, we need to specify in which Khalimsky space it lives and also, optionally, the type of container used for @@ -102,26 +95,20 @@ using DigitalTopology = DGtal::Z3i::DT26_6; using DigitalSet = DGtal::DigitalSetByAssociativeContainer< DGtal::Z3i::Domain, std::unordered_set< typename DGtal::Z3i::Domain::Point> >; -using Object = DGtal::Object; -using Complex = DGtal::VoxelComplex; // Type of VoxelComplex. + +using CellContainerMap = std::unordered_map: +using Complex = DGtal::VoxelComplex; // Type of VoxelComplex. KSpace ks; // The cellular grid space ks.init( Point( 0,0,0 ), Point( 100,100,100 ), true ); // Limits of the grid space -// Voxel Complex needs a KSpace and can be populated with an object. -// Create the object from a digital set and topology +// Voxel Complex needs a KSpace and can be populated with a digital set. Point p1(-10, -10, -10); Point p2(10, 10, 10); Domain domain(p1, p2); Point c(0, 0, 0); DigitalSet a_set(domain); -DigitalTopology::ForegroundAdjacency adjF; -DigitalTopology::BackgroundAdjacency adjB; -DigitalTopology topo( adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - -auto object = Object(topo, a_set); - Complex complex( ks ); -complex.construct( object ); +complex.construct( a_set ); // load LUT to check for simplicity faster. complex.setSimplicityTable(functions::loadTable(simplicity::tableSimple26_6)); @@ -141,7 +128,8 @@ that given a d-cell (pointel, linel, surfel, spel) returns a d-clique and a bool VoxelComplex::K_0,VoxelComplex::K_1, VoxelComplex::K_2, and VoxelComplex::K_3 return a pair where Clique=CubicalComplex, and the bool is true if the Clique is critical. -VoxelComplex::K_3 applies to Voxels, and it uses the isSimple method of Object. +VoxelComplex::K_3 applies to Voxels, it can either create a small object to use the isSimple method of Object, +or if a pre-compute LUT table of simplicity is loaded, it will look up the result based on the occupancy of the neighborhood (recommended). VoxelComplex::K_2 applies to surfels, @@ -184,7 +172,7 @@ testVoxelComplex.cpp provides example of how to use with isIsthmus table. auto table = *functions::loadTable(isthmusicity::tableOneIsthmus); // auto table = *functions::loadTable(isthmusicity::tableIsthmus); -auto pointToMaskMap = *functions::mapZeroPointNeighborhoodToConfigurationMask< Object::Point>(); +auto pointToMaskMap = *functions::mapZeroPointNeighborhoodToConfigurationMask< Point>(); auto isthmusTable = [&table, &pointToMaskMap](const Complex &fc, const Complex::Cell &c) { diff --git a/src/DGtal/topology/tables/NeighborhoodTablesGenerators.h b/src/DGtal/topology/tables/NeighborhoodTablesGenerators.h index 6e6befbddc..ecf0928c14 100644 --- a/src/DGtal/topology/tables/NeighborhoodTablesGenerators.h +++ b/src/DGtal/topology/tables/NeighborhoodTablesGenerators.h @@ -137,26 +137,18 @@ namespace DGtal { > skelFunction ) { - using Object = typename TVoxelComplex::Object; - using DigitalSet = typename Object::DigitalSet ; - using Point = typename Object::Point ; - using Domain = typename DigitalSet::Domain ; + using Domain = DGtal::Z3i::Domain; + using Point = typename Domain::Point ; + using DigitalSet = DigitalSetByAssociativeContainer< + Domain, std::unordered_set< Point > >; using DomainConstIterator = typename Domain::ConstIterator ; using KSpace = typename TVoxelComplex::KSpace; - using DigitalTopology = typename Object::DigitalTopology; - using ForegroundAdjacency = typename Object::ForegroundAdjacency; - using BackgroundAdjacency = typename Object::BackgroundAdjacency; - ForegroundAdjacency adjF; - BackgroundAdjacency adjB; - DigitalTopology dt( adjF, adjB, - DigitalTopologyProperties::JORDAN_DT); Point p1 = Point::diagonal( -1 ); Point p2 = Point::diagonal( 1 ); Point c = Point::diagonal( 0 ); Domain domain( p1, p2 ); DigitalSet shapeSet( domain ); - Object shape( dt, shapeSet ); unsigned int k = 0; for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it ) if ( *it != c ) ++k; @@ -166,11 +158,11 @@ namespace DGtal { KSpace ks; // Pad KSpace domain. - ks.init(shape.domain().lowerBound() + Point::diagonal( -1 ) , - shape.domain().upperBound() + Point::diagonal( 1 ), + ks.init(domain.lowerBound() + Point::diagonal( -1 ) , + domain.upperBound() + Point::diagonal( 1 ), true); TVoxelComplex vc(ks); - vc.construct(shape); + vc.construct(shapeSet); for ( unsigned int cfg = 0; cfg < nbCfg; ++cfg ){ if ( ( cfg % 1000 ) == 0 ) trace.progressBar( (double) cfg, (double) nbCfg ); diff --git a/tests/topology/testVoxelComplex.cpp b/tests/topology/testVoxelComplex.cpp index 8637ee4cb7..dc417bbd5c 100644 --- a/tests/topology/testVoxelComplex.cpp +++ b/tests/topology/testVoxelComplex.cpp @@ -53,7 +53,7 @@ using namespace std; using namespace DGtal; /////////////////////////////////////////////////////////////////////////// -// Fixture for object from a diamond set and DT26_6 topology. +// Fixture for object from a diamond set /////////////////////////////////////////////////////////////////////////// struct Fixture_complex_diamond { /////////////////////////////////////////////////////////// @@ -67,28 +67,27 @@ struct Fixture_complex_diamond { using FixtureDigitalSet = DGtal::DigitalSetByAssociativeContainer< DGtal::Z3i::Domain, std::unordered_set>; - using FixtureObject = - DGtal::Object; - using FixtureComplex = DGtal::VoxelComplex; + using FixtureComplex = DGtal::VoxelComplex; - /////////////////////////////////////////////////////////// - // fixture data - FixtureObject obj_fixture; - FixtureComplex complex_fixture; - KSpace ks_fixture; // needed because ConstAlias in CC constructor. - /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////// - Fixture_complex_diamond() : complex_fixture(ks_fixture) { - create_complex_from_object(create_object()); + Fixture_complex_diamond() : + complex_fixture(ks_fixture) { + create_complex_from_set(create_set()); } + /////////////////////////////////////////////////////////// + // fixture data + FixtureComplex complex_fixture; + KSpace ks_fixture; // needed because ConstAlias in CC constructor. + /////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////// // Function members /////////////////////////////////////////////////////////// - FixtureObject &create_object() { + FixtureDigitalSet create_set() { using namespace DGtal; // trace.beginBlock ( "Create Fixture_object_diamond" ); @@ -98,26 +97,22 @@ struct Fixture_complex_diamond { Point c(0, 0, 0); // diamond of radius 4 - FixtureDigitalSet diamond_set(domain); + FixtureDigitalSet set_fixture(domain); for (auto it = domain.begin(); it != domain.end(); ++it) { if ((*it - c).norm1() <= 3) - diamond_set.insertNew(*it); + set_fixture.insertNew(*it); } - diamond_set.erase(c); + set_fixture.erase(c); - FixtureDigitalTopology::ForegroundAdjacency adjF; - FixtureDigitalTopology::BackgroundAdjacency adjB; - FixtureDigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - return obj_fixture = FixtureObject(topo, diamond_set); + return set_fixture; } - FixtureComplex &create_complex_from_object(FixtureObject &input_obj) { + FixtureComplex &create_complex_from_set(const FixtureDigitalSet &input_set) { - ks_fixture.init(input_obj.domain().lowerBound(), - input_obj.domain().upperBound(), true); + ks_fixture.init(input_set.domain().lowerBound(), + input_set.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); - complex_fixture.construct(input_obj); + complex_fixture.construct(input_set); return complex_fixture; } }; @@ -251,47 +246,27 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Faces of voxel", } TEST_CASE_METHOD(Fixture_complex_diamond, "Neighbors from Object and KSpace", - "[neighborhood]") { + "[neighborhood]") { auto &vc = complex_fixture; - SECTION(" comparing neighbors from Kspace and from Object") { + SECTION(" get neighbors from Kspace") { { size_t dim_voxel = 3; auto it = vc.begin(dim_voxel); for (auto &&n : std::vector(10)) ++it; auto cell = it->first; - auto point_from_objectSet_1 = vc.objPointFromVoxel(cell); auto point_from_kspace_1 = cell.preCell().coordinates; - SECTION( - " points from Kspace and digital set have different coords ") { - // point coordinates are different in the Kspace and in - // DigitalSet. - CHECK(point_from_objectSet_1 != point_from_kspace_1); - SECTION("But uCoords from KSpace gives same coords than the " - "object set") { - CHECK(vc.space().uCoords(cell) == point_from_objectSet_1); - CHECK(vc.space().uKCoords(cell) == point_from_kspace_1); - } - } - - SECTION("properNeighborhood from Object with full topology" - "outputs all adjacent voxels") { - auto neigh_obj = - vc.object().neighborhood(point_from_objectSet_1); - CHECK(neigh_obj.size() == 12); - auto propN_obj = - vc.object().properNeighborhood(point_from_objectSet_1); - CHECK(propN_obj.size() == 11); + size_t expected_num_adjacent_voxels = 12; - SECTION("properNeighborhood from KSpace" - "does not output all adjacent voxels.") { + SECTION("properNeighborhood from KSpace" + "does not output all adjacent voxels.") { - auto neigh_k = vc.space().uNeighborhood(cell); - CHECK(neigh_k.size() != neigh_obj.size()); + size_t expected_kspace_neighborhood = 7; + auto neigh_k = vc.space().uNeighborhood(cell); + CHECK(neigh_k.size() == expected_kspace_neighborhood); - auto propN_k = vc.space().uProperNeighborhood(cell); - CHECK(propN_k.size() != propN_obj.size()); - } + auto propN_k = vc.space().uProperNeighborhood(cell); + CHECK(propN_k.size() == expected_kspace_neighborhood - 1); } SECTION("Getting associated pointels and voxels from input_cell") { @@ -301,16 +276,16 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Neighbors from Object and KSpace", for (auto &&p : pointel_set) vc.spelsFromCell(voxel_set, p); SECTION("Gets desired full adjancency for voxels") { - CHECK(voxel_set.size() == 12); + CHECK(voxel_set.size() == expected_num_adjacent_voxels); } auto clique = vc.Kneighborhood(cell); - CHECK(clique.nbCells(3) == 12); + CHECK(clique.nbCells(3) == expected_num_adjacent_voxels); } } } } -TEST_CASE_METHOD(Fixture_complex_diamond, "Test Object Wrappers", "[object]") { +TEST_CASE_METHOD(Fixture_complex_diamond, "Test Simplicity", "[simplicity]") { auto &vc = complex_fixture; size_t dim_voxel = 3; auto cit = vc.begin(dim_voxel); @@ -329,22 +304,10 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Test Object Wrappers", "[object]") { } // Border points are simple in diamond. - auto border_size = vc.object().border().size(); + // auto border_size = vc.object().border().size(); + size_t border_size = 44; REQUIRE(nsimples == border_size); } - - SECTION("querying object connectivity") { - REQUIRE(vc.isConnected() == true); - } -} - -TEST_CASE_METHOD(Fixture_complex_diamond, "connectedComponents", - "[object][functions][components]") { - auto &vc = complex_fixture; - SECTION("getting connected components") { - auto obj_components = functions::connectedComponents(vc.object(), true); - REQUIRE(obj_components.size() == 1); - } } TEST_CASE_METHOD(Fixture_complex_diamond, "Test table wrappers", @@ -370,7 +333,7 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Test table wrappers", } // Border points are simple in diamond. - auto border_size = vc.object().border().size(); + size_t border_size = 44; REQUIRE(nsimples == border_size); } } @@ -382,29 +345,33 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Cliques Masks K_2", "[clique]") { ++itc; auto cell = itc->first; Point p_cell = vc.space().uCoords(cell); + auto neigh6 = vc.space().uProperNeighborhood(cell); + REQUIRE(neigh6.size() == 6); + KSpace::Cells cells; + for(auto & n : neigh6) + if(vc.belongs(n)) cells.push_back(n); + REQUIRE(cells.size() == 2); - auto voxel_point = vc.objPointFromVoxel(cell); - auto neigh6 = vc.object().geodesicNeighborhood( - DGtal::Z3i::adj6, voxel_point, sqrt(2.0) / 2.0); - REQUIRE(neigh6.size() == 2); // It is a corner std::vector> cliques_p; bool verbose = true; - for (auto &&n : neigh6.pointSet()) { - cliques_p.emplace_back(vc.K_2(p_cell, n, verbose)); + for (auto && cell_n : cells) { + auto cell_point = vc.space().uCoords(cell_n); + cliques_p.emplace_back(vc.K_2(p_cell, cell_point, verbose)); auto &is_critical = cliques_p.back().first; auto &k2_clique = cliques_p.back().second; CHECK(is_critical == true); CHECK(k2_clique.nbCells(3) == 2); } + SECTION(" Check same results for different K_2 interfaces") { - for (auto &&n : neigh6.pointSet()) { - auto cell_n = vc.space().uSpel(n); + for (auto && cell_n : cells) { auto co_face = vc.surfelBetweenAdjacentSpels(cell_n, cell); + auto cell_point = vc.space().uCoords(cell_n); using namespace DGtal::functions; - CHECK(isEqual(vc.K_2(p_cell, n, false).second, + CHECK(isEqual(vc.K_2(p_cell, cell_point, false).second, vc.K_2(cell, cell_n, false).second) == true); - CHECK(isEqual(vc.K_2(p_cell, n, false).second, + CHECK(isEqual(vc.K_2(p_cell, cell_point, false).second, vc.K_2(co_face, false).second) == true); } // endfor } // then_interfaces @@ -418,10 +385,6 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Cliques Masks K_1", "[clique]") { auto cell = itc->first; Point p_cell = vc.space().uCoords(cell); - auto voxel_point = vc.objPointFromVoxel(cell); - auto neigh6 = vc.object().geodesicNeighborhood( - DGtal::Z3i::adj6, voxel_point, sqrt(2.0) / 2.0); - REQUIRE(neigh6.size() == 2); // It is a corner SECTION("K_1 mask from a linel") { auto linel = vc.space().uCell(cell.preCell().coordinates + Point{0, 1, 1}); @@ -444,10 +407,6 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Cliques Masks K_0", "[clique]") { auto cell = itc->first; Point p_cell = vc.space().uCoords(cell); - auto voxel_point = vc.objPointFromVoxel(cell); - auto neigh6 = vc.object().geodesicNeighborhood( - DGtal::Z3i::adj6, voxel_point, sqrt(2.0) / 2.0); - REQUIRE(neigh6.size() == 2); // It is a corner SECTION("K_0 mask from a pointel") { auto pointel = vc.space().uPointel(p_cell); // auto pointel = vc.space().uPointel(Point{0,0,0}); @@ -482,6 +441,7 @@ TEST_CASE_METHOD(Fixture_complex_diamond, "Get All Critical Cliques of diamond", } } + /////////////////////////////////////////////////////////////////////////// // Fixture for complex fig 4 of Asymmetric parallel 3D thinning scheme /////////////////////////////////////////////////////////////////////////// @@ -493,19 +453,14 @@ struct Fixture_complex_fig4 { using Domain = DGtal::Z3i::Domain; using KSpace = DGtal::Z3i::KSpace; - using FixtureDigitalTopology = DGtal::Z3i::DT26_6; using FixtureDigitalSet = DGtal::DigitalSetByAssociativeContainer< DGtal::Z3i::Domain, std::unordered_set>; - using FixtureObject = - DGtal::Object; using FixtureMap = std::unordered_map; - using FixtureComplex = - DGtal::VoxelComplex; + using FixtureComplex = DGtal::VoxelComplex; /////////////////////////////////////////////////////////// // fixture data - FixtureObject obj_fixture; FixtureComplex complex_fixture; KSpace ks_fixture; // needed because ConstAlias in CC constructor. /////////////////////////////////////////////////////////// @@ -514,13 +469,13 @@ struct Fixture_complex_fig4 { // Constructor /////////////////////////////////////////////////////////// Fixture_complex_fig4() : complex_fixture(ks_fixture) { - create_complex_from_object(create_object()); + create_complex_from_set(create_set()); } /////////////////////////////////////////////////////////// // Function members /////////////////////////////////////////////////////////// - FixtureObject &create_object() { + FixtureDigitalSet create_set() { using namespace DGtal; Point p1(-10, -10, -10); @@ -554,19 +509,15 @@ struct Fixture_complex_fig4 { Point r1(1, 3, -2); fig4_set.insertNew(r1); - FixtureDigitalTopology::ForegroundAdjacency adjF; - FixtureDigitalTopology::BackgroundAdjacency adjB; - FixtureDigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - return obj_fixture = FixtureObject(topo, fig4_set); + return fig4_set; } - FixtureComplex &create_complex_from_object(FixtureObject &input_obj) { + FixtureComplex &create_complex_from_set(const FixtureDigitalSet &input_set) { - ks_fixture.init(input_obj.domain().lowerBound(), - input_obj.domain().upperBound(), true); + ks_fixture.init(input_set.domain().lowerBound(), + input_set.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); - complex_fixture.construct(input_obj); + complex_fixture.construct(input_set); return complex_fixture; } }; @@ -588,51 +539,68 @@ TEST_CASE_METHOD(Fixture_complex_fig4, "Get All Critical Cliques of fig4", CHECK(criticals[0].size() == 6); } } + +/* zeroSurance and oneSurface */ TEST_CASE_METHOD(Fixture_complex_fig4, "zeroSurface and oneSurface", "[isSurface][function]") { auto &vc = complex_fixture; using namespace DGtal::functions; using Point = FixtureComplex::Point; vc.clear(); - vc.objectSet().clear(); Point c(0, 0, 0); { - vc.objectSet().insertNew(c); vc.insertCell(3, vc.space().uSpel(c)); } Point r(0, 1, 0); { - vc.objectSet().insertNew(r); vc.insertCell(3, vc.space().uSpel(r)); } Point l(0, -1, 0); { - vc.objectSet().insertNew(l); vc.insertCell(3, vc.space().uSpel(l)); } + // Init an object + using DigitalTopology = DGtal::Z3i::DT26_6; + using DigitalSet = DGtal::DigitalSetByAssociativeContainer< + DGtal::Z3i::Domain, + std::unordered_set>; + using Object = DGtal::Object; + DigitalTopology::ForegroundAdjacency adjF; + DigitalTopology::BackgroundAdjacency adjB; + auto domain = DGtal::Z3i::Domain(ks_fixture.lowerBound(), ks_fixture.upperBound()); + DigitalTopology topo( + adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); + SECTION("checking zero surfaces of original set") { std::set zeroSurfacesCells; - for (const auto &p : vc.objectSet()) { - auto small_obj = vc.object().properNeighborhood(p); + DigitalSet voxel_set(domain); + vc.dumpVoxels(voxel_set); + Object object(topo, voxel_set); + for (const auto &p : voxel_set) { + auto small_obj = object.properNeighborhood(p); if (isZeroSurface(small_obj)) zeroSurfacesCells.insert(p); } CHECK(zeroSurfacesCells.size() == 1); } + SECTION("checking one surfaces of original set") { Point u(-1, 0, 0); { - vc.objectSet().insertNew(u); vc.insertCell(3, vc.space().uSpel(u)); } Point d(1, 0, 0); { - vc.objectSet().insertNew(d); vc.insertCell(3, vc.space().uSpel(d)); } + std::set oneSurfacesCells; - for (const auto &p : vc.objectSet()) { - auto small_obj = vc.object().properNeighborhood(p); + DigitalSet voxel_set(domain); + vc.dumpVoxels(voxel_set); + Object object(topo, voxel_set); + + for (const auto &p : voxel_set) { + auto small_obj = object.properNeighborhood(p); if (isOneSurface(small_obj)) oneSurfacesCells.insert(p); } @@ -655,30 +623,27 @@ struct Fixture_isthmus { using FixtureDigitalSet = DGtal::DigitalSetByAssociativeContainer< DGtal::Z3i::Domain, std::unordered_set>; - using FixtureObject = - DGtal::Object; using FixtureMap = std::unordered_map; - using FixtureComplex = - DGtal::VoxelComplex; + using FixtureComplex = DGtal::VoxelComplex; /////////////////////////////////////////////////////////// // fixture data - FixtureObject obj_fixture; FixtureComplex complex_fixture; + FixtureDigitalSet set_fixture; KSpace ks_fixture; // needed because ConstAlias in CC constructor. /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////// - Fixture_isthmus() : complex_fixture(ks_fixture) { - create_complex_from_object(create_object()); + Fixture_isthmus() : complex_fixture(ks_fixture), set_fixture(create_set()) { + create_complex_from_set(set_fixture); } /////////////////////////////////////////////////////////// // Function members /////////////////////////////////////////////////////////// - FixtureObject &create_object() { + FixtureDigitalSet create_set() { using namespace DGtal; Point p1(-10, -10, -10); @@ -736,19 +701,15 @@ struct Fixture_isthmus { Point c62(-2, 6, -1); fig6_set.insertNew(c62); - FixtureDigitalTopology::ForegroundAdjacency adjF; - FixtureDigitalTopology::BackgroundAdjacency adjB; - FixtureDigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - return obj_fixture = FixtureObject(topo, fig6_set); + return fig6_set; } - FixtureComplex &create_complex_from_object(FixtureObject &input_obj) { + FixtureComplex &create_complex_from_set(const FixtureDigitalSet &input_set) { - ks_fixture.init(input_obj.domain().lowerBound(), - input_obj.domain().upperBound(), true); + ks_fixture.init(input_set.domain().lowerBound(), + input_set.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); - complex_fixture.construct(input_obj); + complex_fixture.construct(input_set); return complex_fixture; } }; @@ -758,17 +719,20 @@ TEST_CASE_METHOD(Fixture_isthmus, "Thin disconnected complex", using namespace DGtal::functions; auto &vc = complex_fixture; auto &ks = vc.space(); - // Delete one point and reconstruct complex. Point x(-1, 4, 0); - obj_fixture.pointSet().erase(x); + set_fixture.erase(x); + // Delete one point and reconstruct complex. + /* obj_fixture.pointSet().erase(x); */ vc.clear(); - vc.construct(obj_fixture); + vc.construct(set_fixture); SECTION("with skelUltimate") { auto vc_new = asymetricThinningScheme( vc, selectFirst, skelUltimate); CHECK(vc_new.nbCells(3) == 2); } } + + TEST_CASE_METHOD(Fixture_isthmus, "Check isthmus", "[isthmus][function]") { auto &vc = complex_fixture; using namespace DGtal::functions; @@ -778,7 +742,7 @@ TEST_CASE_METHOD(Fixture_isthmus, "Check isthmus", "[isthmus][function]") { SECTION("checking one isthmus") { std::set isthmus; - for (const auto &p : vc.objectSet()) { + for (const auto &p : set_fixture) { if (oneIsthmus(vc, ks.uSpel(p))) isthmus.insert(p); } @@ -789,7 +753,7 @@ TEST_CASE_METHOD(Fixture_isthmus, "Check isthmus", "[isthmus][function]") { SECTION("checking 2 isthmus") { std::set isthmus; - for (const auto &p : vc.objectSet()) { + for (const auto &p : set_fixture) { if (twoIsthmus(vc, ks.uSpel(p))) isthmus.insert(p); } @@ -800,7 +764,7 @@ TEST_CASE_METHOD(Fixture_isthmus, "Check isthmus", "[isthmus][function]") { SECTION("checking 1 and 2 isthmus") { std::set isthmus; - for (const auto &p : vc.objectSet()) { + for (const auto &p : set_fixture) { if (skelIsthmus(vc, ks.uSpel(p))) isthmus.insert(p); } @@ -811,7 +775,6 @@ TEST_CASE_METHOD(Fixture_isthmus, "Check isthmus", "[isthmus][function]") { CHECK(yit != isthmus.end()); } } - TEST_CASE_METHOD(Fixture_isthmus, "Thin complex", "[isthmus][thin][function]") { using namespace DGtal::functions; auto &vc = complex_fixture; @@ -859,15 +822,14 @@ TEST_CASE_METHOD(Fixture_isthmus, "Persistence thin", CHECK(vc_new.nbCells(3) == 5); } SECTION("with oneIsthmus") { - /* Not using LUT skel function (slow): - auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( - vc, selectRandom, oneIsthmus, 0); - */ + // Not using LUT skel function (slow): + //auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( + // vc, selectRandom, oneIsthmus, 0); + // // with LUT: auto table = *functions::loadTable(isthmusicity::tableOneIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto oneIsthmusTable = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) { @@ -878,15 +840,14 @@ TEST_CASE_METHOD(Fixture_isthmus, "Persistence thin", CHECK(vc_new.nbCells(3) == 3); } SECTION("with twoIsthmus") { - /* Not using LUT skel function (slow): - auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( - vc, selectRandom, twoIsthmus, 0); - */ + // Not using LUT skel function (slow): + //auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( + // vc, selectRandom, twoIsthmus, 0); + // // with LUT: auto table = *functions::loadTable(isthmusicity::tableTwoIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto twoIsthmusTable = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) { @@ -897,15 +858,14 @@ TEST_CASE_METHOD(Fixture_isthmus, "Persistence thin", CHECK(vc_new.nbCells(3) == 1); } SECTION("with skelIsthmus") { - /* Not using LUT skel function (slow): - auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( - vc, selectRandom, skelIsthmus, 0); - */ + // Not using LUT skel function (slow): + //auto vc_new = persistenceAsymetricThinningScheme< FixtureComplex >( + // vc, selectRandom, skelIsthmus, 0); + // // with LUT: auto table = *functions::loadTable(isthmusicity::tableIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto isthmusTable = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) { @@ -914,26 +874,6 @@ TEST_CASE_METHOD(Fixture_isthmus, "Persistence thin", auto vc_new = persistenceAsymetricThinningScheme( vc, selectRandom, isthmusTable, 0); CHECK(vc_new.nbCells(3) == 3); - // SECTION( "visualize the thining" ){ - // int argc(1); - // char** argv(nullptr); - // QApplication app(argc, argv); - // Viewer3D<> viewer(ks_fixture); - // viewer.show(); - // - // viewer.setFillColor(Color(200, 200, 200, 100)); - // for ( auto it = vc_new.begin(3); it!= vc_new.end(3); ++it ) - // viewer << it->first; - // - // viewer.setFillColor(Color(200, 200, 200, 100)); - // // All kspace voxels - // viewer.setFillColor(Color(40, 200, 55, 30)); - // for ( auto it = vc.begin(3); it!= vc.end(3); ++it ) - // viewer << it->first; - // - // viewer << Viewer3D<>::updateDisplay; - // app.exec(); - // } } } @@ -951,30 +891,27 @@ struct Fixture_X { using FixtureDigitalSet = DGtal::DigitalSetByAssociativeContainer< DGtal::Z3i::Domain, std::unordered_set>; - using FixtureObject = - DGtal::Object; using FixtureMap = std::unordered_map; - using FixtureComplex = - DGtal::VoxelComplex; + using FixtureComplex = DGtal::VoxelComplex; /////////////////////////////////////////////////////////// // fixture data - FixtureObject obj_fixture; FixtureComplex complex_fixture; + FixtureDigitalSet set_fixture; KSpace ks_fixture; // needed because ConstAlias in CC constructor. /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////// - Fixture_X() : complex_fixture(ks_fixture) { - create_complex_from_object(create_object()); + Fixture_X() : complex_fixture(ks_fixture), set_fixture(create_set()) { + create_complex_from_set(set_fixture); } /////////////////////////////////////////////////////////// // Function members /////////////////////////////////////////////////////////// - FixtureObject &create_object() { + FixtureDigitalSet create_set() { using namespace DGtal; Point p1(-30, -30, -30); @@ -1022,22 +959,19 @@ struct Fixture_X { } } - FixtureDigitalTopology::ForegroundAdjacency adjF; - FixtureDigitalTopology::BackgroundAdjacency adjB; - FixtureDigitalTopology topo( - adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); - return obj_fixture = FixtureObject(topo, a_set); + return a_set; } - FixtureComplex &create_complex_from_object(FixtureObject &input_obj) { + FixtureComplex &create_complex_from_set(FixtureDigitalSet &input_set) { - ks_fixture.init(input_obj.domain().lowerBound(), - input_obj.domain().upperBound(), true); + ks_fixture.init(input_set.domain().lowerBound(), + input_set.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); - complex_fixture.construct(input_obj); + complex_fixture.construct(input_set); return complex_fixture; } }; + TEST_CASE_METHOD(Fixture_X, "X Thin", "[x][persistence][isthmus][thin][function]") { using namespace DGtal::functions; @@ -1071,19 +1005,19 @@ TEST_CASE_METHOD(Fixture_X, "X Thin with Isthmus, and tables", auto &ks = vc.space(); bool verbose = true; - SECTION("Compute with skelIsthmus") { - trace.beginBlock("skelIsthmus"); - auto vc_new = asymetricThinningScheme( - vc, selectRandom, skelIsthmus, - verbose); - trace.endBlock(); - } + // Disabled to reduce test time + // SECTION("Compute with skelIsthmus") { + // trace.beginBlock("Fixture_X skelIsthmus"); + // auto vc_new = asymetricThinningScheme( + // vc, selectRandom, skelIsthmus, + // verbose); + // trace.endBlock(); + // } SECTION("Compute with skelWithTable (isIsthmus)") { - trace.beginBlock("skelIsthmus with table"); + trace.beginBlock("Fixture_X skelIsthmus with table"); auto table = *functions::loadTable(isthmusicity::tableIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto skelWithTableIsthmus = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) { @@ -1097,14 +1031,13 @@ TEST_CASE_METHOD(Fixture_X, "X Thin with Isthmus, and tables", } SECTION("Compute with skelWithTable (isIsthmus) and empty Object") { - trace.beginBlock("skelIsthmus with table (empty objectSet)"); + trace.beginBlock("Fixture_X skelIsthmus with table (empty objectSet)"); vc.setSimplicityTable( functions::loadTable(simplicity::tableSimple26_6)); - vc.objectSet().clear(); + vc.clear(); auto table = *functions::loadTable(isthmusicity::tableIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto skelWithTableIsthmus = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) { @@ -1123,15 +1056,14 @@ TEST_CASE_METHOD(Fixture_X, "X DistanceMap", "[x][distance][thin]") { using namespace DGtal::functions; auto &vc = complex_fixture; auto &ks = vc.space(); - auto &obj = vc.object(); using Predicate = Z3i::DigitalSet; using L3Metric = ExactPredicateLpSeparableMetric; using DT = DistanceTransformation; bool verbose = true; - SECTION("Distance Map") { + SECTION("Fixture_X Distance Map") { trace.beginBlock("With a Distance Map"); L3Metric l3; - DT dt(obj.domain(), obj.pointSet(), l3); + DT dt(set_fixture.domain(), set_fixture, l3); // Create wrap around selectMaxValue to use the thinning. auto selectDistMax = [&dt](const FixtureComplex::Clique &clique) { return selectMaxValue(dt, clique); @@ -1143,8 +1075,7 @@ TEST_CASE_METHOD(Fixture_X, "X DistanceMap", "[x][distance][thin]") { SECTION("persistenceThinning"){ auto table = *functions::loadTable(isthmusicity::tableOneIsthmus); auto pointToMaskMap = - *functions::mapZeroPointNeighborhoodToConfigurationMask< - FixtureObject::Point>(); + *functions::mapZeroPointNeighborhoodToConfigurationMask(); auto oneIsthmusTable = [&table, &pointToMaskMap](const FixtureComplex &fc, const FixtureComplex::Cell &c) {