2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file CubicalComplexFunctions.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
24 * Implementation of inline methods defined in CubicalComplexFunctions.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32#include "DGtal/kernel/domains/HyperRectDomain.h"
33#include "DGtal/topology/DigitalTopology.h"
34#include "DGtal/topology/helpers/NeighborhoodConfigurationsHelper.h"
35//////////////////////////////////////////////////////////////////////////////
37///////////////////////////////////////////////////////////////////////////////
38// IMPLEMENTATION of inline methods.
39///////////////////////////////////////////////////////////////////////////////
41//-----------------------------------------------------------------------------
42template <typename TKSpace, typename TCellContainer,
43 typename CellConstIterator,
44 typename CellMapIteratorPriority >
47collapse( CubicalComplex< TKSpace, TCellContainer > & K,
48 CellConstIterator S_itB, CellConstIterator S_itE,
49 const CellMapIteratorPriority& priority,
50 bool hintIsSClosed, bool hintIsKClosed,
54 typedef CubicalComplex< TKSpace, TCellContainer > CC;
55 typedef typename CC::Cell Cell;
56 typedef typename CC::CellType CellType;
57 typedef typename CC::CellMapIterator CellMapIterator;
58 typedef vector< CellMapIterator > CMIVector;
59 typedef typename CMIVector::const_iterator CMIVectorConstIterator;
60 // NB : a maximal k-cell is collapsible if it has a free incident k-1-cell.
61 Dimension n = K.dim();
62 CMIVector S; // stores the cells to process
63 CMIVector Q_low; // stores the iterators on direct faces of the maximal cell.
64 CMIVector Q_collapsible;// stores collapsible cells in order to clean them at the end.
65 CellMapIterator it_cell; // generic iterator on a cell.
66 CellMapIterator it_cell_c; // points on c in the free pair (c,d)
67 CellMapIterator it_cell_d; // points on d in the free pair (c,d)
68 CMIVectorConstIterator itlow;
69 CMIVectorConstIterator itqup;
71 if ( verbose ) trace.info() << "[CC::collapse]-+ tag collapsible elements... " << flush;
72 // Restricts the set of elements that are collapsible.
74 for ( CellConstIterator S_it = S_itB; S_it != S_itE; ++S_it )
77 Dimension k = K.dim( c );
78 it_cell = K.findCell( k, c );
79 uint32_t& ccdata = it_cell->second.data;
80 ASSERT( it_cell != K.end( k ) );
81 S.push_back( it_cell );
82 if ( ! ( ccdata & (CC::FIXED | CC::COLLAPSIBLE ) ) )
84 ccdata |= CC::COLLAPSIBLE;
85 Q_collapsible.push_back( it_cell );
88 else // not ( hintIsSClosed )
89 for ( CellConstIterator S_it = S_itB; S_it != S_itE; ++S_it )
92 Dimension k = K.dim( c );
93 it_cell = K.findCell( k, c );
94 uint32_t& ccdata = it_cell->second.data;
95 ASSERT( it_cell != K.end( k ) );
96 S.push_back( it_cell );
97 if ( ! ( ccdata & (CC::FIXED | CC::COLLAPSIBLE ) ) )
99 ccdata |= CC::COLLAPSIBLE;
100 Q_collapsible.push_back( it_cell );
103 back_insert_iterator< vector<Cell> > back_it( cells );
104 K.faces( back_it, c, hintIsKClosed );
105 for ( typename vector<Cell>::const_iterator
106 it = cells.begin(), itE = cells.end(); it != itE; ++it )
108 it_cell = K.findCell( *it );
109 uint32_t& ccdata2 = it_cell->second.data;
110 if ( ! ( ccdata2 & (CC::FIXED | CC::COLLAPSIBLE ) ) )
112 ccdata2 |= CC::COLLAPSIBLE;
113 Q_collapsible.push_back( it_cell );
117 if ( verbose ) trace.info() << " " << Q_collapsible.size() << " found." << endl;
120 priority_queue<CellMapIterator, CMIVector, CellMapIteratorPriority> PQ( priority );
122 if ( verbose ) trace.info() << "[CC::collapse]-+ entering collapsing loop. " << endl;
123 uint64_t nb_pass = 0;
124 uint64_t nb_examined = 0;
125 uint64_t nb_removed = 0;
126 while ( ! S.empty() )
128 for ( CMIVectorConstIterator it = S.begin(), itE = S.end();
132 (*it)->second.data |= CC::USER1;
135 if ( verbose ) trace.info() << "[CC::collapse]---+ Pass " << ++nb_pass
136 << ", Card(PQ)=" << PQ.size() << " elements, "
137 << "nb_exam=" << nb_examined << endl;
139 // Try to collapse elements according to priority queue.
140 while ( ! PQ.empty() )
143 CellMapIterator itcur = PQ.top();
144 uint32_t& cur_data = itcur->second.data;
147 // Check if the cell is removable
148 if ( ( cur_data & CC::REMOVED ) || ( ! ( cur_data & CC::COLLAPSIBLE ) ) )
150 // Check if the cell was several time in the queue and is already processed.
151 if ( ! ( cur_data & CC::USER1 ) )
153 ASSERT( cur_data & CC::USER1 );
154 cur_data &= ~CC::USER1;
156 // Cell may be removable.
157 // Check if it is a maximal cell
158 CellMapIterator itup;
159 const Cell & cur_c = itcur->first;
160 CellType cur_c_type = K.computeCellType( cur_c, itup, n );
161 bool found_pair = false;
162 // trace.info() << " - Cell " << cur_c << " Dim=" << dim( cur_c ) << " Type=" << cur_c_type << std::endl;
163 if ( cur_c_type == CC::Maximal )
164 { // maximal cell... must find a free face
165 // check faces to find a free face.
166 back_insert_iterator< CMIVector > back_it( Q_low );
167 K.directFacesIterators( back_it, cur_c );
168 bool best_free_face_found = false;
169 CellMapIterator best_free_face_it;
170 for ( CMIVectorConstIterator it = Q_low.begin(), itE = Q_low.end();
173 CellMapIterator low_ic = *it;
174 uint32_t& data = low_ic->second.data;
175 // trace.info() << " + Cell " << low_ic->first << " data=" << data << std::endl;
176 if ( ( data & CC::REMOVED ) || ! ( data & CC::COLLAPSIBLE ) ) continue;
177 const Cell& cur_d = low_ic->first;
178 CellType cur_d_type = K.computeCellType( cur_d, itup, n );
179 // trace.info() << " + Type=" << cur_d_type << std::endl;
180 if ( cur_d_type == CC::Free )
181 { // found a free n-1-face ic
182 if ( ( ! best_free_face_found )
183 || ( ! priority( low_ic, best_free_face_it ) ) )
185 best_free_face_it = low_ic;
186 best_free_face_found = true;
190 if ( best_free_face_found )
195 it_cell_d = best_free_face_it;
196 // Q_low already contains cells that should be
200 else if ( cur_c_type == CC::Free )
201 { // free face... check that its 1-up-incident face is maximal.
202 CellMapIterator it_up_up;
203 const Cell& cur_d = itup->first;
204 CellType cur_d_type = K.computeCellType( cur_d, it_up_up, n );
205 if ( cur_d_type == CC::Maximal )
206 { // found a maximal face.
210 // Q_low will contain cells that should be checked
212 back_insert_iterator< CMIVector > back_it( Q_low );
213 K.directFacesIterators( back_it, it_cell_c->first );
217 { // If found, remove pair from complex (logical removal).
218 it_cell_c->second.data |= CC::REMOVED;
219 it_cell_d->second.data |= CC::REMOVED;
221 // Incident cells have to be checked again.
222 for ( CMIVectorConstIterator it = Q_low.begin(), itE = Q_low.end();
226 uint32_t& data_qlow = it_cell->second.data;
227 if ( ( ! ( data_qlow & CC::REMOVED ) )
228 && ( data_qlow & CC::COLLAPSIBLE )
229 && ( ! ( data_qlow & CC::USER1 ) ) )
231 S.push_back( it_cell );
236 } // while ( ! PQ.empty() )
237 } // while ( ! S.empty() )
239 if ( verbose ) trace.info() << "[CC::collapse]-+ cleaning complex." << std::endl;
241 // Now clean the complex so that removed cells are effectively
242 // removed and no more cell is tagged as collapsible.
243 for ( CMIVectorConstIterator it = Q_collapsible.begin(), itE = Q_collapsible.end();
246 CellMapIterator cmIt = *it;
247 uint32_t& cur_data = cmIt->second.data;
248 if ( cur_data & CC::REMOVED ) K.eraseCell( cmIt );
249 else cur_data &= ~CC::COLLAPSIBLE;
250 // if ( (*it)->second.data & CC::REMOVED )
251 // K.eraseCell( *it );
253 // (*it)->second.data &= ~CC::COLLAPSIBLE;
259//-----------------------------------------------------------------------------
260template <typename TKSpace, typename TCellContainer,
261 typename BdryCellOutputIterator,
262 typename InnerCellOutputIterator>
265filterCellsWithinBounds( const CubicalComplex< TKSpace, TCellContainer > & K,
266 const typename TKSpace::Point& kLow,
267 const typename TKSpace::Point& kUp,
268 BdryCellOutputIterator itBdry,
269 InnerCellOutputIterator itInner )
271 typedef CubicalComplex< TKSpace, TCellContainer > CC;
272 typedef typename CC::Cell Cell;
273 typedef typename CC::Point Point;
274 typedef typename CC::CellMapConstIterator CellMapConstIterator;
275 Dimension d = K.dim();
276 for ( Dimension i = 0; i <= d; ++i )
278 for ( CellMapConstIterator it = K.begin( i ), itE = K.end( i ); it != itE; ++it )
280 Cell cell = it->first;
281 Point kCell = K.space().uKCoords( cell );
282 if ( ( kLow.inf( kCell ) == kLow ) && ( kUp.sup( kCell ) == kUp ) )
283 { // Inside or on boundary.
285 for ( Dimension j = 0; j < Point::dimension; ++j )
287 if ( ( kCell[ j ] == kLow[ j ] ) || ( kCell[ j ] == kUp[ j ] ) )
293 if ( bdry ) *itBdry++ = cell;
294 else *itInner++ = cell;
300//-----------------------------------------------------------------------------
301template <typename TObject, typename TKSpace, typename TCellContainer>
302std::unique_ptr<TObject>
305 const CubicalComplex< TKSpace, TCellContainer > & C)
308 const auto & cs = C.space();
309 // Get domain of C KSpace.
310 typename TObject::Domain domain(cs.lowerBound(), cs.upperBound());
311 typename TObject::DigitalSet dset(domain);
312 for(auto it = C.begin(TKSpace::DIM);
313 it!= C.end(TKSpace::DIM) ; ++it)
314 dset.insertNew(cs.uCoords(it->first));
316 typename TObject::ForegroundAdjacency fAdj;
317 typename TObject::BackgroundAdjacency bAdj;
318 typename TObject::DigitalTopology topo(fAdj,bAdj, JORDAN_DT);
319 std::unique_ptr<TObject> obj( new TObject(topo, dset) );
323template<typename TComplex>
324DGtal::NeighborhoodConfiguration
326getSpelNeighborhoodConfigurationOccupancy
327( const TComplex & input_complex,
328 const typename TComplex::Point & center,
329 const std::unordered_map<
330 typename TComplex::Point, NeighborhoodConfiguration> & mapPointToMask )
332 using Point = typename TComplex::Point;
333 using Space = typename TComplex::Space;
334 using Domain = HyperRectDomain< Space >;
336 Point p1 = Point::diagonal( -1 );
337 Point p2 = Point::diagonal( 1 );
338 Point c = Point::diagonal( 0 );
339 Domain domain( p1, p2 );
341 using KPreSpace = typename TComplex::KSpace::PreCellularGridSpace;
342 const auto & kspace = input_complex.space();
343 const auto & not_found( input_complex.end(3) );
344 NeighborhoodConfiguration cfg{0};
345 for ( auto it = domain.begin(); it != domain.end(); ++it ) {
346 if( *it == c) continue;
347 const auto pre_cell = KPreSpace::uSpel(center + *it);
348 if (input_complex.belongs(pre_cell) &&
349 input_complex.findCell(3, kspace.uCell(pre_cell)) != not_found )
350 cfg |= mapPointToMask.at(*it) ;
355///////////////////////////////////////////////////////////////////////////////