DGtal 1.4.0
Loading...
Searching...
No Matches
testVoronoiMap.cpp
Go to the documentation of this file.
1
30#include <iostream>
31#include <array>
32#include <algorithm>
33
34#include "DGtal/base/Common.h"
35#include "DGtal/helpers/StdDefs.h"
36#include "DGtal/images/CConstImage.h"
37#include "DGtal/geometry/volumes/distance/VoronoiMap.h"
38#include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h"
39#include "DGtal/geometry/volumes/distance/InexactPredicateLpSeparableMetric.h"
40#include "DGtal/geometry/volumes/distance/DistanceTransformation.h"
41#include "DGtal/kernel/BasicPointPredicates.h"
42#include "DGtal/io/boards/Board2D.h"
43#include "DGtal/io/colormaps/HueShadeColorMap.h"
45
46using namespace std;
47using namespace DGtal;
49// Functions for testing class VoronoiMap.
51
52
53template<typename Point>
54double mynorm(const Point &point, const double p)
55{
56 double res=0.0;
57 for(unsigned int i=0; i< Point::dimension; i++)
58 res += std::pow ( (double)abs(point[i]) , p);
59
60 return std::pow(res, 1.0/p);
61}
62
63template <typename VoroMap>
64void saveVoroMap(const std::string &filename,const VoroMap &output,const double p)
65{
67
68 const double maxdt = mynorm( output.domain().upperBound() - output.domain().lowerBound(), p );
69
70 Board2D board;
71 Hue hue(0, maxdt);
72
73 for(typename VoroMap::Domain::ConstIterator it = output.domain().begin(),
74 itend = output.domain().end();
75 it != itend; ++it)
76 {
77 typename VoroMap::Value point = output(*it);
78 board << CustomStyle( (*it).className(), new CustomColors( hue(mynorm(point- (*it),p)),
79 hue(mynorm(point- (*it),p))))
80 << (*it);
81 }
82
83 board.saveSVG(filename.c_str());
84}
85
94template < typename Point, typename Domain >
96{
97 auto const & lowerBound = aDomain.lowerBound();
98 auto const & upperBound = aDomain.upperBound();
99
100 for ( typename Domain::Dimension i = 0; i < Domain::dimension; ++i )
101 aPoint[i] = ( aPoint[i] - 2*lowerBound[i] + upperBound[i] + 1 ) % ( upperBound[i] - lowerBound[i] + 1 ) + lowerBound[i];
102
103 return aPoint;
104}
105
116template < std::size_t N >
117std::array<bool, N> getPeriodicityFromInteger( std::size_t anInteger )
118{
119 std::array<bool, N> periodicity;
120 for ( std::size_t i = 0, mask = 1 ; i < N ; ++i, mask *= 2 )
121 periodicity[i] = anInteger & mask;
122
123 return periodicity;
124}
125
132template < std::size_t N >
133std::string formatPeriodicity( std::array<bool, N> const& aPeriodicity )
134{
135 std::string str;
136 for ( std::size_t i = 0; i < N; ++i )
137 str += aPeriodicity[i] ? '1' : '0';
138
139 return str;
140}
141
144template < typename Set, typename Voro>
145bool checkVoronoi(const Set &aSet, const Voro & voro)
146{
147 typedef typename Voro::Point Point;
148
149 // Domain extent
150 Point const extent = voro.domain().upperBound() - voro.domain().lowerBound() + Point::diagonal();
151
152 // Site shifting depending on the periodicity.
153 std::vector< typename Voro::PeriodicitySpec > periodicShift;
154 for ( std::size_t i = 0; i < ( 1u << Voro::Space::dimension ); ++i )
155 {
156 const auto periodicity = getPeriodicityFromInteger< Voro::Space::dimension >( i );
157
158 // Checking if this periodicity possibility is valid.
159 bool isValid = true;
160 for ( typename Voro::Space::Dimension j = 0; j < periodicity.size(); ++j )
161 if ( periodicity[j] && ! voro.isPeriodic(j) )
162 {
163 isValid = false;
164 break;
165 }
166
167 if ( isValid )
168 periodicShift.push_back( periodicity );
169 }
170
171 // Checking site for all domain points.
172 for ( auto const& pt : voro.domain() )
173 {
174 // Calculating reference (raw-)distance.
175 const Point psite = voro(pt);
176 const auto dist = voro.metric()->rawDistance( pt, psite );
177
178 // Checking that the reference site is actually a given site.
179 // Also testing projectPoint method.
180 if ( std::find( aSet.begin(), aSet.end(), voro.projectPoint( psite ) ) == aSet.end() )
181 {
182 trace.error() << "The Voro point " << psite
183 << " projected to " << voro.projectPoint( psite )
184 << " is not a valid site." << std::endl;
185 return false;
186 }
187
188 // Checking if we can found a better site.
189 for ( auto site : aSet )
190 {
191 // Trying all shifting possibilities of the site depending on the domain periodicity.
192 for ( auto const & periodicity : periodicShift )
193 {
194 auto currSite = site;
195
196 // Shifting site.
197 for ( typename Voro::Space::Dimension dim = 0; dim < Voro::Space::dimension ; ++dim )
198 if ( periodicity[dim] )
199 currSite[dim] += ( pt[dim] < currSite[dim] ? -1 : 1 ) * extent[dim];
200
201 // Checking raw-distance.
202 const auto dbis = voro.metric()->rawDistance( pt, currSite );
203 if ( dbis < dist )
204 {
205 trace.error() << "DT Error at " << pt
206 << " Voro:" << psite << " (" << dist << ")"
207 << " from set:" << site << "(" << dbis << ")"
208 << " projected from " << currSite << "." << std::endl;
209 return false;
210 }
211 }
212 }
213 }
214
215 return true;
216}
217
218
220{
223
224 return true;
225}
226
231bool testVoronoiMap( std::array<bool, 2> const& periodicity = { {false, false} } )
232{
233 unsigned int nbok = 0;
234 unsigned int nb = 0;
235
236 trace.beginBlock ( "Testing VoronoiMap2D with periodicity " + formatPeriodicity(periodicity) );
237
238 Z2i::Point a(-10,-10);
239 Z2i::Point b(10,10);
240 Z2i::Domain domain(a,b);
241
242 Z2i::DigitalSet mySet(domain);
243
244 for(Z2i::Domain::ConstIterator it = domain.begin(), itend = domain.end();
245 it != itend;
246 ++it)
247 mySet.insertNew( *it );
248
249
250 Z2i::DigitalSet sites(domain);
251
252 sites.insertNew( Z2i::Point(3,-6));
253 sites.insertNew( Z2i::Point(9,0));
254 sites.insertNew( Z2i::Point(-2,0));
255
256 for(Z2i::DigitalSet::ConstIterator it = sites.begin(), itend = sites.end();
257 it != itend; ++it)
258 mySet.erase (*it);
259
260
261
264 L2Metric l2;
265 Voro2 voro(&domain, &mySet, &l2, periodicity);
266
267 for(int j=-10; j <= 10; j++)
268 {
269 for(int i=-10; i<=10; i++)
270 trace.info() << "("<<voro( Z2i::Point(i,j))[0]<<","<< voro( Z2i::Point(i,j))[1]<<") ";
271 trace.info()<<std::endl;
272 }
273
274 trace.info()<<"Exporting to SVG"<<std::endl;
275
276 Board2D board;
277 for(Voro2::OutputImage::Domain::ConstIterator it = voro.domain().begin(),
278 itend = voro.domain().end();
279 it != itend; ++it)
280 {
281 const auto p = calcPointModuloDomain( voro(*it), voro.domain() );
282 const unsigned char c = ( p[1]*13 + p[0] * 7) % 256;
283 board << CustomStyle( (*it).className(), new CustomColors(Color(c,c,c),Color(c,c,c)))
284 << (*it);
285 }
286
287 board.saveSVG( ( "Voromap." + formatPeriodicity(periodicity) + ".svg" ).c_str() );
288
289 trace.beginBlock("Validating the Voronoi Map");
290 nbok += checkVoronoi(sites,voro) ? 1 : 0;
291 nb++;
292 trace.endBlock();
293
294 trace.endBlock();
295
296 return nbok == nb;
297}
298
299
300
305template<typename Set>
306bool testVoronoiMapFromSites2D( const Set &aSet,
307 const std::string &name,
308 std::array<bool, 2> const& periodicity = { {false, false} } )
309{
310 unsigned int nbok = 0;
311 unsigned int nb = 0;
312
313 Set mySet(aSet.domain());
314
315 for(typename Set::Domain::ConstIterator it = aSet.domain().begin(), itend = aSet.domain().end();
316 it != itend;
317 ++it)
318 mySet.insertNew( *it );
319
320
321 for(typename Set::ConstIterator it = aSet.begin(), itend = aSet.end();
322 it != itend; ++it)
323 mySet.erase (*it);
324
325
326 trace.beginBlock(" Voro computation");
329 L2Metric l2;
330 Voro2 voro(aSet.domain(), mySet, l2, periodicity );
331
332 trace.endBlock();
333
334 trace.beginBlock(" Voronoi computation l_6");
336 L6Metric l6;
338 Voro6 voro6( aSet.domain(), mySet, l6, periodicity );
339 trace.endBlock();
340
341
342
343 trace.beginBlock(" DT computation");
345 DT dt( aSet.domain(), mySet, l2, periodicity );
346 trace.endBlock();
347
348
349 if ( (aSet.domain().upperBound()[1] - aSet.domain().lowerBound()[1]) <20)
350 {
351 for(int j= aSet.domain().lowerBound()[1]; j <= aSet.domain().upperBound()[1]; j++)
352 {
353 for(int i=aSet.domain().lowerBound()[0]; i<=aSet.domain().upperBound()[0]; i++)
354 if ( aSet.find( Z2i::Point(i,j) ) != aSet.end() )
355 std::cout <<"X ";
356 else
357 std::cout<<"0 ";
358 trace.info()<<std::endl;
359 }
360
361 trace.info() << std::endl;
362
363 for(int j= aSet.domain().lowerBound()[1]; j <= aSet.domain().upperBound()[1]; j++)
364 {
365 for(int i=aSet.domain().lowerBound()[0]; i<=aSet.domain().upperBound()[0]; i++)
366 trace.info() << "("<<voro( Z2i::Point(i,j))[0]<<","<< voro( Z2i::Point(i,j))[1]<<") ";
367 trace.info()<<std::endl;
368 }
369 }
370
371 Board2D board;
372 board << voro.domain();
373 for(typename Voro2::OutputImage::Domain::ConstIterator it = voro.domain().begin(), itend = voro.domain().end();
374 it != itend; ++it)
375 {
376 if (!mySet(*it))
377 board << (*it);
378 }
379 std::string filename = "Voromap-" + name + "-orig." + formatPeriodicity(periodicity) + ".svg";
380 board.saveSVG(filename.c_str());
381
382 board.clear();
383 board << voro.domain();
384 board.setPenColor(Color(0,0,0));
385 for(typename Voro2::OutputImage::Domain::ConstIterator it = voro.domain().begin(), itend = voro.domain().end();
386 it != itend; ++it)
387 {
388 Z2i::Point p = voro(*it);
389 if ((p != (*it)) && (p != voro.domain().upperBound() + Z2i::Point::diagonal(1))
390 && (p != voro.domain().lowerBound()))
391 Display2DFactory::draw( board, p - (*it), (*it));
392 }
393
394 filename = "Voromap-" + name + "-diag." + formatPeriodicity(periodicity) + ".svg";
395 board.saveSVG(filename.c_str());
396
397
398 board.clear();
399 board << voro.domain();
400 for(typename Voro2::OutputImage::Domain::ConstIterator it = voro.domain().begin(), itend = voro.domain().end();
401 it != itend; ++it)
402 {
403 const auto p = calcPointModuloDomain( voro(*it), voro.domain() );
404 unsigned char c = (p[1]*13 + p[0] * 7) % 256;
405 board << CustomStyle( (*it).className(), new CustomColors(Color(c,c,c),Color(c,c,c)))
406 << (*it);
407 }
408
409 filename = "Voromap-" + name + "." + formatPeriodicity(periodicity) + ".svg";
410 board.saveSVG(filename.c_str());
411
412 filename = "Voromap-" + name + "-hue." + formatPeriodicity(periodicity) + ".svg";
413 saveVoroMap(filename.c_str(),voro,2);
414
415
416 board.clear();
417 for(typename Voro6::OutputImage::Domain::ConstIterator it = voro6.domain().begin(),
418 itend = voro6.domain().end();
419 it != itend; ++it)
420 {
421 Z2i::Point p = voro6(*it);
422 if (p != (*it))
423 Display2DFactory::draw( board, p - (*it), (*it));
424 }
425
426 filename = "Voromap-diag-l6-" + name + "." + formatPeriodicity(periodicity) + ".svg";
427 board.saveSVG(filename.c_str());
428
429 board.clear();
430 for(typename Voro6::OutputImage::Domain::ConstIterator it = voro6.domain().begin(), itend = voro6.domain().end();
431 it != itend; ++it)
432 {
433 const auto p = calcPointModuloDomain( voro6(*it), voro6.domain() );
434 unsigned char c = (p[1]*13 + p[0] * 7) % 256;
435 board << CustomStyle( (*it).className(), new CustomColors(Color(c,c,c),Color(c,c,c)))
436 << (*it);;
437 }
438
439 filename = "Voromap-l6" + name + "." + formatPeriodicity(periodicity) + ".svg";
440 board.saveSVG(filename.c_str());
441
442 filename = "Voromap-hue-l6-" + name + "." + formatPeriodicity(periodicity) + ".svg";
443 saveVoroMap(filename.c_str(),voro6,3);
444
445
446 trace.beginBlock("Validating the Voronoi Map");
447 nbok += checkVoronoi(aSet, voro) ? 1 : 0;
448 nb++;
449 trace.endBlock();
450
451 trace.beginBlock("Validating the Voronoi Map l_6");
452 nbok += checkVoronoi(aSet, voro6) ? 1 : 0;
453 nb++;
454 trace.endBlock();
455
456 return nbok == nb;
457}
458
463template<typename Set>
464bool testVoronoiMapFromSites( const Set &aSet )
465{
466 std::array<bool, Set::dimension> periodicity;
467 periodicity.fill( false );
468 return testVoronoiMapFromSites( aSet, periodicity );
469}
470
471template<typename Set>
472bool testVoronoiMapFromSites( const Set &aSet, std::array<bool, Set::Space::dimension> const & periodicity )
473{
474 unsigned int nbok = 0;
475 unsigned int nb = 0;
476
477 Set mySet(aSet.domain());
478
479 for(typename Set::Domain::ConstIterator it = aSet.domain().begin(),
480 itend = aSet.domain().end();
481 it != itend;
482 ++it)
483 mySet.insertNew( *it );
484
485
486 for(typename Set::ConstIterator it = aSet.begin(), itend = aSet.end();
487 it != itend; ++it)
488 mySet.erase (*it);
489
490
491
492 trace.beginBlock(" Voronoi computation l_2");
495 L2Metric l2;
496 Voro2 voro(aSet.domain(), mySet, l2, periodicity);
497 trace.endBlock();
498
499 trace.beginBlock("Validating the Voronoi Map");
500 nbok += checkVoronoi(aSet, voro) ? 1 : 0;
501 nb++;
502 trace.endBlock();
503
504 trace.beginBlock(" Voronoi computation l_3");
507 L3Metric l3;
508 Voro3 voro3(aSet.domain(), mySet, l3, periodicity);
509 trace.endBlock();
510
511 trace.beginBlock("Validating the Voronoi Map l_3");
512 nbok += checkVoronoi(aSet, voro3) ? 1 : 0;
513 nb++;
514 trace.endBlock();
515
516 trace.beginBlock(" DT computation");
518 DT dt(aSet.domain(), mySet, l2, periodicity);
519 trace.endBlock();
520
521 return nbok == nb;
522}
523
524
526{
527
528 Z2i::Point a(-10,-10);
529 Z2i::Point b(10,10);
530 Z2i::Domain domain(a,b);
531
532 Z2i::DigitalSet sites(domain);
533 bool ok = true;
534
535 sites.insertNew( Z2i::Point(3,-6));
536 sites.insertNew( Z2i::Point(9,0));
537 sites.insertNew( Z2i::Point(-3,0));
538
539 for ( std::size_t i = 0; i < 4; ++i )
540 {
541 auto const periodicity = getPeriodicityFromInteger<2>(i);
542 trace.beginBlock( "Simple2D with periodicity " + formatPeriodicity(periodicity) );
543 ok = ok && testVoronoiMapFromSites2D( sites, "simple", periodicity );
544 trace.endBlock();
545 }
546
547 return ok;
548
549}
550
552{
553 unsigned size=16;
554 Z2i::Point a(0,0);
555 Z2i::Point b(size,size);
556 Z2i::Domain domain(a,b);
557
558 Z2i::DigitalSet sites(domain);
559 bool ok = true;
560
561 for(unsigned int i = 0 ; i < size; ++i)
562 {
563 Z2i::Point p( rand() % (b[0]) - a[0], rand() % (b[1]) + a[1] );
564 sites.insert( p );
565 }
566
567 for ( std::size_t i = 0; i < 4; ++i )
568 {
569 auto const periodicity = getPeriodicityFromInteger<2>(i);
570 trace.beginBlock( "Random 2D with periodicity " + formatPeriodicity(periodicity) );
571 ok = ok && testVoronoiMapFromSites2D( sites, "random", periodicity );
572 trace.endBlock();
573 }
574
575 for(unsigned int i = 0 ; i < size*size-size; ++i)
576 {
577 Z2i::Point p( rand() % (b[0]) - a[0], rand() % (b[1]) + a[1] );
578 sites.insert( p );
579 }
580
581 for ( std::size_t i = 0; i < 4; ++i )
582 {
583 auto const periodicity = getPeriodicityFromInteger<2>(i);
584 trace.beginBlock( "Random 2D (dense) with periodicity " + formatPeriodicity(periodicity) );
585 ok = ok && testVoronoiMapFromSites2D( sites, "random-dense", periodicity );
586 trace.endBlock();
587 }
588
589 return ok;
590}
591
592
594{
595
596 Z3i::Point a(-10,-10,-10);
597 Z3i::Point b(10,10,10);
598 Z3i::Domain domain(a,b);
599
600 Z3i::DigitalSet sites(domain);
601 bool ok = true;
602
603 sites.insertNew( Z3i::Point(0,0,-6));
604 sites.insertNew( Z3i::Point(6,0,0));
605 sites.insertNew( Z3i::Point(-6,0,3));
606
607 for ( auto i = 0; i < 8; ++i )
608 {
609 auto const periodicity = getPeriodicityFromInteger<3>(i);
610 trace.beginBlock( "Simple3D with periodicity " + formatPeriodicity(periodicity) );
611 ok = ok && testVoronoiMapFromSites( sites, periodicity );
612 trace.endBlock();
613 }
614
615 return ok;
616}
617
619{
620 std::size_t const N = 16;
621
622 Z3i::Point a(0, 0, 0);
623 Z3i::Point b(N, N, N);
624 Z3i::Domain domain(a,b);
625
626 Z3i::DigitalSet sites(domain);
627 bool ok = true;
628
629 for(unsigned int i = 0 ; i < N; ++i)
630 {
631 Z3i::Point p( rand() % (b[0]) - a[0],
632 rand() % (b[1]) + a[1],
633 rand() % (b[2]) + a[2] );
634 sites.insert( p );
635 }
636
637 for ( std::size_t i = 0; i < 8; ++i )
638 {
639 auto const periodicity = getPeriodicityFromInteger<3>(i);
640 trace.beginBlock( "Random 3D with periodicity " + formatPeriodicity(periodicity) );
641 ok = ok && testVoronoiMapFromSites( sites, periodicity );
642 trace.endBlock();
643 }
644
645 return ok;
646}
647
648
649
651{
652
653 typedef SpaceND<4> Space4;
654 Space4::Point a(0,0,0,0);
655 Space4::Point b(5,5,5,5);
657
659 bool ok = true;
660
661 sites.insertNew( Space4::Point(1,4,1,1));
662 sites.insertNew( Space4::Point(3,1,3,1));
663 sites.insertNew( Space4::Point(0,0,0,0));
664
665 for ( std::size_t i = 0; i < 16; ++i )
666 {
667 auto const periodicity = getPeriodicityFromInteger<4>(i);
668 trace.beginBlock( "Simple4D with periodicity " + formatPeriodicity(periodicity) );
669 ok = ok && testVoronoiMapFromSites( sites, periodicity );
670 trace.endBlock();
671 }
672
673 return ok;
674}
675
676
678// Standard services - public :
679
680int main( int argc, char** argv )
681{
682 trace.beginBlock ( "Testing class VoronoiMap" );
683 trace.info() << "Args:";
684 for ( int i = 0; i < argc; ++i )
685 trace.info() << " " << argv[ i ];
686 trace.info() << endl;
687
688 bool res = testCheckConcept()
689 && testVoronoiMap()
690 && testVoronoiMap( { {true, false} } )
691 && testVoronoiMap( { {false, true} } )
692 && testVoronoiMap( { {true, true} } )
693 && testSimple2D()
695 && testSimple3D()
697 && testSimple4D()
698 ; // && ... other tests
699
700 trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
701 trace.endBlock();
702 return res ? 0 : 1;
703}
704// //
Aim: This class specializes a 'Board' class so as to display DGtal objects more naturally (with <<)....
Definition Board2D.h:71
Structure representing an RGB triple with alpha component.
Definition Color.h:68
Aim: A wrapper class around a STL associative container for storing sets of digital points within som...
Container::const_iterator ConstIterator
ConstIterator type of the container;.
Aim: A container class for storing sets of digital points within some given domain.
void insertNew(const Point &p)
Aim: Implementation of the linear in time distance transformation for separable metrics.
Aim: implements separable l_p metrics with exact predicates.
Aim: This class template may be used to (linearly) convert scalar values in a given range into a colo...
const ConstIterator & begin() const
const Point & lowerBound() const
const Point & upperBound() const
const ConstIterator & end() const
static Self diagonal(Component val=1)
void beginBlock(const std::string &keyword="")
std::ostream & emphase()
std::ostream & error()
std::ostream & info()
double endBlock()
Aim: Implementation of the linear in time Voronoi map construction.
Definition VoronoiMap.h:127
Board & setPenColor(const DGtal::Color &color)
Definition Board.cpp:297
void clear(const DGtal::Color &color=DGtal::Color::None)
Definition Board.cpp:151
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition Board.cpp:1011
ExactPredicateLpSeparableMetric< Space, 2 > L2Metric
Definition StdDefs.h:118
DGtal is the top-level namespace which contains all DGtal functions and types.
Trace trace
Definition Common.h:153
STL namespace.
Custom style class redefining the pen color and the fill color. You may use Board2D::Color::None for ...
Definition Board2D.h:279
static void draw(DGtal::Board2D &board, const DGtal::DiscreteExteriorCalculus< dimEmbedded, dimAmbient, TLinearAlgebraBackend, TInteger > &calculus)
Aim: Defines the concept describing a read-only image, which is a refinement of CPointFunctor.
Definition CConstImage.h:95
int main()
Definition testBits.cpp:56
MyPointD Point
Domain domain
const Point aPoint(3, 4)
double mynorm(const Point &point, const double p)
bool testSimple2D()
Point calcPointModuloDomain(Point aPoint, Domain const &aDomain)
bool testSimple3D()
bool testCheckConcept()
bool testVoronoiMap(std::array< bool, 2 > const &periodicity={ {false, false} })
bool testSimpleRandom3D()
std::string formatPeriodicity(std::array< bool, N > const &aPeriodicity)
std::array< bool, N > getPeriodicityFromInteger(std::size_t anInteger)
void saveVoroMap(const std::string &filename, const VoroMap &output, const double p)
bool testVoronoiMapFromSites(const Set &aSet)
bool testSimple4D()
bool testVoronoiMapFromSites2D(const Set &aSet, const std::string &name, std::array< bool, 2 > const &periodicity={ {false, false} })
bool testSimpleRandom2D()
bool checkVoronoi(const Set &aSet, const Voro &voro)