DGtalTools  0.9.4
patternTriangulation.cpp
1 
39 #include <iostream>
40 #include <iterator>
41 #include <cstdio>
42 #include <cmath>
43 #include <fstream>
44 #include <vector>
45 
46 #include <boost/program_options/options_description.hpp>
47 #include <boost/program_options/parsers.hpp>
48 #include <boost/program_options/variables_map.hpp>
49 
50 #include "DGtal/base/Common.h"
51 #include "DGtal/helpers/StdDefs.h"
52 
53 #include "DGtal/arithmetic/LighterSternBrocot.h"
54 #include "DGtal/arithmetic/Pattern.h"
55 
56 #include "DGtal/io/boards/Board2D.h"
57 #include "DGtal/io/Color.h"
58 
59 using namespace DGtal;
60 using namespace std;
61 
62 namespace po = boost::program_options;
64 
109 template <typename Point>
110 struct OddConvexHullMap {
111 
112 public:
113  typedef Point Vector;
114 
115 public:
122  OddConvexHullMap(const Vector& aShift = Vector(1,-1))
123  : myS(aShift) {}
124 
131  Point operator()(const Point& aP) const
132  {
133  return aP + myS;
134  }
135 
136 private:
137  Vector myS;
138 
139 };
140 
148 template <typename Point>
149 struct EvenConvexHullMap {
150 
151 public:
152  typedef Point Vector;
153 
154 public:
162  EvenConvexHullMap(const Point& aPoint, const Vector& aShift = Vector(1,-1))
163  : myZn(aPoint), myS(aShift) {}
164 
171  Point operator()(const Point& aP) const
172  {
173  return myZn - aP + myS;
174  }
175 
176 private:
177  Point myZn;
178  Vector myS;
179 
180 };
181 
183 
194 template <typename Board, typename Point>
195 void drawSegment(Board& aBoard, const Point& aP, const Point& aQ)
196 {
197  aBoard.drawLine(aP[0], aP[1], aQ[0], aQ[1]);
198  aBoard << aP << aQ;
199 }
200 
215 template <typename Board, typename Iterator, typename Functor>
216 void drawSegments(Board& aBoard,
217  const Iterator& itb, const Iterator& ite,
218  const Functor& aF)
219 {
220  Iterator it = itb;
221  if (it != ite)
222  {
223  Iterator prevIt = it;
224  ++it;
225  for ( ; it != ite; ++prevIt, ++it)
226  {
227  drawSegment( aBoard, aF(*prevIt), aF(*it) );
228  }
229  }
230 }
231 
232 
234 
249 template<typename Fraction, typename Container>
250 void fillConvergents(const Fraction& aZn,
251  Container& odd, Container& even)
252 {
253  typedef typename Container::value_type Vector;
254 
255  for (typename Fraction::Quotient i = 1; i <= aZn.k(); ++i)
256  {
257  Fraction zk = aZn.reduced(i);
258  if (((aZn.k() - i)%2) == 1 )
259  { //odd
260  odd.push_back(Vector(zk.q(),zk.p()));
261  }
262  else
263  { //even
264  even.push_back(Vector(zk.q(),zk.p()));
265  }
266  }
267 }
268 
283 template <typename Pattern, typename Integer>
284 void displayConvexHull(const Pattern& aP, const Integer& aD, bool withFDT = false)
285 {
286  typedef typename Pattern::Fraction Fraction;
287  typedef typename Pattern::Vector2I Vector;
288  typedef std::vector<Vector> Convergents;
289  typedef typename Pattern::Point2I Point;
290 
291  Board2D aBoard;
292 
293  //list of convergents
294  Convergents oddConvergents, evenConvergents;
295 
296  //fill the lists
297  Fraction zn = aP.slope();
298  // aD > 1
299  if (aD > 1)
300  {
301  Fraction znm1 = zn.father();
302  if (zn.odd())
303  oddConvergents.push_back(Vector(znm1.q(),znm1.p()));
304  else
305  evenConvergents.push_back(Vector(znm1.q(),znm1.p()));
306  }
307  // aD >= 1
308  fillConvergents( zn, oddConvergents, evenConvergents );
309 
310  //display the domain
311  Point Zn = Point(aD*zn.q(),aD*zn.p());
312  aBoard << Z2i::Domain( Point(0,0), Zn );
313  aBoard << SetMode( Zn.className(), "Grid" );
316 
317  //display the two main lists
318  OddConvexHullMap<Point> oddH;
319  drawSegments( aBoard, oddConvergents.begin(), oddConvergents.end(), oddH );
320 
321  EvenConvexHullMap<Point> evenH(Zn);
322  drawSegments( aBoard, evenConvergents.begin(), evenConvergents.end(), evenH );
323 
324  //display the four last segments
325  drawSegment( aBoard, Point(0,0), Zn );
326  if (evenConvergents.size() != 0)
327  {
328  drawSegment( aBoard, evenH(*evenConvergents.rbegin()), Zn );
329  if (oddConvergents.size() != 0)
330  {
331  drawSegment( aBoard, Point(0,0), oddH(*oddConvergents.rbegin()) );
332  drawSegment( aBoard,
333  oddH(*oddConvergents.begin()),
334  evenH(*evenConvergents.begin()) );
335  }
336  else
337  {
338  drawSegment( aBoard, Point(0,0), evenH(*evenConvergents.rbegin()) );
339  }
340  }
341 
342  if (withFDT)
343  {//display internal edges
344 
345  //first internal edge
346  if (evenConvergents.size() != 0)
347  drawSegment( aBoard,
348  Point(0,0),
349  evenH(*evenConvergents.rbegin()) );
350  //other internal edges
351  typedef typename Convergents::const_reverse_iterator RI;
352  RI oddRit = oddConvergents.rbegin();
353  RI evenRit = evenConvergents.rbegin();
354  bool hasToContinue = true;
355  while (hasToContinue)
356  {
357  if (oddRit != oddConvergents.rend())
358  {
359  drawSegment( aBoard,
360  oddH(*oddRit),
361  evenH(*evenRit) );
362  }
363  else
364  hasToContinue = false;
365  ++evenRit;
366 
367  if ( (hasToContinue) && (evenRit != evenConvergents.rend()) )
368  {
369  drawSegment( aBoard,
370  oddH(*oddRit),
371  evenH(*evenRit) );
372  }
373  else
374  hasToContinue = false;
375  ++oddRit;
376  }
377 
378  aBoard.saveEPS("FDT.eps");
379  }
380  else
381  {
382  aBoard.saveEPS("CH.eps");
383  }
384 }
385 
387 
398 template <typename Board, typename Point>
399 void drawTriangle(Board& aBoard,
400  const Point& aP, const Point& aQ, const Point& aR)
401 {
402  aBoard.drawTriangle( aP[0], aP[1], aQ[0], aQ[1], aR[0], aR[1] );
403 }
404 
414 struct InDirectBezoutComputer
415 {
423  template<typename Pattern>
424  typename Pattern::Vector2I
425  getPositiveBezout(const Pattern& aP) const
426  {
427  return aP.bezout();
428  }
429 
437  template<typename Pattern>
438  typename Pattern::Vector2I
439  getNegativeBezout(const Pattern& aP) const
440  {
441  return aP.slope().even()
442  ? aP.U( 1 ) - aP.previousPattern().U( 1 )
443  : aP.previousPattern().U( 1 );
444  }
445 
446 };
447 
457 struct DirectBezoutComputer
458 {
466  template<typename Pattern>
467  typename Pattern::Vector2I
468  getPositiveBezout(const Pattern& aP) const
469  {
470  return aP.slope().even()
471  ? aP.U( 1 ) - aP.previousPattern().U( 1 )
472  : aP.previousPattern().U( 1 );
473  }
474 
482  template<typename Pattern>
483  typename Pattern::Vector2I
484  getNegativeBezout(const Pattern& aP) const
485  {
486  return aP.bezout();
487  }
488 
489 };
490 
509 template <typename Board, typename Pattern, typename BezoutComputer>
510 void displayPartialCDT(Board& aBoard,
511  const Pattern& aP,
512  const typename Pattern::Point2I& aStartingPoint,
513  const BezoutComputer& aBC )
514 {
515  typedef typename Pattern::Fraction Fraction;
516  typedef typename Pattern::Vector2I Vector;
517  typedef typename Pattern::Point2I Point;
518 
519  Fraction f = aP.slope();
520  if ( (f.p() >= 1)&&(f.q() >= 1) )
521  {
522  Point O = aStartingPoint;
523  Point Zn = aStartingPoint + aP.v();
524  Vector v1 = aBC.getNegativeBezout(aP);
525  Point B = aStartingPoint + v1;
526  drawTriangle(aBoard, O, Zn, B);
527 
528  if ( (f.p() > 1)||(f.q() > 1) )
529  {
530  //recursive calls
531  // - first pattern
532  displayPartialCDT(aBoard, Pattern(Fraction(v1[1],v1[0])), O, aBC);
533  // - second pattern
534  Vector v2 = aBC.getPositiveBezout(aP);
535  displayPartialCDT(aBoard, Pattern(Fraction(v2[1],v2[0])), B, aBC);
536  }
537  }
538 }
539 
551 template <typename Pattern, typename Integer>
552 void displayCDT(const Pattern& aP, const Integer& aD)
553 {
554  Board2D aBoard;
555 
556  typedef typename Pattern::Point2I Point;
557  typedef typename Pattern::Fraction Fraction;
558  Fraction zn = aP.slope();
559 
560  //display the domain
561  Point Zn = Point(aD*zn.q(),aD*zn.p());
562  aBoard << Z2i::Domain( Point(0,0), Zn );
563  aBoard << SetMode( Zn.className(), "Grid" );
566 
567  //display the upper part of the triangulation
568  for (Integer i = 0; i < aD; ++i)
569  {
570  displayPartialCDT( aBoard, aP, Point(i*zn.q(), i*zn.p()), InDirectBezoutComputer() );
571  }
572 
573  //display the lower parts of the triangulation
574  // - getting the reversed patterns
575  typedef typename Pattern::Vector2I Vector;
576  typedef std::vector<Vector> Convergents;
577  typedef typename std::vector<Vector>::const_reverse_iterator ReverseIterator;
578  Convergents oddConvergents, evenConvergents;
579  fillConvergents( zn, oddConvergents, evenConvergents );
580  // - displaying the reversed patterns...
581  Point rPStartingPoint;
582  // - of odd slope:
583  OddConvexHullMap<Point> oddH;
584  {
585  ReverseIterator itb = evenConvergents.rbegin();
586  ReverseIterator ite = evenConvergents.rend();
587  Point aStartingPoint = oddH( *oddConvergents.rbegin() );
588  //
589  Point p = aStartingPoint;
590  ReverseIterator it = itb;
591  if (it != ite)
592  {
593  for (++it; it != ite; ++it)
594  {
595  displayPartialCDT( aBoard, Pattern( (*it)[1], (*it)[0] ), p, DirectBezoutComputer() );
596  p += *it;
597  }
598  }
599  rPStartingPoint = p;
600  }
601  // - of even slope:
602  EvenConvexHullMap<Point> evenH(Zn);
603  {
604  ReverseIterator itb = oddConvergents.rbegin();
605  ReverseIterator ite = oddConvergents.rend();
606  Point aStartingPoint = evenH( *evenConvergents.rbegin() );
607  //
608  Point p = aStartingPoint;
609  ReverseIterator it = itb;
610  for ( ; it != ite; ++it)
611  {
612  p -= *it;
613  displayPartialCDT( aBoard, Pattern( (*it)[1], (*it)[0] ), p, DirectBezoutComputer() );
614  }
615  }
616  // - of same slope:
617  {
618  for (Integer i = 0; i < (aD-1); ++i)
619  {
620  Point p = rPStartingPoint + i*aP.v();
621  displayPartialCDT( aBoard, aP, p, DirectBezoutComputer() );
622  }
623  }
624 
625 
626  aBoard.saveEPS("CDT.eps");
627 }
628 
629 
631 
636 void missingParam(std::string param)
637 {
638  trace.error() << " Parameter: " << param << " is required...";
639  trace.info() << std::endl;
640  exit(1);
641 }
642 
643 
645 
653 int main(int argc, char **argv)
654 {
655  // parse command line ----------------------------------------------
656  po::options_description general_opt("Allowed options are");
657  general_opt.add_options()
658  ("help,h", "display this message")
659  ("aparam,a", po::value<int>(), "pattern a parameter" )
660  ("bparam,b", po::value<int>(), "pattern b parameter" )
661  ("delta,d", po::value<int>()->default_value(1), "number of repetitions" )
662  ("triangulation,t", po::value<string>()->default_value("CH"), "output:\n\tClosest-point Delaunay triangulation {CDT}\n\tFarthest-point Delaunay triangulation {FDT}\n\tConvex hull {CH}" );
663 
664  bool parseOK=true;
665  po::variables_map vm;
666  try{
667  po::store(po::parse_command_line(argc, argv, general_opt), vm);
668  }catch(const std::exception& ex){
669  parseOK=false;
670  trace.info()<< "Error checking program options: "<< ex.what()<< endl;
671  }
672 
673  po::notify(vm);
674  if(!parseOK || vm.count("help")||argc<=1)
675  {
676  trace.info()<< "Draw the Delaunay triangulation of a pattern using DGtal library" <<std::endl
677  << "Basic usage: "<<std::endl
678  << "\t" << argv[0] << " -a 5 -b 8 "<<std::endl
679  << general_opt << "\n";
680  return 0;
681  }
682 
683 
684  if (!(vm.count("aparam"))) missingParam("-a");
685  if (!(vm.count("bparam"))) missingParam("-b");
686 
687  typedef DGtal::int32_t Integer;
688  Integer a = vm["aparam"].as<int>();
689  Integer b = vm["bparam"].as<int>();
690  if ( (a < 0) || (b <= 0) )
691  {
692  trace.error() << " parameters a and b should be strictly positive.";
693  trace.info() << std::endl;
694  return 0;
695  }
696  if (a >= b)
697  {
698  trace.error() << " parameter a should be strictly less than b.";
699  trace.info() << std::endl;
700  return 0;
701  }
702  Integer d = vm["delta"].as<int>();
703  if (d <= 0)
704  {
705  trace.error() << " parameter d should be strictly positive";
706  trace.info() << std::endl;
707  return 0;
708  }
709  trace.info() << "a=" << a << ", b=" << b << ", d=" << d << std::endl;
710 
711  typedef DGtal::int32_t Quotient;
713  typedef SB::Fraction Fraction; // the type for fractions
714  typedef Pattern<Fraction> Pattern; // the type for patterns
715 
716  Pattern pattern( a, b );
717 
718  string type = vm["triangulation"].as<string>();
719  if (type == "CDT")
720  {
721  displayCDT(pattern, d);
722  }
723  else if (type == "FDT")
724  {
725  displayConvexHull(pattern, d, true);
726  }
727  else if (type == "CH")
728  {
729  displayConvexHull(pattern, d);
730  }
731  else
732  {
733  trace.error() << " unknown output type. Try -h option. ";
734  trace.info() << std::endl;
735  return 0;
736  }
737 
738  return 1;
739 }
DGtal::int32_t Integer
static const Color Black
HyperRectDomain< Space > Domain
IC::Point2I Point2I
TFraction Fraction
Vector2I v() const
STL namespace.
Fraction slope() const
Point2I U(Quotient k) const
Board & setLineStyle(Shape::LineStyle style)
IC::Vector2I Vector2I
Trace trace(traceWriterTerm)
std::ostream & info()
void saveEPS(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
typename Self::Point Point
Vector2I bezout() const
Board & setPenColor(const DGtal::Color &color)
boost::int32_t int32_t
Pattern previousPattern() const
std::ostream & error()
Space::Vector Vector