From e1edb05bbbd95bf0f15d3540545d9bf1cf63356e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 6 Aug 2018 20:13:04 +0200 Subject: [PATCH] Better support for circular bed. --- xs/src/libnest2d/examples/main.cpp | 501 +----------------- .../libnest2d/libnest2d/geometry_traits.hpp | 2 +- .../libnest2d/libnest2d/placers/nfpplacer.hpp | 110 +++- xs/src/libnest2d/tests/test.cpp | 37 ++ xs/src/libslic3r/ModelArrange.hpp | 52 +- 5 files changed, 172 insertions(+), 530 deletions(-) diff --git a/xs/src/libnest2d/examples/main.cpp b/xs/src/libnest2d/examples/main.cpp index d6b2ccc34..02be465a8 100644 --- a/xs/src/libnest2d/examples/main.cpp +++ b/xs/src/libnest2d/examples/main.cpp @@ -50,492 +50,12 @@ void arrangeRectangles() { using namespace libnest2d; const int SCALE = 1000000; -// const int SCALE = 1; + std::vector rects = { - {80*SCALE, 80*SCALE}, - {60*SCALE, 90*SCALE}, - {70*SCALE, 30*SCALE}, - {80*SCALE, 60*SCALE}, - {60*SCALE, 60*SCALE}, - {60*SCALE, 40*SCALE}, - {40*SCALE, 40*SCALE}, - {10*SCALE, 10*SCALE}, - {10*SCALE, 10*SCALE}, - {10*SCALE, 10*SCALE}, - {10*SCALE, 10*SCALE}, - {10*SCALE, 10*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {5*SCALE, 5*SCALE}, - {20*SCALE, 20*SCALE} - }; - -// std::vector rects = { -// {20*SCALE, 10*SCALE}, -// {20*SCALE, 10*SCALE}, -// {20*SCALE, 20*SCALE}, -// }; - -// std::vector input { -// {{0, 0}, {0, 20*SCALE}, {10*SCALE, 0}, {0, 0}} -// }; - - std::vector crasher = - { - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-5000000, 8954050}, - {5000000, 8954050}, - {5000000, -45949}, - {4972609, -568549}, - {3500000, -8954050}, - {-3500000, -8954050}, - {-4972609, -568549}, - {-5000000, -45949}, - {-5000000, 8954050}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-9945219, -3065619}, - {-9781479, -2031780}, - {-9510560, -1020730}, - {-9135450, -43529}, - {-2099999, 14110899}, - {2099999, 14110899}, - {9135450, -43529}, - {9510560, -1020730}, - {9781479, -2031780}, - {9945219, -3065619}, - {10000000, -4110899}, - {9945219, -5156179}, - {9781479, -6190020}, - {9510560, -7201069}, - {9135450, -8178270}, - {8660249, -9110899}, - {8090169, -9988750}, - {7431449, -10802200}, - {6691309, -11542300}, - {5877850, -12201100}, - {5000000, -12771100}, - {4067369, -13246399}, - {3090169, -13621500}, - {2079119, -13892399}, - {1045279, -14056099}, - {0, -14110899}, - {-1045279, -14056099}, - {-2079119, -13892399}, - {-3090169, -13621500}, - {-4067369, -13246399}, - {-5000000, -12771100}, - {-5877850, -12201100}, - {-6691309, -11542300}, - {-7431449, -10802200}, - {-8090169, -9988750}, - {-8660249, -9110899}, - {-9135450, -8178270}, - {-9510560, -7201069}, - {-9781479, -6190020}, - {-9945219, -5156179}, - {-10000000, -4110899}, - {-9945219, -3065619}, - }, - { - {-18000000, -1000000}, - {-15000000, 22000000}, - {-11000000, 26000000}, - {11000000, 26000000}, - {15000000, 22000000}, - {18000000, -1000000}, - {18000000, -26000000}, - {-18000000, -26000000}, - {-18000000, -1000000}, - }, + {60*SCALE, 200*SCALE}, + {60*SCALE, 200*SCALE} }; - std::vector proba = { - { - Rectangle(100, 2) - }, - { - Rectangle(100, 2) - }, - { - Rectangle(100, 2) - }, - { - Rectangle(10, 10) - }, - }; - - proba[0].rotate(Pi/3); - proba[1].rotate(Pi-Pi/3); - -// std::vector input(25, Rectangle(70*SCALE, 10*SCALE)); std::vector input; input.insert(input.end(), prusaParts().begin(), prusaParts().end()); // input.insert(input.end(), prusaExParts().begin(), prusaExParts().end()); @@ -544,7 +64,7 @@ void arrangeRectangles() { // input.insert(input.end(), proba.begin(), proba.end()); // input.insert(input.end(), crasher.begin(), crasher.end()); - Box bin(250*SCALE, 210*SCALE); +// Box bin(250*SCALE, 210*SCALE); // PolygonImpl bin = { // { // {25*SCALE, 0}, @@ -560,9 +80,11 @@ void arrangeRectangles() { // {} // }; + _Circle bin({0, 0}, 125*SCALE); + auto min_obj_distance = static_cast(0*SCALE); - using Placer = strategies::_NofitPolyPlacer; + using Placer = strategies::_NofitPolyPlacer; using Packer = Arranger; Packer arrange(bin, min_obj_distance); @@ -571,9 +93,9 @@ void arrangeRectangles() { pconf.alignment = Placer::Config::Alignment::CENTER; pconf.starting_point = Placer::Config::Alignment::CENTER; pconf.rotations = {0.0/*, Pi/2.0, Pi, 3*Pi/2*/}; - pconf.accuracy = 0.5f; + pconf.accuracy = 1.0f; -// auto bincenter = ShapeLike::boundingBox(bin).center(); +// auto bincenter = ShapeLike::boundingBox(bin).center(); // pconf.object_function = [&bin, bincenter]( // Placer::Pile pile, const Item& item, // double /*area*/, double norm, double penality) { @@ -660,10 +182,7 @@ void arrangeRectangles() { // score = pl::distance(ibb.center(), bigbb.center()) / norm; // } -// // If it does not fit into the print bed we will beat it -// // with a large penality. If we would not do this, there would be only -// // one big pile that doesn't care whether it fits onto the print bed. -// if(!NfpPlacer::wouldFit(fullbb, bin)) score = 2*penality - score; +// if(!Placer::wouldFit(fullbb, bin)) score += norm; // return score; // }; diff --git a/xs/src/libnest2d/libnest2d/geometry_traits.hpp b/xs/src/libnest2d/libnest2d/geometry_traits.hpp index 058c47cd4..830643130 100644 --- a/xs/src/libnest2d/libnest2d/geometry_traits.hpp +++ b/xs/src/libnest2d/libnest2d/geometry_traits.hpp @@ -109,7 +109,7 @@ public: inline void radius(double r) { radius_ = r; } inline double area() const BP2D_NOEXCEPT { - return 2.0*Pi*radius_; + return 2.0*Pi*radius_*radius_; } }; diff --git a/xs/src/libnest2d/libnest2d/placers/nfpplacer.hpp b/xs/src/libnest2d/libnest2d/placers/nfpplacer.hpp index a3429bf48..c506a5d5a 100644 --- a/xs/src/libnest2d/libnest2d/placers/nfpplacer.hpp +++ b/xs/src/libnest2d/libnest2d/placers/nfpplacer.hpp @@ -1,16 +1,19 @@ #ifndef NOFITPOLY_HPP #define NOFITPOLY_HPP +#include +#include + #ifndef NDEBUG #include #endif #include "placer_boilerplate.hpp" #include "../geometry_traits_nfp.hpp" #include "libnest2d/optimizer.hpp" -#include #include "tools/svgtools.hpp" + namespace libnest2d { namespace strategies { template @@ -161,12 +164,11 @@ template class EdgeCache { } size_t stride(const size_t N) const { - using std::ceil; using std::round; using std::pow; return static_cast( - std::round(N/std::pow(N, std::pow(accuracy_, 1.0/3.0))) + round(N/pow(N, pow(accuracy_, 1.0/3.0))) ); } @@ -177,6 +179,7 @@ template class EdgeCache { const auto S = stride(N); contour_.corners.reserve(N / S + 1); + contour_.corners.emplace_back(0.0); auto N_1 = N-1; contour_.corners.emplace_back(0.0); for(size_t i = 0; i < N_1; i += S) { @@ -190,8 +193,8 @@ template class EdgeCache { if(!hc.corners.empty()) return; const auto N = hc.distances.size(); - const auto S = stride(N); auto N_1 = N-1; + const auto S = stride(N); hc.corners.reserve(N / S + 1); hc.corners.emplace_back(0.0); for(size_t i = 0; i < N_1; i += S) { @@ -339,7 +342,7 @@ Nfp::Shapes nfp( const Container& polygons, Nfp::Shapes nfps; - //int pi = 0; +// int pi = 0; for(Item& sh : polygons) { auto subnfp_r = Nfp::noFitPolygon( sh.transformedShape(), trsh.transformedShape()); @@ -441,6 +444,63 @@ Nfp::Shapes nfp( const Container& polygons, // return nfps; } +template +_Circle> minimizeCircle(const RawShape& sh) { + using sl = ShapeLike; using pl = PointLike; + using Point = TPoint; + using Coord = TCoord; + + auto bb = sl::boundingBox(sh); + auto capprx = bb.center(); + auto rapprx = pl::distance(bb.minCorner(), bb.maxCorner()); + + auto& ctr = sl::getContour(sh); + + opt::StopCriteria stopcr; + stopcr.max_iterations = 100; + stopcr.relative_score_difference = 1e-3; + opt::TOptimizer solver(stopcr); + + std::vector dists(ctr.size(), 0); + + auto result = solver.optimize_min( + [capprx, rapprx, &ctr, &dists](double xf, double yf) { + auto xt = Coord( std::round(getX(capprx) + rapprx*xf) ); + auto yt = Coord( std::round(getY(capprx) + rapprx*yf) ); + + Point centr(xt, yt); + + unsigned i = 0; + for(auto v : ctr) { + dists[i++] = pl::distance(v, centr); + } + + auto mit = std::max_element(dists.begin(), dists.end()); + + assert(mit != dists.end()); + + return *mit; + }, + opt::initvals(0.0, 0.0), + opt::bound(-1.0, 1.0), opt::bound(-1.0, 1.0) + ); + + double oxf = std::get<0>(result.optimum); + double oyf = std::get<1>(result.optimum); + auto xt = Coord( std::round(getX(capprx) + rapprx*oxf) ); + auto yt = Coord( std::round(getY(capprx) + rapprx*oyf) ); + + Point cc(xt, yt); + auto r = result.score; + + return {cc, r}; +} + +template +_Circle> boundingCircle(const RawShape& sh) { + return minimizeCircle(sh); +} + template>> class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer, RawShape, TBin, NfpPConfig> { @@ -512,11 +572,7 @@ public: bool static inline wouldFit(const RawShape& chull, const _Circle& bin) { - auto bb = sl::boundingBox(chull); - auto d = bin.center() - bb.center(); - auto chullcpy = chull; - sl::translate(chullcpy, d); - return sl::isInside(chullcpy, bin); + return boundingCircle(chull).radius() < bin.radius(); } PackResult trypack(Item& item) { @@ -574,8 +630,9 @@ public: auto getNfpPoint = [&ecache](const Optimum& opt) { - return opt.hidx < 0? ecache[opt.nfpidx].coords(opt.relpos) : + auto ret = opt.hidx < 0? ecache[opt.nfpidx].coords(opt.relpos) : ecache[opt.nfpidx].coords(opt.hidx, opt.relpos); + return ret; }; Nfp::Shapes pile; @@ -595,7 +652,7 @@ public: [this, &merged_pile]( Nfp::Shapes& /*pile*/, const Item& item, - double occupied_area, + double occupied_area, double norm, double /*penality*/) { @@ -751,14 +808,37 @@ public: } inline void clearItems() { + finalAlign(bin_); + Base::clearItems(); + } + +private: + + inline void finalAlign(const RawShape& pbin) { + auto bbin = sl::boundingBox(pbin); + finalAlign(bbin); + } + + inline void finalAlign(_Circle> cbin) { + if(items_.empty()) return; + Nfp::Shapes m; m.reserve(items_.size()); + for(Item& item : items_) m.emplace_back(item.transformedShape()); + auto c = boundingCircle(sl::convexHull(m)); + + auto d = cbin.center() - c.center(); + for(Item& item : items_) item.translate(d); + } + + inline void finalAlign(Box bbin) { + Nfp::Shapes m; + m.reserve(items_.size()); for(Item& item : items_) m.emplace_back(item.transformedShape()); auto&& bb = sl::boundingBox(m); Vertex ci, cb; - auto bbin = sl::boundingBox(bin_); switch(config_.alignment) { case Config::Alignment::CENTER: { @@ -790,12 +870,8 @@ public: auto d = cb - ci; for(Item& item : items_) item.translate(d); - - Base::clearItems(); } -private: - void setInitialPosition(Item& item) { Box&& bb = item.boundingBox(); Vertex ci, cb; diff --git a/xs/src/libnest2d/tests/test.cpp b/xs/src/libnest2d/tests/test.cpp index 39315ff1a..1e030c056 100644 --- a/xs/src/libnest2d/tests/test.cpp +++ b/xs/src/libnest2d/tests/test.cpp @@ -99,6 +99,43 @@ TEST(BasicFunctionality, creationAndDestruction) } +TEST(GeometryAlgorithms, boundingCircle) { + using namespace libnest2d; + using strategies::boundingCircle; + + PolygonImpl p = {{{0, 10}, {10, 0}, {0, -10}, {0, 10}}, {}}; + _Circle c = boundingCircle(p); + + ASSERT_EQ(c.center().X, 0); + ASSERT_EQ(c.center().Y, 0); + ASSERT_DOUBLE_EQ(c.radius(), 10); + + ShapeLike::translate(p, PointImpl{10, 10}); + c = boundingCircle(p); + + ASSERT_EQ(c.center().X, 10); + ASSERT_EQ(c.center().Y, 10); + ASSERT_DOUBLE_EQ(c.radius(), 10); + + auto parts = prusaParts(); + + int i = 0; + for(auto& part : parts) { + c = boundingCircle(part.transformedShape()); + if(std::isnan(c.radius())) std::cout << "fail: radius is nan" << std::endl; + + else for(auto v : ShapeLike::getContour(part.transformedShape()) ) { + auto d = PointLike::distance(v, c.center()); + if(d > c.radius() ) { + auto e = std::abs( 1.0 - d/c.radius()); + ASSERT_LE(e, 1e-3); + } + } + i++; + } + +} + TEST(GeometryAlgorithms, Distance) { using namespace libnest2d; diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp index 53b99b781..57a169205 100644 --- a/xs/src/libslic3r/ModelArrange.hpp +++ b/xs/src/libslic3r/ModelArrange.hpp @@ -102,9 +102,9 @@ using SpatIndex = bgi::rtree< SpatElement, bgi::rstar<16, 4> >; std::tuple objfunc(const PointImpl& bincenter, - double /*bin_area*/, + double bin_area, ShapeLike::Shapes& pile, // The currently arranged pile - double /*pile_area*/, + double pile_area, const Item &item, double norm, // A norming factor for physical dimensions std::vector& areacache, // pile item areas will be cached @@ -115,12 +115,16 @@ objfunc(const PointImpl& bincenter, using pl = PointLike; using sl = ShapeLike; - static const double BIG_ITEM_TRESHOLD = 0.2; + static const double BIG_ITEM_TRESHOLD = 0.04; static const double ROUNDNESS_RATIO = 0.5; static const double DENSITY_RATIO = 1.0 - ROUNDNESS_RATIO; // We will treat big items (compared to the print bed) differently - auto normarea = [norm](double area) { return std::sqrt(area)/norm; }; + + auto isBig = [&areacache, bin_area](double a) { + bool t = areacache.empty() ? true : a > 0.5*areacache.front(); + return a/bin_area > BIG_ITEM_TRESHOLD || t; + }; // If a new bin has been created: if(pile.size() < areacache.size()) { @@ -133,7 +137,7 @@ objfunc(const PointImpl& bincenter, for(auto& p : pile) { if(idx == areacache.size()) { areacache.emplace_back(sl::area(p)); - if(normarea(areacache[idx]) > BIG_ITEM_TRESHOLD) + if(isBig(areacache[idx])) spatindex.insert({sl::boundingBox(p), idx}); } @@ -157,14 +161,10 @@ objfunc(const PointImpl& bincenter, boost::geometry::convert(boostbb, bigbb); } - // The size indicator of the candidate item. This is not the area, - // but almost... - double item_normarea = normarea(item.area()); - // Will hold the resulting score double score = 0; - if(item_normarea > BIG_ITEM_TRESHOLD) { + if(isBig(item.area())) { // This branch is for the bigger items.. // Here we will use the closest point of the item bounding box to // the already arranged pile. So not the bb center nor the a choosen @@ -223,10 +223,9 @@ objfunc(const PointImpl& bincenter, // The final mix of the score is the balance between the distance // from the full pile center, the pack density and the // alignment with the neigbours - auto C = 0.33; - score = C * dist + C * density + C * alignment_score; + score = 0.4 * dist + 0.4 * density + 0.2 * alignment_score; - } else if( item_normarea < BIG_ITEM_TRESHOLD && spatindex.empty()) { + } else if( !isBig(item.area()) && spatindex.empty()) { // If there are no big items, only small, we should consider the // density here as well to not get silly results auto bindist = pl::distance(ibb.center(), bincenter) / norm; @@ -349,17 +348,26 @@ public: auto result = objfunc(bin.center(), bin_area_, pile, pile_area, item, norm, areacache_, rtree_); double score = std::get<0>(result); - - // Circle fitting detection is very rough at the moment but - // we still need something that tells how badly the arrangement - // misses the print bed. auto& fullbb = std::get<1>(result); - auto bbr = 0.5*PointLike::distance(fullbb.minCorner(), - fullbb.maxCorner()); - auto diff = bbr - bin.radius(); - if(diff > 0) score += std::pow(diff, 2) / norm; + auto d = PointLike::distance(fullbb.minCorner(), + fullbb.maxCorner()); + auto diff = d - 2*bin.radius(); + if(diff > 0) { + if( item.area() > 0.01*bin_area_ && item.vertexCount() < 20) { + pile.emplace_back(item.transformedShape()); + auto chull = ShapeLike::convexHull(pile); + pile.pop_back(); + + auto C = strategies::boundingCircle(chull); + auto rdiff = C.radius() - bin.radius(); + + if(rdiff > 0) { + score += std::pow(rdiff, 3) / norm; + } + } + } return score; }; @@ -695,6 +703,8 @@ bool arrange(Model &model, coordf_t min_obj_distance, } }; + if(result.empty()) return false; + if(first_bin_only) { applyResult(result.front(), 0, shapemap); } else {