From 62a2fadeb8f419d4646b73beaf52f1725f95490e Mon Sep 17 00:00:00 2001 From: manch1n Date: Wed, 29 Mar 2023 09:43:17 +0800 Subject: [PATCH] ENH: make arrangement align better Jira: STUDIO-2584, STUDIO-2507 Change-Id: I1987103e46f5ecb84395b5885954679ffe105c60 (cherry picked from commit 90df278408b79ad5b8d4ceaf90fe483cd8f5a48c) --- .../include/libnest2d/placers/nfpplacer.hpp | 74 ++++++++++++++++--- src/libslic3r/Arrange.cpp | 4 +- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 08afd130b..56aa3fdd8 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -602,6 +602,21 @@ private: return nfp::subtract({innerNfp}, nfps); } + Shapes calcnfp(const RawShape &sliding, const Shapes &stationarys, const Box &bed, Lvl) + { + using namespace nfp; + + Shapes nfps(stationarys.size()); + Item slidingItem(sliding); + __parallel::enumerate(stationarys.begin(), stationarys.end(), [&nfps, sliding, &slidingItem](const RawShape &stationary, size_t n) { + auto subnfp_r = noFitPolygon(stationary, sliding); + correctNfpPosition(subnfp_r, stationary, slidingItem); + nfps[n] = subnfp_r.first; + }); + + RawShape innerNfp = nfpInnerRectBed(bed, sliding).first; + return nfp::subtract({innerNfp}, nfps); + } template Shapes calcnfp(const Item &/*trsh*/, Level) @@ -702,18 +717,31 @@ private: }; } - if(items_.empty()) { + bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; }); + + // item won't overlap with virtual objects if it's inside or touches NFP + auto overlapWithVirtObject = [&]() -> double { + if (items_.empty()) return 0; + nfps = calcnfp(item, binbb, Lvl()); + auto v = item.referenceVertex(); + for (const RawShape &nfp : nfps) { + if (sl::isInside(v, nfp) || sl::touches(v, nfp)) { return 0; } + } + return 1; + }; + + if (first_object) { setInitialPosition(item); auto best_tr = item.translation(); auto best_rot = item.rotation(); - best_overfit = overfit(item.transformedShape(), bin_); + best_overfit = overfit(item.transformedShape(), bin_) + overlapWithVirtObject(); for(auto rot : config_.rotations) { item.translation(initial_tr); item.rotation(initial_rot + rot); setInitialPosition(item); double of = 0.; - if ((of = overfit(item.transformedShape(), bin_)) < best_overfit) { + if ((of = overfit(item.transformedShape(), bin_)) + overlapWithVirtObject() < best_overfit) { best_overfit = of; best_tr = item.translation(); best_rot = item.rotation(); @@ -725,7 +753,8 @@ private: global_score = 0.2; item.rotation(best_rot); item.translation(best_tr); - } else { + } + if (can_pack == false) { Pile merged_pile = merged_pile_; @@ -1086,13 +1115,33 @@ private: auto d = cb - ci; - // BBS TODO we assume the exclude region contains bottom left corner. If not, change the code below - if (!config_.m_excluded_regions.empty()) { // do not move to left to much to avoid clash with excluded regions - if (d.x() < 0) { - d.x() = 0;// std::max(long(d.x()), long(bbin.maxCorner().x() - bb.maxCorner().x())); + // BBS make sure the item won't clash with excluded regions + if(1) + { + std::vector objs,excludes; + for (const Item &item : items_) { + if (item.isFixed()) continue; + objs.push_back(item.transformedShape()); } - if (d.y() < 0) { - d.y() = 0;// std::max(long(d.y()), long(bbin.maxCorner().y() - bb.maxCorner().y())); + RawShape objs_convex_hull = sl::convexHull(objs); + if (objs.size() != 0) { + for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); } + for (const Item &item : items_) { + if (item.isFixed()) { excludes.push_back(item.transformedShape()); } + } + Box binbb = sl::boundingBox(bin_); + auto allowShifts = calcnfp(objs_convex_hull, excludes, binbb, Lvl()); + int maxAllowShiftX = 0; + int maxAllowShiftY = 0; + for (const auto &shiftShape : allowShifts) { + auto shiftBox = sl::boundingBox(shiftShape); // assume that the exclude region is box so that the nfp is box. + maxAllowShiftX = shiftBox.width(); + maxAllowShiftY = shiftBox.height(); + } + int finalShiftX = std::min(std::abs(maxAllowShiftX), std::abs(d.x())); + int finalShiftY = std::min(std::abs(maxAllowShiftY), std::abs(d.y())); + d.x() = d.x() > 0 ? finalShiftX : -finalShiftX; + d.y() = d.y() > 0 ? finalShiftY : -finalShiftY; } } for(Item& item : items_) @@ -1104,7 +1153,10 @@ private: Box bb = item.boundingBox(); Vertex ci, cb; - auto bbin = sl::boundingBox(bin_); + Box bbin = sl::boundingBox(bin_); + Vertex shrink(10, 10); + bbin.maxCorner() -= shrink; + bbin.minCorner() += shrink; switch(config_.starting_point) { case Config::Alignment::CENTER: { diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 22e9147b6..ca462269b 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -85,7 +85,7 @@ const double BIG_ITEM_TRESHOLD = 0.02; template void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { - if (params.is_seq_print || params.excluded_regions.empty()==false) { + if (params.is_seq_print) { // Align the arranged pile into the center of the bin pcfg.alignment = PConf::Alignment::CENTER; // Start placing the items from the center of the print bed @@ -95,7 +95,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { // Align the arranged pile into the center of the bin pcfg.alignment = PConf::Alignment::CENTER; // Start placing the items from the center of the print bed - pcfg.starting_point = PConf::Alignment::CENTER; + pcfg.starting_point = PConf::Alignment::TOP_RIGHT; } // Try 4 angles (45 degree step) and find the one with min cost