int 
main(int argc, char ** argv){
  typedef Z2i::Point Point;
  std::vector<Point> contour = PointListReader<Point>::getPointsFromFile("../Samples/contourS.sdp");
  Board2D aBoard;
  for (auto&& p :contour) {
    aBoard << p;
  }
  aBoard.setPenColor(DGtal::Color::Red);
  aBoard.setFillColor(DGtal::Color::Red);
  aBoard.drawCircle(contour[30][0], contour[30][1],1); 
  unsigned int startIndex = 30;
  typedef  AlphaThickSegmentComputer< Z2i::Point > AlphaThickSegmentComputer2D;
  AlphaThickSegmentComputer2D aComputer(5);
  aComputer.init(contour.begin()+30);
  while(aComputer.extendFront()){
  }

  aBoard  << CustomStyle( aComputer.className(), new CustomColors( DGtal::Color::Blue, DGtal::Color::None ) );  
  aBoard << aComputer;
  aBoard.saveEPS("resultTuto2.eps");
  
  return 0;
}
/**
 * Algorithms that computes the convex hull
 * of a point set
 */
void convexHull()
{
  //Digitization of a disk of radius 6
  Ball2D<Z2i::Space> ball(Z2i::Point(0,0), 6);
  Z2i::Domain domain(ball.getLowerBound(), ball.getUpperBound());
  Z2i::DigitalSet pointSet(domain);   
  Shapes<Z2i::Domain>::euclideanShaper(pointSet, ball);

  //! [Hull2D-Namespace]
  using namespace functions::Hull2D; 
  //! [Hull2D-Namespace]

  //! [Hull2D-Functor]
  typedef InHalfPlaneBySimple3x3Matrix<Z2i::Point, DGtal::int64_t> Functor;  
  Functor functor; 
  //! [Hull2D-Functor]

  { //convex hull in counter-clockwise order
    vector<Z2i::Point> res; 

    //! [Hull2D-StrictPredicateCCW]
    typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; 
    StrictPredicate predicate( functor ); 
    //! [Hull2D-StrictPredicateCCW]
    //according to the last two template arguments, neither strictly negative values, nor zeros are accepted: 
    //the predicate returns 'true' only for strictly positive values returned by the underlying functor. 

    //! [Hull2D-AndrewAlgo]
    andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate );   
    //! [Hull2D-AndrewAlgo]
    //![Hull2D-Caliper-computeBasic]
    double th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness);
    //![Hull2D-Caliper-computeBasic]

    //![Hull2D-Caliper-computeAnti]
    Z2i::Point antipodalP, antipodalQ, antipodalS;
    th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness, antipodalP, antipodalQ, antipodalS);
    //![Hull2D-Caliper-computeAnti]

    
    trace.info() <<" ConvexHull HV thickness: " << th << std::endl;
    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board ); 
    //![Hull2D-Caliper-display]
    board.setPenColor(DGtal::Color::Red);
    board.drawCircle( antipodalS[0], antipodalS[1], 0.2) ;
    board.setPenColor(DGtal::Color::Blue);
    board.drawCircle(antipodalP[0], antipodalP[1], 0.2);
    board.drawCircle(antipodalQ[0], antipodalQ[1], 0.2);
    board.drawLine(antipodalP[0], antipodalP[1], antipodalQ[0], antipodalQ[1]);
    //![Hull2D-Caliper-display]
    
    board.saveSVG( "ConvexHullCCW.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("ConvexHullCCW.png", Board2D::CairoPNG);
#endif
  }

  { //convex hull in counter-clockwise order with all the points lying on the edges
    vector<Z2i::Point> res; 

    //! [Hull2D-LargePredicateCCW]
    typedef PredicateFromOrientationFunctor2<Functor, false, true> LargePredicate; 
    LargePredicate predicate( functor ); 
    //! [Hull2D-LargePredicateCCW]
    //according to the last template argument, zeros are accepted so that  
    //the predicate returns 'true' for all the positive values returned by the underlying functor. 

    //andrew algorithm
    andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate );   

    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board ); 
    board.saveSVG( "ConvexHullCCWWithPointsOnEdges.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("ConvexHullCCWWithPointsOnEdges.png", Board2D::CairoPNG);
#endif

  }

  { //convex hull in clockwise order
    vector<Z2i::Point> res; 

    //! [Hull2D-StrictPredicateCW]
    typedef PredicateFromOrientationFunctor2<Functor, true, false> StrictPredicate; 
    StrictPredicate predicate( functor );
    //! [Hull2D-StrictPredicateCW]
    //according to the last two argument template, 
    //the predicate returns 'true' only for strictly negative values returned by the underlying functor. 

    //andrew algorithm
    andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate );   

    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board ); 
    board.saveSVG( "ConvexHullCW.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("ConvexHullCW.png", Board2D::CairoPNG);
#endif
  }

  { //convex hull in counter-clockwise order
    vector<Z2i::Point> res; 

    //geometric predicate
    typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; 
    StrictPredicate predicate( functor ); 

    //! [Hull2D-GrahamAlgo]
    grahamConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate ); 
    //! [Hull2D-GrahamAlgo]

    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board ); 
    board.saveSVG( "ConvexHullCCWbis.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("ConvexHullCCWbis.png", Board2D::CairoPNG);
#endif
  }

  { //convex hull of a simple polygonal line that is not weakly externally visible
    vector<Z2i::Point> polygonalLine;
    polygonalLine.push_back(Z2i::Point(0,0)); 
    polygonalLine.push_back(Z2i::Point(0,4)); 
    polygonalLine.push_back(Z2i::Point(1,4)); 
    polygonalLine.push_back(Z2i::Point(1,1)); 
    polygonalLine.push_back(Z2i::Point(3,1)); 
    polygonalLine.push_back(Z2i::Point(2,2)); 
    polygonalLine.push_back(Z2i::Point(3,4)); 
    polygonalLine.push_back(Z2i::Point(4,4)); 
    polygonalLine.push_back(Z2i::Point(4,0)); 

    vector<Z2i::Point> resGraham, res; 

    typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; 
    StrictPredicate predicate( functor ); 
    closedGrahamScanFromAnyPoint( polygonalLine.begin(), polygonalLine.end(), back_inserter( resGraham ), predicate );   

    //! [Hull2D-OnLineMelkmanAlgo]
    DGtal::MelkmanConvexHull<Z2i::Point, Functor> ch( functor ); 
    for (std::vector<Z2i::Point>::const_iterator 
	   it = polygonalLine.begin(), 
	   itEnd = polygonalLine.end(); 
	 it != itEnd; ++it)
      ch.add( *it ); 
    //! [Hull2D-OnLineMelkmanAlgo]

    //! [Hull2D-OffLineMelkmanAlgo]
    melkmanConvexHullAlgorithm( polygonalLine.begin(), polygonalLine.end(), back_inserter( res ), functor );   
    //! [Hull2D-OffLineMelkmanAlgo]

    //display
    Board2D board;
    drawPolygon( polygonalLine.begin(), polygonalLine.end(), board, true ); 
    board.saveSVG( "SimplePolygonalLine.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("SimplePolygonalLine.png", Board2D::CairoPNG);
#endif
    board.clear(); 
    drawPolygon( resGraham.begin(), resGraham.end(), board ); 
    board.saveSVG( "SimplePolygonalLineGraham.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("SimplePolygonalLineGraham.png", Board2D::CairoPNG);
#endif
    board.clear(); 
    drawPolygon( res.begin(), res.end(), board ); 
    board.saveSVG( "SimplePolygonalLineMelkman.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("SimplePolygonalLineMelkman.png", Board2D::CairoPNG);
#endif
    board.clear(); 
    drawPolygon( ch.begin(), ch.end(), board ); 
    board.saveSVG( "SimplePolygonalLineMelkman2.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("SimplePolygonalLineMelkman2.png", Board2D::CairoPNG);
#endif
  }

  { //order of the points for andrew algorithm
    vector<Z2i::Point> res; 
    std::copy( pointSet.begin(), pointSet.end(), back_inserter( res ) ); 

    std::sort( res.begin(), res.end() ); 

    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board, false ); 
    board.saveSVG( "AndrewWEVP.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("AndrewWEVP.png", Board2D::CairoPNG);
#endif
  }

  { //order of the points for graham algorithm
    vector<Z2i::Point> res; 
    std::copy( pointSet.begin(), pointSet.end(), back_inserter( res ) ); 

    //find an extremal point
    //NB: we choose the point of greatest x-coordinate
    //so that the sort step (by a polar comparator) 
    //returns a weakly externally visible polygon
    std::vector<Z2i::Point>::iterator itMax 
      = std::max_element( res.begin(), res.end() ); 

    //sort around this point with a polar comparator
    functors::PolarPointComparatorBy2x2DetComputer<Z2i::Point> comparator;  
    comparator.setPole( *itMax );
    std::sort( res.begin(), res.end(), comparator ); 

    //display
    Board2D board;
    drawPolygon( res.begin(), res.end(), board, false ); 
    board.saveSVG( "GrahamWEVP.svg" );  
#ifdef WITH_CAIRO
    board.saveCairo("GrahamWEVP.png", Board2D::CairoPNG);
#endif
  }


}