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); } }
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; } }
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())); }
/** \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 << ")"; }
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; }
/* * 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 ); } }
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()); }
// 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(); }
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); }
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); }
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; }
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(); }
/** * 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; }
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); }
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; } }
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); } }
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); }
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; }
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; }
// 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; } }