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/>.
21 * @author David Coeurjolly (\c david.coeurjolly@liris.cnrs.fr )
22 * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS,
23 UMR 5205), CNRS, France
28 * Implementation of inline methods defined in VoronoiMap.h
30 * This file is part of the DGtal library.
33 //////////////////////////////////////////////////////////////////////////////
35 #include "DGtal/kernel/NumberTraits.h"
37 ///////////////////////////////////////////////////////////////////////////////
38 // IMPLEMENTATION of inline methods.
39 ///////////////////////////////////////////////////////////////////////////////
40 // ----------------------- Standard services ------------------------------
42 template <typename S, typename P, typename TSep, typename TImage>
43 inline void DGtal::VoronoiMapComplete<S, P, TSep, TImage>::compute()
45 // We copy the image extent
46 myLowerBoundCopy = myDomainPtr->lowerBound();
47 myUpperBoundCopy = myDomainPtr->upperBound();
49 // Point outside the domain
50 for ( auto & coord : myInfinity )
51 coord = DGtal::NumberTraits<typename Point::Coordinate>::max();
54 for ( auto const & pt : *myDomainPtr )
55 if ( ( *myPointPredicatePtr )( pt ) )
57 Value myVectorInfinity;
58 myVectorInfinity.insert( myInfinity );
59 myImagePtr->setValue( pt, myVectorInfinity );
64 external_point.insert( pt );
65 myImagePtr->setValue( pt, external_point );
68 // We process the remaining dimensions
69 for ( Dimension dim = 0; dim < S::dimension; dim++ )
71 computeOtherSteps( dim );
75 template <typename S, typename P, typename TSep, typename TImage>
76 inline void DGtal::VoronoiMapComplete<S, P, TSep, TImage>::computeOtherSteps(
77 const Dimension dim ) const
80 std::string title = "VoronoiMapComplete dimension " + std::to_string( dim );
81 trace.beginBlock( title );
84 // We setup the subdomain iterator
85 // the iterator will scan dimension using the order:
86 // {n-1, n-2, ... 1} (we skip the '0' dimension).
87 std::vector<Dimension> subdomain;
88 subdomain.reserve( S::dimension - 1 );
89 for ( int k = 0; k < (int)S::dimension; k++ )
90 if ( static_cast<Dimension>( ( (int)S::dimension - 1 - k ) ) != dim )
91 subdomain.push_back( (int)S::dimension - 1 - k );
93 Domain localDomain( myLowerBoundCopy, myUpperBoundCopy );
97 std::vector<Point> subRangePoints;
98 // Starting point precomputation
99 for ( auto const & pt : localDomain.subRange( subdomain ) )
100 subRangePoints.push_back( pt );
102 // We run the 1D problems in //
103 #pragma omp parallel for schedule( dynamic )
104 for ( int i = 0; i < static_cast<int>(subRangePoints.size()); ++i ) //MSVC requires signed type for openmp
105 computeOtherStep1D( subRangePoints[ i ], dim );
108 // We solve the 1D problems sequentially
109 for ( auto const & pt : localDomain.subRange( subdomain ) )
110 computeOtherStep1D( pt, dim );
118 // //////////////////////////////////////////////////////////////////////:
119 // ////////////////////////// Other Phases
120 template <typename S, typename P, typename TSep, typename TImage>
121 void DGtal::VoronoiMapComplete<S, P, TSep, TImage>::computeOtherStep1D(
122 const Point & startingPoint, const Dimension dim ) const
124 ASSERT( dim < S::dimension );
126 // Default starting and ending point for a cycle
127 Point startPoint = startingPoint;
128 Point endPoint = startingPoint;
129 startPoint[ dim ] = myLowerBoundCopy[ dim ];
130 endPoint[ dim ] = myUpperBoundCopy[ dim ];
132 Value myVectorInfinity;
133 myVectorInfinity.emplace( myInfinity );
135 // Extent along current dimension.
136 const auto extent = myUpperBoundCopy[ dim ] - myLowerBoundCopy[ dim ] + 1;
139 std::vector<Point> Sites;
141 // Reserve sites storage.
142 // +1 along periodic dimension in order to store two times the site that is on
144 Sites.reserve( extent + ( isPeriodic( dim ) ? 1 : 0 ) );
146 // Pruning the list of sites and defining cycle bounds.
147 // In the periodic case, the cycle bounds depend on the so-called break index
148 // that defines the start point.
151 // For dim = 0, no sites are hidden.
152 for ( auto point = startPoint; point[ dim ] <= myUpperBoundCopy[ dim ];
155 const Value psite = myImagePtr->operator()( point );
156 if ( psite != myVectorInfinity )
158 for ( Point voronoiPoint : psite )
160 Sites.push_back( voronoiPoint );
165 // If no sites are found, then there is nothing to do.
166 if ( Sites.size() == 0 )
169 // In the periodic case and along the first dimension, the break index
170 // is at the first site found.
171 if ( isPeriodic( dim ) )
173 startPoint[ dim ] = Sites[ 0 ][ dim ];
174 endPoint[ dim ] = startPoint[ dim ] + extent - 1;
176 // The first site is also the last site (with appropriate shift).
177 Sites.push_back( Sites[ 0 ] + Point::base( dim, extent ) );
182 // In the periodic case, the cycle depends on break index
183 if ( isPeriodic( dim ) )
185 // Along other than the first dimension, the break index is at the lowest
188 DGtal::NumberTraits<typename SeparableMetric::RawValue>::max();
190 for ( auto point = startPoint; point[ dim ] <= myUpperBoundCopy[ dim ];
193 const Value psite = myImagePtr->operator()( point );
195 if ( psite != myVectorInfinity )
197 const auto rawDist = myMetricPtr->rawDistance(
198 point, *( psite.begin() ) ); // All distances to Voronoi sites are
199 // equal, we take the first one
200 if ( rawDist < minRawDist )
202 minRawDist = rawDist;
203 startPoint[ dim ] = point[ dim ];
208 // If no sites are found, then there is nothing to do.
210 DGtal::NumberTraits<typename SeparableMetric::RawValue>::max() )
213 endPoint[ dim ] = startPoint[ dim ] + extent - 1;
216 // Pruning the list of sites for both periodic and non-periodic cases.
217 for ( auto point = startPoint; point[ dim ] <= myUpperBoundCopy[ dim ];
220 const Value psite = myImagePtr->operator()( point );
222 if ( psite != myVectorInfinity )
224 for ( Point site : psite )
226 while ( ( Sites.size() >= 2 ) &&
227 ( myMetricPtr->hiddenBy( Sites[ Sites.size() - 2 ],
228 Sites[ Sites.size() - 1 ], site,
229 startingPoint, endPoint, dim ) ) )
235 Sites.push_back( site );
240 // Pruning the remaining list of sites in the periodic case.
241 if ( isPeriodic( dim ) )
243 auto point = startPoint;
244 point[ dim ] = myLowerBoundCopy[ dim ];
245 for ( ; point[ dim ] <= endPoint[ dim ] - extent + 1;
246 ++point[ dim ] ) // +1 in order to add the break-index site at the
249 const Value psite = myImagePtr->operator()( point );
251 if ( psite != myVectorInfinity )
253 for ( Point site : psite )
255 // Site coordinates must be between startPoint and endPoint.
256 site[ dim ] += extent;
258 while ( ( Sites.size() >= 2 ) &&
259 ( myMetricPtr->hiddenBy( Sites[ Sites.size() - 2 ],
260 Sites[ Sites.size() - 1 ], site,
261 startingPoint, endPoint, dim ) ) )
264 Sites.push_back( site );
272 if ( Sites.size() == 0 )
275 // Rewriting for both periodic and non-periodic cases.
277 auto point = startPoint;
278 IntegerLong minimal_distance;
280 for ( ; point[ dim ] <= myUpperBoundCopy[ dim ]; ++point[ dim ] )
282 Value voronoiSites = myImagePtr->operator()( point );
284 myMetricPtr->rawDistance( *( voronoiSites.begin() ), point );
286 for ( Point site : Sites )
288 if ( myMetricPtr->rawDistance( site, point ) < minimal_distance )
290 voronoiSites.clear();
291 voronoiSites.emplace( site );
292 minimal_distance = myMetricPtr->rawDistance( site, point );
294 else if ( ( myMetricPtr->rawDistance( site, point ) ==
295 minimal_distance ) &&
296 ( std::find( voronoiSites.begin(), voronoiSites.end(), site ) ==
297 voronoiSites.end() ) )
299 voronoiSites.emplace( site );
302 myImagePtr->setValue( point, voronoiSites );
305 // Continuing rewriting in the periodic case.
306 if ( isPeriodic( dim ) )
308 for ( ; point[ dim ] <= endPoint[ dim ]; ++point[ dim ] )
313 while ( siteId < Sites.size() - 1 )
314 { // Idem ici en prenant en compte la périodicité
315 if ( myMetricPtr->closest( point, Sites[ siteId ],
316 Sites[ siteId + 1 ] ) ==
317 DGtal::ClosestFIRST )
319 voronoiSites.insert( Sites[ siteId ] - Point::base( dim, extent ) );
323 myImagePtr->setValue( point - Point::base( dim, extent ), voronoiSites );
331 template <typename S, typename P, typename TSep, typename TImage>
332 inline DGtal::VoronoiMapComplete<S, P, TSep, TImage>::VoronoiMapComplete(ConstAlias<Domain> aDomain,
333 ConstAlias<PointPredicate> aPredicate,
334 ConstAlias<SeparableMetric> aMetric )
335 : myDomainPtr( &aDomain )
336 , myPointPredicatePtr( &aPredicate )
337 , myDomainExtent( aDomain->upperBound() - aDomain->lowerBound() +
338 Point::diagonal( 1 ) )
339 , myMetricPtr( &aMetric )
341 myPeriodicitySpec.fill( false );
342 myImagePtr = CountedPtr<OutputImage>( new OutputImage( aDomain ) );
346 template <typename S, typename P, typename TSep, typename TImage>
347 inline DGtal::VoronoiMapComplete<S, P, TSep, TImage>::VoronoiMapComplete(ConstAlias<Domain> aDomain,
348 ConstAlias<PointPredicate> aPredicate,
349 ConstAlias<SeparableMetric> aMetric,
350 PeriodicitySpec const & aPeriodicitySpec )
351 : myDomainPtr( &aDomain )
352 , myPointPredicatePtr( &aPredicate )
353 , myDomainExtent( aDomain->upperBound() - aDomain->lowerBound() +
354 Point::diagonal( 1 ) )
355 , myMetricPtr( &aMetric )
356 , myPeriodicitySpec( aPeriodicitySpec )
358 // Finding periodic dimension index.
359 for ( Dimension i = 0; i < Space::dimension; ++i )
360 if ( isPeriodic( i ) )
361 myPeriodicityIndex.push_back( i );
363 myImagePtr = CountedPtr<OutputImage>( new OutputImage( aDomain ) );
367 template <typename S, typename P, typename TSep, typename TImage>
368 inline typename DGtal::VoronoiMapComplete<S, P, TSep, TImage>::Point
369 DGtal::VoronoiMapComplete<S, P, TSep, TImage>::projectPoint(
372 for ( auto const & dim : myPeriodicityIndex )
373 aPoint[ dim ] = projectCoordinate( aPoint[ dim ], dim );
378 template <typename S, typename P, typename TSep, typename TImage>
379 inline typename DGtal::VoronoiMapComplete<S, P, TSep, TImage>::Point::Coordinate
380 DGtal::VoronoiMapComplete<S, P, TSep, TImage>::projectCoordinate(typename Point::Coordinate aCoordinate,
381 const Dimension aDim ) const
383 ASSERT( aCoordinate - myDomainPtr->lowerBound()[ aDim ] +
384 myDomainExtent[ aDim ] >=
386 return ( aCoordinate - myDomainPtr->lowerBound()[ aDim ] +
387 myDomainExtent[ aDim ] ) %
388 myDomainExtent[ aDim ] +
389 myDomainPtr->lowerBound()[ aDim ];
392 template <typename S, typename P, typename TSep, typename TImage>
393 inline void DGtal::VoronoiMapComplete<S, P, TSep, TImage>::selfDisplay(
394 std::ostream & out ) const
396 out << "[VoronoiMapComplete] separable metric=" << *myMetricPtr;
400 // ///////////////////////////////////////////////////////////////////////////////
402 template <typename S, typename P, typename TSep, typename TImage>
403 inline std::ostream &
404 DGtal::operator<<( std::ostream & out,
405 const VoronoiMapComplete<S, P, TSep, TImage> & object )
407 object.selfDisplay( out );