int main () { Delaunay t; trace.beginBlock("Construction the shape"); typedef Ellipse2D<Z2i::Space> Ellipse; int a = 5, b = 3; Ellipse2D<Z2i::Space> ellipse(Z2i::Point(0,0), a, b, 0.3 ); // Ellipse2D<Z2i::Space> ellipse(Z2i::Point(0,0), 5.5, 5.5, 0 ); double h = 0.25; GaussDigitizer<Z2i::Space,Ellipse> dig; dig.attach( ellipse ); dig.init( ellipse.getLowerBound()+Z2i::Vector(-1,-1), ellipse.getUpperBound()+Z2i::Vector(1,1), h ); // typedef Flower2D<Z2i::Space> Flower; // Flower2D<Z2i::Space> flower(Z2i::Point(0,0), 15, 2, 5, 0); // double h = 0.25; // GaussDigitizer<Z2i::Space,Flower> dig; // dig.attach( flower ); // dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), // flower.getUpperBound()+Z2i::Vector(1,1), h ); Z2i::KSpace ks; ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); SurfelAdjacency<2> sAdj( true ); Z2i::SCell bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 1000 ); std::vector<Z2i::Point> boundaryPoints; Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); Z2i::Curve c; c.initFromVector( boundaryPoints ); typedef Z2i::Curve::PointsRange Range; Range r = c.getPointsRange(); trace.endBlock(); trace.beginBlock("Delaunay"); for(Range::ConstIterator it=r.begin(), itend=r.end(); it != itend; ++it) { t.insert( Point( (*it)[0], (*it)[1])); t.insert( Point( (*it)[0] + 3 + (int) ceil( ((double)b)/h ), (*it)[1] - 3 - (int) ceil( ((double)a)/h ) )); } trace.endBlock(); std::cout << "number of vertices : " ; std::cout << t.number_of_vertices() << std::endl; std::cout << "number of faces : " ; std::cout << t.number_of_faces() << std::endl; trace.beginBlock("Area minimizing triangulation"); Edge_iterator itnext; bool flip = true; bool inverse = false; unsigned int pass = 0; while ( flip ) { std::cout << "----------- pass " << pass << " -------------------" << std::endl; inverse = false; flip = false; int nb_flip = 0; int nb_random_flip = 0; for( Edge_iterator it = t.edges_begin(), itend=t.edges_end(); it != itend; it = itnext ) { // vertex(cw(i)) and vertex(ccw(i)) of f. itnext = it; ++itnext; Edge e1 = *it; if ( isEdgeElementary( t, e1.first->vertex( t.ccw( e1.second ) ), e1.first->vertex( t.cw( e1.second ) ) ) ) continue; Edge e2 = t.mirror_edge( e1 ); if ( ! isQuadrilateral( t, e1.first->vertex( e1.second ), e1.first->vertex( t.ccw( e1.second ) ), e2.first->vertex( e2.second ), e1.first->vertex( t.cw( e1.second ) ) ) ) continue; int nb_f1 = twiceNbLatticePointsInTriangle( t, e1.first ); int nb_f2 = twiceNbLatticePointsInTriangle( t, e2.first ); int nb_flip_f1 = twiceNbLatticePointsInTriangle( t, e1.first->vertex( e1.second ), e1.first->vertex( t.ccw( e1.second ) ), e2.first->vertex( e2.second ) ); int nb_flip_f2 = twiceNbLatticePointsInTriangle( t, e1.first->vertex( e1.second ), e1.first->vertex( t.cw( e1.second ) ), e2.first->vertex( e2.second ) ); int nb_min = nb_f1 <= nb_f2 ? nb_f1 : nb_f2; int nb_flip_min = nb_flip_f1 <= nb_flip_f2 ? nb_flip_f1 : nb_flip_f2; if ( nb_flip_min < nb_min ) { std::cout << "flipped " << e1.first->vertex( e1.second )->point() << "->" << e1.first->vertex( e1.second )->point() << std::endl; t.flip( e1.first, e1.second ); nb_flip++; flip = true; } if ( nb_flip_min == nb_min ) { inverse = true; if ( random() % 2 == 1 ) { std::cout << "Random flipped " << e1.first->vertex( e1.second )->point() << "->" << e1.first->vertex( e1.second )->point() << std::endl; t.flip( e1.first, e1.second ); nb_random_flip++; } } // if ( ( empty_f1 == false ) // && ( empty_f2 == false ) ) // { // try if flip is better. // bool empty_flip_f1 // = twiceNbLatticePointsInTriangle( t, // e1.first->vertex( e1.second ), // e1.first->vertex( t.ccw( e1.second ) ), // e2.first->vertex( e2.second ) ) == 0; // bool empty_flip_f2 // = twiceNbLatticePointsInTriangle( t, // e2.first->vertex( e2.second ), // e2.first->vertex( t.ccw( e2.second ) ), // e1.first->vertex( e1.second ) ) == 0; // if ( empty_flip_f1 || empty_flip_f2 ) // { // if ( isEdgeElementary( t, // e1.first->vertex( t.ccw( e1.second ) ), // e1.first->vertex( t.cw( e1.second ) ) ) ) // { // std::cout << "Flip forbidden: " << e1.first->vertex( e1.second )->point() // << "->" << e1.first->vertex( e1.second )->point() // << std::endl; // } // else // { // std::cout << "flipped " << e1.first->vertex( e1.second )->point() // << "->" << e1.first->vertex( e1.second )->point() // << std::endl; // t.flip( e1.first, e1.second ); // flip = true; // } // } // } } std::cout << "----------- nb_flip " << nb_flip << ", nb_random " << nb_random_flip << " -------------" << std::endl; ++pass; if ( inverse && ( (nb_random_flip+4) > log(pass) ) ) flip = true; } trace.endBlock(); // GridCurve Z2i::Curve gc; gc.initFromPointsRange( r.begin(), r.end() ); typedef Z2i::Curve::PointsRange::ConstIterator ConstIterator; typedef ArithmeticalDSS<ConstIterator,int,4> DSS4; typedef SaturatedSegmentation<DSS4> Segmentation; //Segmentation Z2i::Curve::PointsRange range = gc.getPointsRange(); DSS4 dss4RecognitionAlgorithm; Segmentation theSegmentation( range.begin(), range.end(), dss4RecognitionAlgorithm ); DGtal::Board2D board; Z2i::Point dP; board << CustomStyle( dP.className(), new CustomPen( Color(0,0,0), Color(230,230,230), 1, Board2D::Shape::SolidStyle, Board2D::Shape::RoundCap, Board2D::Shape::RoundJoin )); for(Range::ConstIterator it=r.begin(), itend=r.end(); it != itend; ++it) board << *it; for(Faces_iterator it = t.finite_faces_begin(), itend=t.finite_faces_end(); it != itend; ++it) { Z2i::Point a( toDGtal(it->vertex(0)->point())), b(toDGtal(it->vertex(1)->point())), c(toDGtal(it->vertex(2)->point())); // Z2i::Vector ab( b - a ), ac( c - a ); // int d = ab[ 0 ] * ac[ 1 ] - ab[ 1 ] * ac[ 0 ]; if ( emptyLatticeTriangle( t, it ) ) //( ( d == 1 ) || (d == -1 ) ) { board.setPenColor(DGtal::Color::Blue); board.setFillColor( DGtal::Color::None ); board.setLineWidth( 3.0 ); board.drawTriangle(a[0],a[1],b[0],b[1],c[0],c[1]); } else { board.setPenColor(DGtal::Color::Red); board.setFillColor( DGtal::Color::None ); // board.setFillColorRGBi(200,200,200,128); board.setLineWidth( 2.0 ); board.drawTriangle(a[0],a[1],b[0],b[1],c[0],c[1]); } } Segmentation::SegmentComputerIterator i = theSegmentation.begin(); Segmentation::SegmentComputerIterator end = theSegmentation.end(); board.setPenColor(DGtal::Color::Green); board.setFillColor( DGtal::Color::None ); board << SetMode( "ArithmeticalDSS", "BoundingBox" ); std::string aStyleName = "ArithmeticalDSS/BoundingBox"; for ( ; i != end; ++i) { DSS4 current(*i); board << CustomStyle( aStyleName, new CustomPenColor( DGtal::Color::Green ) ) << current; } // Display Voronoi. // for(Edge_iterator it = t.edges_begin(), itend=t.edges_end(); // it != itend; ++it) // { // // vertex(cw(i)) and vertex(ccw(i)) of f. // Face_handle itf = it->first; // int i = it->second; // Z2i::Point a( toDGtal(itf->vertex( t.cw( i ) )->point())); // Z2i::Point b( toDGtal(itf->vertex( t.ccw( i ) )->point())); // CGAL::Object o = t.dual( it ); // if (CGAL::object_cast<K::Segment_2>(&o)) // { // const K::Segment_2* ptrSegment = CGAL::object_cast<K::Segment_2>(&o); // board.setPenColor(DGtal::Color::Black); // board.setFillColor( DGtal::Color::None ); // board.setLineWidth( 2.0 ); // board.drawLine( ptrSegment->source().x(), // ptrSegment->source().y(), // ptrSegment->target().x(), // ptrSegment->target().y() ); // } // else if (CGAL::object_cast<K::Ray_2>(&o)) // { // const K::Ray_2* ptrRay = CGAL::object_cast<K::Ray_2>(&o); // board.setPenColor(DGtal::Color::Black); // board.setFillColor( DGtal::Color::None ); // board.setLineWidth( 2.0 ); // double dx = ptrRay->to_vector().x(); // double dy = ptrRay->to_vector().y(); // double norm = sqrt( dx*dx+dy*dy ); // dx = 5.0 * dx / norm; // dy = 5.0 * dy / norm; // board.drawArrow( ptrRay->source().x(), // ptrRay->source().y(), // ptrRay->source().x() + dx, //1*ptrRay->to_vector().x(), // ptrRay->source().y() + dy ); //1*ptrRay->to_vector().y() ); // } // } board.saveSVG("delaunay.svg"); board.saveEPS("delaunay.eps"); return 0; }
/** * Algorithms that computes the alpha-shape * of a point set */ void alphaShape() { //Digitization of a disk of radius 8 Ball2D<Z2i::Space> ball(Z2i::Point(0,0), 8); Z2i::Domain domain(ball.getLowerBound(), ball.getUpperBound()); Z2i::DigitalSet digitalSet(domain); Shapes<Z2i::Domain>::euclideanShaper(digitalSet, ball); //Contour of the digital set Z2i::KSpace kspace; kspace.init(domain.lowerBound()-Z2i::Point(1,1), domain.upperBound()+Z2i::Point(1,1), true); typedef DigitalSetBoundary<Z2i::KSpace, Z2i::DigitalSet> DigitalSurfaceContainer; typedef DigitalSurface<DigitalSurfaceContainer> CustomDigitalSurface; DigitalSurfaceContainer digitalSurfaceContainer( kspace, digitalSet ); CustomDigitalSurface digitalSurface( digitalSurfaceContainer ); //Grid curve Z2i::Curve gridCurve; typedef DepthFirstVisitor<DigitalSurface<DigitalSurfaceContainer> > CustomVisitor; CustomVisitor visitor( digitalSurface, *digitalSurface.begin() ); while ( ! visitor.finished() ) { gridCurve.pushBack( visitor.current().first ); visitor.expand(); } //Point set defined as the set of (not duplicated) inner points typedef Z2i::Curve::InnerPointsRange PointRange; PointRange pointsRange = gridCurve.getInnerPointsRange(); vector<Z2i::Point> border; unique_copy( pointsRange.begin(), pointsRange.end(), back_inserter( border ) ); //namespace for hull functions using namespace functions::Hull2D; { //alpha = 0 trace.info() << " alpha == 0 " << endl; vector<Z2i::Point> res; //! [Hull2D-RadiusPredicateInf] typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; Functor functor(true, 1, 0); //alpha = 0; 1/alpha -> +inf typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); //! [Hull2D-RadiusPredicateInf] //! [Hull2D-ClosedGrahamScan] closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //! [Hull2D-ClosedGrahamScan] //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShape0.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShape0.png", Board2D::CairoPNG); #endif } { //alpha = 0 trace.info() << " alpha == 0 " << endl; vector<Z2i::Point> res; //comparator and functor typedef InHalfPlaneBySimple3x3Matrix<Z2i::Point, DGtal::int64_t> Functor; Functor functor; typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShape0bis.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShape0bis.png", Board2D::CairoPNG); #endif } //negative alpha shape { //alpha = -1 trace.info() << " alpha == -1 " << endl; vector<Z2i::Point> res; typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; //! [Hull2D-RadiusPredicateM1] Functor functor(false, 1, 1); //1/alpha = -sqrt(1/1) = -1 //! [Hull2D-RadiusPredicateM1] typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShapeM1.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShapeM1.png", Board2D::CairoPNG); #endif } { //alpha = -sqrt(5) trace.info() << " alpha == -sqrt(5) " << endl; vector<Z2i::Point> res; typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; //! [Hull2D-RadiusPredicateMsqrt5] Functor functor(false, 5, 1); //1/alpha = -sqrt(5) //! [Hull2D-RadiusPredicateMsqrt5] typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShapeMSqrt5.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShapeMSqrt5.png", Board2D::CairoPNG); #endif } { //alpha = -5 trace.info() << " alpha == -5 " << endl; vector<Z2i::Point> res; typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; //! [Hull2D-RadiusPredicateM5] Functor functor(false, 25, 1); //1/alpha = -sqrt(25/1) = -5 //! [Hull2D-RadiusPredicateM5] typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShapeM5.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShapeM5.png", Board2D::CairoPNG); #endif } //positive alpha shape { trace.info() << " alpha == 8 " << endl; vector<Z2i::Point> res; //! [Hull2D-RadiusPredicateP8] typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; Functor functor(true, 64, 1); //1/alpha = sqrt(64/1) = 8 typedef PredicateFromOrientationFunctor2<Functor, false, true> Predicate; Predicate predicate( functor ); //! [Hull2D-RadiusPredicateP8] closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShapeP8.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShapeP8.png", Board2D::CairoPNG); #endif } //positive alpha shape { trace.info() << " alpha == 9 " << endl; vector<Z2i::Point> res; typedef AvnaimEtAl2x2DetSignComputer<DGtal::int64_t> DetComputer; typedef InGeneralizedDiskOfGivenRadius<Z2i::Point, DetComputer> Functor; //! [Hull2D-RadiusPredicateP9] Functor functor(true, 81, 1); //1/alpha = sqrt(81/1) = 9 //! [Hull2D-RadiusPredicateP9] typedef PredicateFromOrientationFunctor2<Functor> Predicate; Predicate predicate( functor ); closedGrahamScanFromAnyPoint( border.begin(), border.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "AlphaShapeP9.svg" ); #ifdef WITH_CAIRO board.saveCairo("AlphaShapeP9.png", Board2D::CairoPNG); #endif } }
int main() { //shape typedef Flower2D<Z2i::Space> Flower; Flower2D<Z2i::Space> flower(Z2i::Point(0,0), 20, 5, 5, 0); //! [shapeGridCurveEstimator-dig] //implicit digitization of a shape of type Flower //into a digital space of type Space double h = 1; GaussDigitizer<Z2i::Space,Flower> dig; dig.attach( flower ); dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), flower.getUpperBound()+Z2i::Vector(1,1), h ); //! [shapeGridCurveEstimator-dig] //! [shapeGridCurveEstimator-prepareTracking] //Khalimsky space Z2i::KSpace ks; ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); //adjacency (4-connectivity) SurfelAdjacency<2> sAdj( true ); //! [shapeGridCurveEstimator-prepareTracking] //! [shapeGridCurveEstimator-tracking] //searching for one boundary element Z2i::SCell bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 1000 ); //tracking vector<Z2i::Point> boundaryPoints; Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); //! [shapeGridCurveEstimator-tracking] //! [shapeGridCurveEstimator-instantiation] Z2i::Curve c; c.initFromVector( boundaryPoints ); //! [shapeGridCurveEstimator-instantiation] DGtal::Board2D aBoard; aBoard << c; aBoard.saveEPS("DisplayGridCurve1.eps"); //! [shapeGridCurveEstimator-getRange] //range of points typedef Z2i::Curve::PointsRange Range; Range r = c.getPointsRange(); //! [shapeGridCurveEstimator-getRange] //! [shapeGridCurveEstimator-lengthEstimation] //length estimation DSSLengthEstimator< Range::ConstIterator > DSSlength; DSSlength.init( h, r.begin(), r.end(), c.isClosed() ); double length1 = DSSlength.eval(); trace.info() << "Length (h=" << h << "): " << length1 << endl; //! [shapeGridCurveEstimator-lengthEstimation] //@TODO correct init method of trueLengthEstimator (remove &flower) //! [shapeGridCurveEstimator-trueLengthEstimation] typedef ParametricShapeArcLengthFunctor< Flower > Length; TrueGlobalEstimatorOnPoints< Range::ConstIterator, Flower, Length > trueLengthEstimator; trueLengthEstimator.init( h, r.begin(), r.end(), &flower, c.isClosed()); double trueLength = trueLengthEstimator.eval(); trace.info() << "ground truth: " << trueLength << endl; //! [shapeGridCurveEstimator-trueLengthEstimation] //! [shapeGridCurveEstimator-higher] //implicit digitization at higher resolution h = 0.1; dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), flower.getUpperBound()+Z2i::Vector(1,1), h ); //a greater domain is needed in the Khalimsky space ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); //searching for one boundary element bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 10000 ); //tracking Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); //reset grid curve and its points range c.initFromVector( boundaryPoints ); Range r2 = c.getPointsRange(); //estimate length DSSlength.init( h, r2.begin(), r2.end(), c.isClosed() ); double length2 = DSSlength.eval(); trace.info() << "Length (h=" << h << "): " << length2 << endl; //! [shapeGridCurveEstimator-higher] aBoard.clear(); aBoard << c; aBoard.saveEPS("DisplayGridCurve01.eps"); return 0; }