void build_skeleton(const char* fname)
{
  typedef typename Kernel::Point_2                                         Point_2;
  typedef CGAL::Polygon_2<Kernel>                                 Polygon_2;
  typedef CGAL::Straight_skeleton_builder_traits_2<Kernel>        SsBuilderTraits;
  typedef CGAL::Straight_skeleton_2<Kernel>                       Ss;
  typedef CGAL::Straight_skeleton_builder_2<SsBuilderTraits,Ss>   SsBuilder;
  
  Polygon_2 pgn;
  
  std::ifstream input(fname);
  
  FT x,y;
  while(input)
  {
    input >> x;
    if (!input) break;
    input >> y;
    if (!input) break;
    pgn.push_back( Point_2( typename Kernel::FT(x), typename Kernel::FT(y) ) );
  }
  input.close();
  
  std::cout << "Polygon has " << pgn.size() <<  " points\n";
  
  if(!pgn.is_counterclockwise_oriented()) {
      std::cerr << "Polygon is not CCW Oriented" << std::endl;
  }
  if(!pgn.is_simple()) {
      std::cerr << "Polygon is not simple" << std::endl;
  }  

  CGAL::Timer time;
  time.start();
  SsBuilder ssb;
  ssb.enter_contour(pgn.vertices_begin(), pgn.vertices_end());
  boost::shared_ptr<Ss> straight_ske = ssb.construct_skeleton();
  time.stop();
  
  std::cout << "Time spent to build skeleton " << time.time() << "\n";
  
  if(!straight_ske->is_valid()) {
      std::cerr << "Straight skeleton is not valid" << std::endl;
  }

  std::cerr.precision(60);
  print_straight_skeleton(*straight_ske);
  
}
Exemplo n.º 2
0
int main()
{
  // A start-shaped polygon, oriented counter-clockwise as required for outer contours.
  Point_2 pts[] = { Point_2(-1,-1)
                  , Point_2(0,-12)
                  , Point_2(1,-1)
                  , Point_2(12,0)
                  , Point_2(1,1)
                  , Point_2(0,12)
                  , Point_2(-1,1)
                  , Point_2(-12,0)
                  } ;

  std::vector<Point_2> star(pts,pts+8);

  // We want an offset contour in the outside.
  // Since the package doesn't support that operation directly, we use the following trick:
  // (1) Place the polygon as a hole of a big outer frame.
  // (2) Construct the skeleton on the interior of that frame (with the polygon as a hole)
  // (3) Construc the offset contours
  // (4) Identify the offset contour that corresponds to the frame and remove it from the result


  double offset = 3 ; // The offset distance

  // First we need to determine the proper separation between the polygon and the frame.
  // We use this helper function provided in the package.
  boost::optional<double> margin = CGAL::compute_outer_frame_margin(star.begin(),star.end(),offset);

  // Proceed only if the margin was computed (an extremely sharp corner might cause overflow)
  if ( margin )
  {
    // Get the bbox of the polygon
    CGAL::Bbox_2 bbox = CGAL::bbox_2(star.begin(),star.end());

    // Compute the boundaries of the frame
    double fxmin = bbox.xmin() - *margin ;
    double fxmax = bbox.xmax() + *margin ;
    double fymin = bbox.ymin() - *margin ;
    double fymax = bbox.ymax() + *margin ;

    // Create the rectangular frame
    Point_2 frame[4]= { Point_2(fxmin,fymin)
                      , Point_2(fxmax,fymin)
                      , Point_2(fxmax,fymax)
                      , Point_2(fxmin,fymax)
                      } ;

    // Instantiate the skeleton builder
    SsBuilder ssb ;

    // Enter the frame
    ssb.enter_contour(frame,frame+4);

    // Enter the polygon as a hole of the frame (NOTE: as it is a hole we insert it in the opposite orientation)
    ssb.enter_contour(star.rbegin(),star.rend());

    // Construct the skeleton
    boost::shared_ptr<Ss> ss = ssb.construct_skeleton();

    // Proceed only if the skeleton was correctly constructed.
    if ( ss )
    {
      print_straight_skeleton(*ss);
      
      // Instantiate the container of offset contours
      ContourSequence offset_contours ;

      // Instantiate the offset builder with the skeleton
      OffsetBuilder ob(*ss);

      // Obtain the offset contours
      ob.construct_offset_contours(offset, std::back_inserter(offset_contours));

      // Locate the offset contour that corresponds to the frame
      // That must be the outmost offset contour, which in turn must be the one
      // with the largetst unsigned area.
      ContourSequence::iterator f = offset_contours.end();
      double lLargestArea = 0.0 ;
      for (ContourSequence::iterator i = offset_contours.begin(); i != offset_contours.end(); ++ i  )
      {
        double lArea = CGAL_NTS abs( (*i)->area() ) ; //Take abs() as  Polygon_2::area() is signed.
        if ( lArea > lLargestArea )
        {
          f = i ;
          lLargestArea = lArea ;
        }
      }

      // Remove the offset contour that corresponds to the frame.
      offset_contours.erase(f);
      
      print_polygons(offset_contours);
    }
  }

  return 0;
}
Exemplo n.º 3
0
PwhPtr CstmCGAL::applyOffset(double offset, const Polygon_with_holes_2& poly) {

    // This code is inspired from the CGAL example Straight_skeleton_2/Low_level_API
    // As the offset can only produce an interior polygon, we need to produce a frame
    // that encloses the polygon and is big enough so that the offset of the contour
    // does not interfere with the one ot the polygon. See CGAL doc page for more info
    boost::optional<double> margin = CGAL::compute_outer_frame_margin(
                                         poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end(),offset);

    if ( margin ) {

        CGAL::Bbox_2 bbox = CGAL::bbox_2(poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end());

        double fxmin = bbox.xmin() - *margin ;
        double fxmax = bbox.xmax() + *margin ;
        double fymin = bbox.ymin() - *margin ;
        double fymax = bbox.ymax() + *margin ;

        // Create the rectangular frame
        Point_2 frame[4]= { Point_2(fxmin,fymin)
                            , Point_2(fxmax,fymin)
                            , Point_2(fxmax,fymax)
                            , Point_2(fxmin,fymax)
                          } ;

        SsBuilder ssb ;

        ssb.enter_contour(frame,frame+4);

        // We have to revert the orientation of the polygon
        std::vector<Point_2> outerBoundary = std::vector<Point_2>(
                poly.outer_boundary().vertices_begin(),poly.outer_boundary().vertices_end());

        ssb.enter_contour(outerBoundary.rbegin(), outerBoundary.rend());

        SsPtr ss = ssb.construct_skeleton();

        if ( ss ) {
            std::vector<Polygon_2Ptr> offset_contours ;

            OffsetBuilder ob(*ss);

            ob.construct_offset_contours(offset, std::back_inserter(offset_contours));

            // Locate the offset contour that corresponds to the frame
            // That must be the outmost offset contour, which in turn must be the one
            // with the largest unsigned area.
            std::vector<Polygon_2Ptr>::iterator f = offset_contours.end();
            double lLargestArea = 0.0 ;
            for (std::vector<Polygon_2Ptr>::iterator i = offset_contours.begin(); i != offset_contours.end(); ++ i) {
                double lArea = CGAL_NTS abs( (*i)->area() ) ; //Take abs() as  Polygon_2::area() is signed.
                if ( lArea > lLargestArea ) {
                    f = i ;
                    lLargestArea = lArea ;
                }
            }

            offset_contours.erase(f);

            // Construct result polygon

            std::vector<Point_2> newOuterBoundary = std::vector<Point_2>(
                    offset_contours.front()->vertices_begin(), offset_contours.front()->vertices_end());

            Polygon_with_holes_2 result = Polygon_with_holes_2(Polygon_2(newOuterBoundary.rbegin(), newOuterBoundary.rend()));

            // We have to handle the holes separately

            for (auto it = poly.holes_begin() ; it != poly.holes_end() ; it++) {
                std::vector<Point_2> hole = std::vector<Point_2>(it->vertices_begin(),it->vertices_end());

                std::vector<PwhPtr> holeOffsets =
                    CGAL::create_interior_skeleton_and_offset_polygons_with_holes_2(offset,
                            Polygon_with_holes_2(Polygon_2(hole.begin(), hole.end())));

                for (auto it2 = holeOffsets.begin() ; it2 != holeOffsets.end() ; it++) {
                    std::vector<Point_2> revertNewHoles = std::vector<Point_2>(
                            (*it2)->outer_boundary().vertices_begin(),(*it2)->outer_boundary().vertices_end());

                    result.add_hole(Polygon_2(revertNewHoles.rbegin(), revertNewHoles.rend()));
                }
            }

            return boost::make_shared<Polygon_with_holes_2>(result);
        }
    }

    return NULL;
}