//#ifndef NDEBUG //#define NFP_DEBUG //#endif #include "libnfpglue.hpp" #include "tools/libnfporb/libnfporb.hpp" namespace libnest2d { namespace { inline bool vsort(const libnfporb::point_t& v1, const libnfporb::point_t& v2) { using Coord = libnfporb::coord_t; Coord x1 = v1.x_, x2 = v2.x_, y1 = v1.y_, y2 = v2.y_; auto diff = y1 - y2; #ifdef LIBNFP_USE_RATIONAL long double diffv = diff.convert_to(); #else long double diffv = diff.val(); #endif if(std::abs(diffv) <= std::numeric_limits::epsilon()) return x1 < x2; return diff < 0; } TCoord getX(const libnfporb::point_t& p) { #ifdef LIBNFP_USE_RATIONAL return p.x_.convert_to>(); #else return static_cast>(std::round(p.x_.val())); #endif } TCoord getY(const libnfporb::point_t& p) { #ifdef LIBNFP_USE_RATIONAL return p.y_.convert_to>(); #else return static_cast>(std::round(p.y_.val())); #endif } libnfporb::point_t scale(const libnfporb::point_t& p, long double factor) { #ifdef LIBNFP_USE_RATIONAL auto px = p.x_.convert_to(); auto py = p.y_.convert_to(); #else long double px = p.x_.val(); long double py = p.y_.val(); #endif return libnfporb::point_t(px*factor, py*factor); } } PolygonImpl _nfp(const PolygonImpl &sh, const PolygonImpl &cother) { using Vertex = PointImpl; PolygonImpl ret; // try { libnfporb::polygon_t pstat, porb; boost::geometry::convert(sh, pstat); boost::geometry::convert(cother, porb); long double factor = 0.0000001;//libnfporb::NFP_EPSILON; long double refactor = 1.0/factor; for(auto& v : pstat.outer()) v = scale(v, factor); // std::string message; // boost::geometry::is_valid(pstat, message); // std::cout << message << std::endl; for(auto& h : pstat.inners()) for(auto& v : h) v = scale(v, factor); for(auto& v : porb.outer()) v = scale(v, factor); // message; // boost::geometry::is_valid(porb, message); // std::cout << message << std::endl; for(auto& h : porb.inners()) for(auto& v : h) v = scale(v, factor); // this can throw auto nfp = libnfporb::generateNFP(pstat, porb, true); auto &ct = ShapeLike::getContour(ret); ct.reserve(nfp.front().size()+1); for(auto v : nfp.front()) { v = scale(v, refactor); ct.emplace_back(getX(v), getY(v)); } ct.push_back(ct.front()); std::reverse(ct.begin(), ct.end()); auto &rholes = ShapeLike::holes(ret); for(size_t hidx = 1; hidx < nfp.size(); ++hidx) { if(nfp[hidx].size() >= 3) { rholes.push_back({}); auto& h = rholes.back(); h.reserve(nfp[hidx].size()+1); for(auto& v : nfp[hidx]) { v = scale(v, refactor); h.emplace_back(getX(v), getY(v)); } h.push_back(h.front()); std::reverse(h.begin(), h.end()); } } auto& cmp = vsort; std::sort(pstat.outer().begin(), pstat.outer().end(), cmp); std::sort(porb.outer().begin(), porb.outer().end(), cmp); // leftmost lower vertex of the stationary polygon auto& touch_sh = scale(pstat.outer().back(), refactor); // rightmost upper vertex of the orbiting polygon auto& touch_other = scale(porb.outer().front(), refactor); // Calculate the difference and move the orbiter to the touch position. auto dtouch = touch_sh - touch_other; auto _top_other = scale(porb.outer().back(), refactor) + dtouch; Vertex top_other(getX(_top_other), getY(_top_other)); // Get the righmost upper vertex of the nfp and move it to the RMU of // the orbiter because they should coincide. auto&& top_nfp = Nfp::rightmostUpVertex(ret); auto dnfp = top_other - top_nfp; std::for_each(ShapeLike::begin(ret), ShapeLike::end(ret), [&dnfp](Vertex& v) { v+= dnfp; } ); for(auto& h : ShapeLike::holes(ret)) std::for_each( h.begin(), h.end(), [&dnfp](Vertex& v) { v += dnfp; } ); // } catch(std::exception& e) { // std::cout << "Error: " << e.what() << "\nTrying with convex hull..." << std::endl; // auto ch_stat = ShapeLike::convexHull(sh); // auto ch_orb = ShapeLike::convexHull(cother); // ret = Nfp::nfpConvexOnly(ch_stat, ch_orb); // } return ret; } PolygonImpl Nfp::NfpImpl::operator()( const PolygonImpl &sh, const ClipperLib::PolygonImpl &cother) { return _nfp(sh, cother);//nfpConvexOnly(sh, cother); } PolygonImpl Nfp::NfpImpl::operator()( const PolygonImpl &sh, const ClipperLib::PolygonImpl &cother) { return _nfp(sh, cother); } PolygonImpl Nfp::NfpImpl::operator()( const PolygonImpl &sh, const ClipperLib::PolygonImpl &cother) { return _nfp(sh, cother); } PolygonImpl Nfp::NfpImpl::operator()( const PolygonImpl &sh, const ClipperLib::PolygonImpl &cother) { return _nfp(sh, cother); } PolygonImpl Nfp::NfpImpl::operator()( const PolygonImpl &sh, const ClipperLib::PolygonImpl &cother) { return _nfp(sh, cother); } }