Beispiel #1
0
bool boundaries_intersect(const Polygon_2& P, const Polygon_2& Q, bool proper)
{
  std::list<Segment_2> segments0, segments1;
  segments0.insert(segments0.end(), P.edges_begin(), P.edges_end());
  segments1.insert(segments1.end(), Q.edges_begin(), Q.edges_end());
  
  bool intersects = has_intersection(segments0.begin(), segments0.end(), 
			  segments1.begin(), segments1.end(), 
			  true, true);
  if (!intersects || !proper)
    return intersects;

  if (has_intersection(segments0.begin(), segments0.end(), 
		       segments1.begin(), segments1.end(), 
		       false, false))
    return true;

  typedef Polygon_2::Vertex_const_iterator Iter;
  for (Iter it = P.vertices_begin(); it != P.vertices_end(); ++it) {
    if (Q.has_on_bounded_side(*it))
      return true;
  }
  for (Iter it = Q.vertices_begin(); it != Q.vertices_end(); ++it) {
    if (P.has_on_bounded_side(*it))
      return true;
  }
  return false;
}
int main()
{
  CGAL::set_pretty_mode(cout);

  // build a random convex 20-gon p
  {
    Polygon_2 p;
    random_convex_set_2(20, back_inserter(p), Point_generator(1.0));
    cout << "------------------------------\nInput:\n" << p << endl;
    compute(p.vertices_begin(), p.vertices_end());
  }

  // try identical points
  {
    Polygon_2 p;
    for (int i = 1; i < 3; ++i) {
      cout << "------------------------------\nInput:\n" << p << endl;
      compute(p.vertices_begin(), p.vertices_end());
      p.push_back(Point_2(0,0));
    }
  }


  return 0;
} 
void decomposePolygonCgal(geometry_msgs::Polygon& input, std::vector<geometry_msgs::Polygon>& output)
{
    Polygon_list cgalOutputPolys;
    Traits partitionTraits;
    Validity_traits validityTraits;

    // Convert from ROS-polygon to CGAL polygon
    Polygon_2 cgalInput;

    for (int i = 0; i < input.points.size(); i++)
    {
        cgalInput.push_back(Point_2(input.points[i].x, input.points[i].y));
    }

    // Make sure we have a COUNTERCLOCKWISE polygon
    if (cgalInput.orientation() == CGAL::CLOCKWISE)
    {
        cgalInput.clear();
        for (int i = input.points.size() - 1; i >= 0; i--)
        {
            cgalInput.push_back(Point_2(input.points[i].x, input.points[i].y));
        }
    }

    // Do the decomposition using CGAL
    CGAL::optimal_convex_partition_2(
        cgalInput.vertices_begin(), cgalInput.vertices_end(), std::back_inserter(cgalOutputPolys), partitionTraits);

    std::cout << "CHECK output data!" << std::endl;
    assert(CGAL::partition_is_valid_2(cgalInput.vertices_begin(),
                                      cgalInput.vertices_end(),
                                      cgalOutputPolys.begin(),
                                      cgalOutputPolys.end(),
                                      validityTraits));

    // Now walk through the result and convert to ROS
    for (Polygon_iterator poly_it = cgalOutputPolys.begin(); poly_it != cgalOutputPolys.end(); poly_it++)
    {
        Polygon_2 p = *poly_it;

        geometry_msgs::Polygon outputPoly;

        // Iterate through the points for a polygon
        for (Vertex_iterator vi = p.vertices_begin(); vi != p.vertices_end(); ++vi)
        {
            Point_2 v = *vi;
            geometry_msgs::Point32 pt;
            pt.x = v.x();
            pt.y = v.y();

            outputPoly.points.push_back(pt);
        }

        output.push_back(outputPoly);
    }
}
Beispiel #4
0
void gnuplot_print_polygon(std::ostream& out, const Polygon_2& P)
{
    int prec = out.precision();
    out << std::setprecision(pp_precision);
    Polygon_2::Vertex_const_iterator  vit;
    for (vit = P.vertices_begin(); vit != P.vertices_end(); ++vit)
        vit->insert(out) << std::endl;//" " << vit->z() << std::endl;
    P.vertices_begin()->insert(out) << std::endl;//" " << P.vertices_begin()->z() << std::endl;
    out.precision(prec);
}
Beispiel #5
0
void gnuplot_print_polygon(std::ostream& out, const Polygon_2& P, int z)
{
    int prec = out.precision();
    out << std::setprecision(pp_precision);
    Polygon_2::Vertex_const_iterator  vit;
    for (vit = P.vertices_begin(); vit != P.vertices_end(); ++vit)
        out << *vit << " " << z << std::endl;
    out << *(P.vertices_begin()) << " " << z << std::endl;
    out.precision(prec);
}
Beispiel #6
0
void perturb(Polygon_2& p, Number_type epsilon) {
  Polygon_2::Vertex_iterator vit;
  for (vit = p.vertices_begin(); vit != p.vertices_end(); ++vit) {
    Point_2 pnt = *vit;
    // Make sure we get a consistent perturbation with each point across runs
    const static Number_type prime = 827;
    srand((int)(pnt.x() + prime*(pnt.y() + prime*pnt.z())));
    pnt = Point_25_<Kernel>(perturb(pnt.x(), epsilon), perturb(pnt.y(), epsilon), pnt.z(), pnt.id());
    p.set(vit, pnt);
  }

  p = Polygon_2(p.vertices_begin(), unique(p.vertices_begin(), p.vertices_end()));
}
Beispiel #7
0
Polygon_2 xz_swap_neg(const Polygon_2& p)
{
  Polygon_2 ret;
  for (Polygon_2::Vertex_iterator it = p.vertices_begin(); it != p.vertices_end(); ++it)
    ret.push_back(xz_swap_neg(*it));
  return ret;
}
int main()
{
  Polygon_2 poly ;
  
  poly.push_back( Point(-1,-1) ) ;
  poly.push_back( Point(0,-12) ) ;
  poly.push_back( Point(1,-1) ) ;
  poly.push_back( Point(12,0) ) ;
  poly.push_back( Point(1,1) ) ;
  poly.push_back( Point(0,12) ) ;
  poly.push_back( Point(-1,1) ) ;
  poly.push_back( Point(-12,0) ) ;
     
  // You can pass the polygon via an iterator pair
  SsPtr iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());

  // Or you can pass the polygon directly, as below.
  
  // To create an exterior straight skeleton you need to specify a maximum offset.
  double lMaxOffset = 5 ; 
  SsPtr oss = CGAL::create_exterior_straight_skeleton_2(lMaxOffset, poly);
  
  print_straight_skeleton(*iss);
  print_straight_skeleton(*oss);
  
  return 0;
}
Beispiel #9
0
/*
 * append gA+gB into the polygonSet
 */
void minkowskiSum( const Point& gA, const Polygon_2& gB, Polygon_set_2& polygonSet )
{
    BOOST_ASSERT( gB.size() );

    CGAL::Aff_transformation_2< Kernel > translate(
        CGAL::TRANSLATION,
        gA.toVector_2()
    );

    Polygon_2 sum ;

    for ( Polygon_2::Vertex_const_iterator it = gB.vertices_begin();
            it != gB.vertices_end(); ++it ) {
        sum.push_back( translate.transform( *it ) );
    }

    if ( sum.is_clockwise_oriented() ) {
        sum.reverse_orientation() ;
    }

    if ( polygonSet.is_empty() ) {
        polygonSet.insert( sum );
    }
    else {
        polygonSet.join( sum );
    }
}
Beispiel #10
0
int main(int argc, char** argv)
{
    //Reading polygon files
    Polygon_2 poly;
    QPolygonF poly_qt;
    read_file("models/turtle_w.txt", poly, poly_qt);

    //Compute straight skeleton
    //*****This program now works for polygon WITHOUT HOLES.
    SsPtr iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());
    SsPtr ess = CGAL::create_exterior_straight_skeleton_2(EMaxOffset, poly);

    //Constructing the graph combining the straight skeleton and polygon
    std::vector<BridgingGraph> bg;
    construct_bridging_graph(poly, *iss, *ess, bg);

    //Compute perpendiculars
    std::list<Perpendiculars> ppd;
    generate_perpendiculars(*iss, *ess, bg, ppd);
    deduplicate_perpendiculars<K>(ppd);

    //Assign mountain and valley
    std::list<Segment> mt;
    std::list<Segment> vl;
    MountainValley<K>(*iss, *ess, bg, ppd,  mt, vl);

    //Extracts skeleton from cgal and converts them to qt
    std::list<QLineF> bis_qt;
    convert_straight_skeleton(*iss, bis_qt);
    convert_straight_skeleton(*ess, bis_qt);

    std::list<QLineF> ppd_qt;
    convert_perpendiculars<K>(ppd, ppd_qt);

    std::list<QLineF> mt_qt, vl_qt;
    convert_mountain_valley<K>(mt, mt_qt);
    convert_mountain_valley<K>(vl, vl_qt);

    //SETUP QT
    //Create applicaiton
    QApplication app(argc, argv);

    //Create scene
    QGraphicsScene scene;
    createQTscene(scene, poly_qt, bis_qt, ppd_qt, mt_qt, vl_qt);

    //Create view
    QGraphicsView* view = new QGraphicsView(&scene);
    CGAL::Qt::GraphicsViewNavigation nav;
    view->installEventFilter(&nav);
    view->viewport()->installEventFilter(&nav);
    view->setRenderHint(QPainter::Antialiasing);
    //view->keyPressEvent();

    //Show view
    view->show();

    return app.exec();
}
Point_2 centroid(const Polygon_2& P)
{
  Point_2 sum(0,0);
  BOOST_FOREACH (const Point_2& p, make_pair(P.vertices_begin(), P.vertices_end())) {
    sum = Point_2(sum.x() + p.x(), sum.y() + p.y());
  }
  return Point_2(sum.x()/P.size(), sum.y()/P.size());
}
Beispiel #12
0
// This class is mainly used for scaling all the polys to 
// a certain bounding box!
void PreProcessor::process(double xmin_target, double ymin_target, double width_target, double height_target) {
	auto it = ++tree->element_tree.begin();
	auto it_end = tree->element_tree.end();
	Bbox_2 bb_final;
	Bbox_2 bb;
	int i = 0;
	for(; it != it_end; ++it) {
		switch((*it)->get_type()) {
			case EL_POLYGON: {
				Polygon_2 * p = &(static_cast<PolygonElementPtr *>(*it)->element);
				bb = CGAL::bounding_box(p->vertices_begin(), p->vertices_end()).bbox();
			}
			case EL_FILLED_POLYGON:{
				Polygon_2 * p = &(static_cast<FilledPolygonElementPtr *>(*it)->element.outer_boundary());
				bb = CGAL::bounding_box(p->vertices_begin(), p->vertices_end()).bbox();
			}
			case EL_POLYLINE: {
				PolyLine_P * p = &(static_cast<PolyLineElementPtr *>(*it)->element);
				bb = CGAL::bounding_box(p->begin(), p->end()).bbox();
			}
		}
		if(i == 0) {
			bb_final = bb;
		} else {
			bb_final = bb_final + bb;
		}
		i++;
	}
	double w = bb_final.xmax() - bb_final.xmin();
	double h = bb_final.ymax() - bb_final.ymin();
	cout << "BB: " << bb_final.xmax()<< " " << bb_final.xmin() << " " << bb_final.ymax() << " " << bb_final.ymin() << endl;

	if(GlobalOptions::getInstance().field_offset) {
		width_target -= 2 * GlobalOptions::getInstance().field_offset;
		height_target -= 2 * GlobalOptions::getInstance().field_offset;
	}
	double ws = (double)width_target / (double)w;
	double hs = (double)height_target / (double)h;
	double s = (ws < hs) ? ws : hs;
	cout << "Scale: " << s << endl;
	this->process(s, 
		bb_final.xmin() - GlobalOptions::getInstance().field_offset * 1 / s, 
		bb_final.ymin() - GlobalOptions::getInstance().field_offset * 1 / s); // -bb_final.xmin() -bb_final.ymin();
}
Beispiel #13
0
void insert_polygon( CDT& cdt, const Polygon_2& polygon ) {
	if (polygon.is_empty())
		return;
	CDT::Vertex_handle v_prev = cdt.insert( *CGAL::cpp0x::prev( polygon.vertices_end() ) );
	for (Polygon_2::Vertex_iterator vit = polygon.vertices_begin(); vit != polygon.vertices_end(); ++vit) {
		CDT::Vertex_handle vh = cdt.insert(*vit);
		cdt.insert_constraint(vh, v_prev);
		v_prev = vh;
	}
}
Beispiel #14
0
VisiLibity::Polygon ConvertPolygonCGAL2Vis(Polygon_2 pgn)
{
    VisiLibity::Polygon cPoly;
    Polygon_2::Vertex_iterator cv ;
    for (cv=pgn.vertices_begin();cv!=pgn.vertices_end();++cv)
          {
              cPoly.push_back(VisiLibity::Point(cv->x(),cv->y()));
          };
    return cPoly;

}
Beispiel #15
0
std::string pp(const Polygon_2& P)
{
    Polygon_2::Vertex_const_iterator vit;
    std::stringstream out;
    out << std::setprecision(pp_precision);

    out << "[ " << P.size() << " vertices:";
    for (vit = P.vertices_begin(); vit != P.vertices_end(); ++vit)
        out << pp(*vit);
    out << " ]";
    return out.str();
}
Beispiel #16
0
/**
* Checks if plg2 is inside plg1
*/
bool is_inside(Polygon_2 plg1, Polygon_2 plg2) {
    bool ishole = true;
    for (std::vector<Point>::iterator v2 = plg2.vertices_begin();
            v2 != plg2.vertices_end();
            ++v2) {
        if(! check_inside(*v2, plg1, K())) {
            ishole = false;
            break; //stop checking
        }
    }
    return ishole;
}
Beispiel #17
0
int distance(const Point_2& p, const Point_2& q, const Polygon_2& P)
{
  typedef Polygon_2::Vertex_const_iterator Iter;
  typedef iterator_traits<Iter>::difference_type Diff;

  Iter pit = find(P.vertices_begin(), P.vertices_end(), p);
  Iter qit = find(P.vertices_begin(), P.vertices_end(), q);
  if (pit == P.vertices_end() || qit == P.vertices_end()) {
    return -1;
  }

  Diff pbeg = CGAL::iterator_distance(P.vertices_begin(), pit);
  Diff qbeg = CGAL::iterator_distance(P.vertices_begin(), qit);
  if (qbeg < pbeg) {
    std::swap(pit, qit);
    std::swap(pbeg, qbeg);
  }
  Diff pq = CGAL::iterator_distance(pit, qit);
  Diff qend = CGAL::iterator_distance(qit, P.vertices_end());
  
  return (int) min(pbeg+qend, pq);
}
Beispiel #18
0
void print_ser(std::ostream& out, const Polygon_2& polygon, const string& component)
{
    out << "<Contour name=\"" << component << "\" hidden=\"true\" closed=\"true\" simplified=\"true\" border=\"0 1 0\" fill=\"0 1 0\" mode=\"9\"" << endl;
    out << "points=\"";

    // insert points here
    Polygon_2::Vertex_const_iterator  vit;
    for (vit = polygon.vertices_begin(); vit != polygon.vertices_end(); ++vit) {
        out << "\t" << vit->x() << " " << vit->y() << "," << std::endl;
    }

    out << "\t\"/>" << endl;
}
void printCgalPoly(Polygon_2 poly)
{
    int i = 0;
    std::cout <<"Printing polygon: size=" << poly.size();
    for (Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi)
    {
        Point_2 v = *vi;
        geometry_msgs::Point32 pt;
        pt.x = v.x();
        pt.y = v.y();
        std::cout << i++ << " x=" <<pt.x << ", y="  << pt.y << std::endl;
    }
}
Beispiel #20
0
/**
\brief Prints a polygon in its WKT form (p1,p2,p3,....)

\note Does not add POLYGON text. It is used inside other printing functions
*/
void print_WKT_polygon_2(Polygon_2 plg) {


    std::cout << "(";
    std::vector<Point>::iterator v;
    for ( v = plg.vertices_begin();
            v != plg.vertices_end()-1;
            ++v) {
        std::cout << *v << ",";
    }
    v = plg.vertices_end()-1; //last one with no comma
    std::cout << *v << ")";

}
void rosPolyFromCgal(Polygon_2& input, geometry_msgs::Polygon& output)
{
    std::cout << "Converting to ROS polygon... " << std::endl;
    // Iterate through the points for a polygon
    for (Vertex_iterator vi = input.vertices_begin(); vi != input.vertices_end(); ++vi)
    {
        Point_2 v = *vi;
        geometry_msgs::Point32 pt;
        pt.x = v.x();
        pt.y = v.y();

        output.points.push_back(pt);
    }
}
Beispiel #22
0
int main()
{
  // build a random convex 20-gon p
  Polygon_2 p;
  CGAL::random_convex_set_2(20, std::back_inserter(p), Generator(1.0));
  std::cout << p << std::endl;

  // compute the minimal enclosing strip p_m of p
  Line_2 p_m[2];
  CGAL::min_strip_2(p.vertices_begin(), p.vertices_end(), p_m);
  std::cout << p_m[0] << "\n" << p_m[1] << std::endl;

  return 0;
}
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);
  
}
Beispiel #24
0
bool check_inside(Point pt, Polygon_2 pgn, K traits)
{
    //std::cout << "The point " << pt;
    switch(CGAL::bounded_side_2(pgn.vertices_begin(), pgn.vertices_end(), pt, traits)) {
    case CGAL::ON_BOUNDED_SIDE :
        //std::cout << " is inside the polygon.\n";
        return true;
    case CGAL::ON_BOUNDARY:
        //std::cout << " is on the polygon boundary.\n";
        return false;
    case CGAL::ON_UNBOUNDED_SIDE:
        //std::cout << " is outside the polygon.\n";
        return false;
    }
}
int main()
{
  // build a random convex 20-gon p
  Polygon_2 p;
  CGAL::random_convex_set_2(20, std::back_inserter(p), Generator(1.0));
  std::cout << p << std::endl;

  // compute the minimal enclosing parallelogram p_m of p
  Polygon_2 p_m;
  CGAL::min_parallelogram_2(
    p.vertices_begin(), p.vertices_end(), std::back_inserter(p_m));
  std::cout << p_m << std::endl;

  return 0;
}
Beispiel #26
0
void PreProcessor::process(double scale, double trans_x, double trans_y) {
	Transformation trafo_scale(CGAL::SCALING, scale);
	Transformation trafo_trans(CGAL::TRANSLATION, Vector_2(-trans_x, -trans_y));
	Transformation trafo = trafo_scale * trafo_trans;
	// GlobalOptions::getInstance().tree_trafo = trafo;
	cout << "Transforming: " << trafo << endl;
	auto it = tree->element_tree.begin();
	auto it_end = tree->element_tree.end();

	for(; it != it_end; ++it) {
		switch((*it)->get_type()) {
			case EL_POLYGON: {
				Polygon_2 * p = &(static_cast<PolygonElementPtr *>(*it)->element);
				for(auto poly_it = p->vertices_begin(); poly_it != p->vertices_end(); ++poly_it) {
					*poly_it = poly_it->transform(trafo);
				}			
			}
			break;
			case EL_FILLED_POLYGON: { // Todo transform holes!
				FilledPolygonElementPtr * fp = static_cast<FilledPolygonElementPtr *>(*it);
				Polygon_with_holes_2 scaled_pwh(transform(trafo, fp->element.outer_boundary()));
				for(auto hit = fp->element.holes_begin(); hit != fp->element.holes_end(); ++hit) {
					scaled_pwh.add_hole(transform(trafo, (*hit)));
				}
				cout << "Scaled PWH = " << scaled_pwh << endl;
				fp->element = scaled_pwh;
			}
			break;
			case EL_POLYLINE: {
				PolyLine_P * p = &(static_cast<PolyLineElementPtr *>(*it)->element);
				auto poly_it = p->begin();
				auto poly_end = p->end();
				for(; poly_it != poly_end; ++poly_it) {
					*poly_it = poly_it->transform(trafo);
				}
			}
			break;
		}
	}
	if(tree->startpoint_elem) {
		PolyLine_P * p = &(static_cast<PolyLineElementPtr *>(tree->startpoint_elem)->element);
		auto poly_it = p->begin();
		auto poly_end = p->end();
		for(; poly_it != poly_end; ++poly_it) {
			*poly_it = poly_it->transform(trafo);
		}
	}
}
int main() {

  int n = 10;
  int k = 5;

  // generate random convex polygon:
  Polygon_2 p;
  CGAL::random_convex_set_2(n, std::back_inserter(p), Generator(1));
  std::cout << "Generated Polygon:\n" << p << std::endl;

  // compute maximum perimeter incribed k-gon of p:
  Polygon_2 k_gon;
  CGAL::maximum_perimeter_inscribed_k_gon_2(
    p.vertices_begin(), p.vertices_end(), k, std::back_inserter(k_gon));
  std::cout << "Maximum perimeter " << k << "-gon:\n"
            << k_gon << std::endl;

  return 0;
}
Polygon_2 CollisionDetector::translate_polygon_to(const Polygon_2& poly, const Point_2& new_ref_pt) const
{
	m_translate_helper.resize(0);
	const Point_2 &ref = *poly.left_vertex();
	std::pair<double,double> diff(
	//Vector_2 diff(
		CGAL::to_double(ref.x().exact()) - CGAL::to_double(new_ref_pt.x().exact()), 
		CGAL::to_double(ref.y().exact()) - CGAL::to_double(new_ref_pt.y().exact())
	);

  	for (Polygon_2::Vertex_const_iterator it = poly.vertices_begin(), it_end = poly.vertices_end(); it != it_end; ++it)
  	{
		m_translate_helper.push_back( Point_2(CGAL::to_double(it->x()) + diff.first, CGAL::to_double(it->y()) + diff.second ) );
		//translated.push_back( (*it) + diff );
  	}



  	Polygon_2 new_poly(m_translate_helper.begin(),m_translate_helper.end());
  	return new_poly;
}
Beispiel #29
0
// This routine checks whether a poylgon can be inserted into a block such that the interior of the polygon does not at all overlap with used space
// in the block.  We COULD do this using boolean operations (E.g. is the intersection of the used block space and our polygon empty?) but we do NOT want
// to.  Why?  Time to do a boolean op is a function of BOTH polygons, and in a lot of cases the block will be HUGELY complex (imagine a giant forest expanse
// with lots of crap already inserted into it) and our test block will be TINY (a quad).  In this case, we get better performance by doing a piece-wise per-side
// test.  
// Side note: using the bulk locator totally violates this principle...we will probably need to replace it with a walk location strategy.
// So we use the zone utility to see what we'll hit as we go along our edges.  
bool	can_insert_into_block(
					Block_2&						block,
					const Polygon_2&				bounds)
{
	// Run a bulk location on the entire block...TBD: there may be blocks where sweeping is worse than marching.
	// Anyway, we get a bunch of pairs of the locate point and the actual part of the arrangement we hit.
	vector<pair<Point_2, CGAL::Object> >	pts;
	CGAL::locate(block, bounds.vertices_begin(), bounds.vertices_end(), back_inserter(pts));
	
	// Quick check: if ANY of our points are inside a non empty face, we are by definition hosed.
	// We can see this now just from the location data.
	Block_2::Face_const_handle ff;
	for(int n = 0; n < pts.size(); ++n)
	if(CGAL::assign(ff,pts[n].second))
	if(ff->data().usage != usage_Empty)
		return false;

	for(int n = 0; n < pts.size(); ++n)
	{
		// We are now going to go through each side and do a zone test.  This will check whether it is 
		// either running along a full area or crashing through it.
		int m = (n+1)%pts.size();
		check_block_visitor	v;
		v.cv = Block_2::X_monotone_curve_2(Segment_2(pts[n].first, pts[m].first));

		CGAL::Arrangement_zone_2<Block_2,check_block_visitor>	zone(block, &v);

		if(v.cv.is_directed_right())
			zone.init_with_hint(v.cv,pts[n].second);
		else
			zone.init_with_hint(v.cv,pts[m].second);

		zone.compute_zone();
		
		if(!v.ok)
			return false;		
	}
	return true;
}
vector<ofVec3f> ofApp::offsetCell(list<int> & crv, AnisoPoint2f & pt) {
	float scaling = 1000;
	ClipperOffset co;
	co.ArcTolerance = 1;
	Path P;
	Paths offsetP;
	float offset = ofClamp(offsetPercent / sqrt(pt.jacobian->determinant()), minThick*0.5, maxThick*0.5);

	if (doSmooth) {
		
		for (auto index : crv) {
			ofVec3f v = linesMesh.getVertex(index);
			IntPoint iPt(v.x * scaling, v.y * scaling);
			P.push_back(iPt);
		}
		co.AddPath(P, jtRound, etClosedPolygon);
		co.Execute(offsetP, -offset*scaling);
		if(offsetP.size() == 0) return vector<ofVec3f>();
		P.clear();
		ofVec2f center;
		for (auto & v : offsetP[0]) {
			//ofVec3f v = linesMesh.getVertex(index);
			Vector2f p(v.X, v.Y);
			p = (*pt.jacobian)*p;
			IntPoint iPt(p.coeff(0), p.coeff(1));
			P.push_back(iPt);
			center += ofVec2f(iPt.X, iPt.Y);
		}
		center /= crv.size();
		CleanPolygon(P);
		
		co.Clear();
		co.AddPath(P, jtRound, etClosedPolygon);
		float radius = 9e20;

		//get exact radius from straight skeleton
		Polygon_2 poly;
		for (auto & pt : P) {
			poly.push_back(Point_2(pt.X, pt.Y));
		}
		boost::shared_ptr<Ss> iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());
		radius = 0;
		for (Ss::Vertex_handle vh = iss->vertices_begin(); vh != iss->vertices_end(); vh++) {
			if (!vh->has_infinite_time()) {
				radius = max(radius, (float)vh->time());
			}
		}

		//estimate radius
		//for (auto & iPt : P) {
		//	radius = min(radius, (iPt.X - center.x)*(iPt.X - center.x) + (iPt.Y - center.y)*(iPt.Y - center.y));
		//}
		//radius = sqrt(radius);
		//co.Execute(offsetP, -radius);
		//int tries = 0;
		//while (offsetP.size() == 0 && tries < 50) {
		//	radius *= .95;
		//	co.Execute(offsetP, -radius);
		//	tries++;
		//}
		//cout << tries << endl;
		radius *= filletPercent;
		co.Execute(offsetP, -radius);
		//radius = min(radius,(radius - offset*scaling)*filletPercent + offset*scaling);
		
		//co.Execute(offsetP, -offset*scaling);
		vector<ofVec3f> offsetPts;
		if (offsetP.size() > 0) {
			//visual offset for etching
			co.Clear();
			CleanPolygons(offsetP);
			co.AddPaths(offsetP, jtRound, etClosedPolygon);
			co.Execute(offsetP, radius);
			CleanPolygons(offsetP);
			Path longestP;
			int pLen = 0;
			for (auto & oP : offsetP) {
				if (oP.size() > pLen) {
					pLen = oP.size();
					longestP = oP;
				}
			}
			Matrix2f inverse = pt.jacobian->inverse();
			if (doEtchOffset) {
				co.Clear();
				for (auto & lPt : longestP) {
					Vector2f anisoPt(lPt.X, lPt.Y);
					anisoPt = inverse*anisoPt;
					lPt.X = anisoPt[0];
					lPt.Y = anisoPt[1];
				}
				co.AddPath(longestP, jtRound, etClosedPolygon);
				co.Execute(offsetP, etchOffset*scaling);
				longestP = offsetP[0];
			}
			for (int i = 0; i < longestP.size(); i++) {
				//ofVec3f pt3D(oP[i].X / scaling, oP[i].Y/ scaling);
				Vector2f anisoPt(longestP[i].X / scaling, longestP[i].Y / scaling);
				if(!doEtchOffset)anisoPt = inverse*anisoPt;
				offsetPts.push_back(ofVec3f(anisoPt.coeff(0), anisoPt.coeff(1)));
			}
		}
		return offsetPts;
	}
	else {
		for (auto index : crv) {
			ofVec3f v = linesMesh.getVertex(index);
			IntPoint iPt(v.x * scaling, v.y * scaling);
			P.push_back(iPt);
		}
		CleanPolygon(P);
		//Paths simplerP;
		//SimplifyPolygon(P, simplerP);
		//CleanPolygons(simplerP);
		//P = simplerP[0];
		//CleanPolygon(P);
		//Polygon_2 poly;
		//for (auto & pt : P) {
		//	poly.push_back(Point_2(pt.X, pt.Y));
		//}
		//boost::shared_ptr<Ss> iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());
		//float radius = 0;
		//for (Ss::Vertex_handle vh = iss->vertices_begin(); vh != iss->vertices_end(); vh++) {
		//	if (!vh->has_infinite_time()) {
		//		radius = max(radius, (float)vh->time());
		//	}
		//}
		
		//Paths simplerP;
		//SimplifyPolygon(P, simplerP);
		//co.AddPaths(simplerP, jtRound, etClosedPolygon);
		//radius = ofClamp(radius*offsetPercent, minThick*0.5*scaling, maxThick*0.5*scaling);
		co.AddPath(P, jtRound, etClosedPolygon);
		co.Execute(offsetP, -offset*scaling);
		vector<ofVec3f> offsetPts;
		if (offsetP.size() > 0) {
			CleanPolygons(offsetP);
			if (doEtchOffset) {
				co.Clear();
				co.AddPaths(offsetP, jtRound, etClosedPolygon);
				co.Execute(offsetP, etchOffset*scaling);
			}
			else {
				co.Clear();
				co.AddPaths(offsetP, jtRound, etClosedPolygon);
				co.Execute(offsetP, 1);
			}
			Path longestP;
			int pLen = 0;
			for (auto & oP : offsetP) {
				if (oP.size() > pLen) {
					pLen = oP.size();
					longestP = oP;
				}
			}
			Path & oP = longestP;
			for (int i = 0; i < oP.size(); i++) {
				ofVec3f pt3D(oP[i].X / scaling, oP[i].Y/ scaling);
				offsetPts.push_back(pt3D);
			}
		}
		return offsetPts;
	}

}