diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 97abadba8..0217cf5d2 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -4422,6 +4422,10 @@ int CLI::run(int argc, char **argv) oriented_or_arranged |= need_arrange; BOOST_LOG_TRIVIAL(info) << boost::format("before arrange, need_arrange=%1%, duplicate_count %2%, filament_color_changed %3%")%need_arrange %duplicate_count %filament_color_changed; + // if (!assemble_plate_info_list.empty() || need_arrange) + BOOST_LOG_TRIVIAL(debug) << "filament_count: " << filament_count; + Model::setExtruderParams(m_print_config, filament_count); + if (need_arrange || filament_color_changed) { for (int index = 0; index < partplate_list.get_plate_count(); index ++) @@ -4589,7 +4593,7 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "Arrange full params: " << arrange_cfg.to_json(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % selected.size(); for (auto item : selected) - BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx + BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_id_filament_types.begin()->first << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); for (auto item : unselected) @@ -5001,12 +5005,9 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose(); BOOST_LOG_TRIVIAL(info)<< "Arrange full params: "<< arrange_cfg.to_json(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size(); - for (auto item : selected) - BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx - << ", trans: " << item.translation.transpose(); + for (auto item : selected) BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); - for (auto item : unselected) - BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); + for (auto item : unselected) BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); } arrange_cfg.progressind= [](unsigned st, std::string str = "") { //boost::nowide::cout << "st=" << st << ", " << str << std::endl; diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp index a4767c7f7..f9e32b25d 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp @@ -656,7 +656,7 @@ inline std::string toString(const S& /*sh*/) } template -inline std::string serialize(const S& /*sh*/, double /*scale*/=1, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) +inline std::string serialize(const S & /*sh*/, const std::string &name = "", double /*scale*/ = 1, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) { static_assert(always_false::value, "shapelike::serialize() unimplemented!"); diff --git a/src/libnest2d/include/libnest2d/nester.hpp b/src/libnest2d/include/libnest2d/nester.hpp index 68141c9b4..b35e416e7 100644 --- a/src/libnest2d/include/libnest2d/nester.hpp +++ b/src/libnest2d/include/libnest2d/nester.hpp @@ -75,8 +75,7 @@ class _Item { public: int itemid_{ 0 }; - std::vector extrude_ids; - std::vector filament_types{}; /// filament type for different material judge + std::map extrude_id_filament_types; // extrude id to filament type int filament_temp_type = -1; // -1 means unset. otherwise should be one of FilamentTempType ie {0,1,2} double height{ 0 }; double print_temp{ 0 }; @@ -86,7 +85,8 @@ public: //BBS: virtual object to mark unprintable region on heatbed bool is_virt_object{ false }; bool is_wipe_tower{ false }; - bool has_tried_with_excluded{ false }; + bool is_extrusion_cali_object{ false }; + bool has_tried_without_extrusion_cali_obj{ false }; std::vector allowed_rotations{0.}; /// The type of the shape which was handed over as the template argument. diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index bf333909e..c95aa2bb2 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -18,8 +18,8 @@ #include "placer_boilerplate.hpp" // temporary -//#include "../tools/svgtools.hpp" -//#include // setprecision +#include "../tools/svgtools.hpp" +#include // setprecision #include @@ -690,6 +690,18 @@ private: using Edges = EdgeCache; + // item won't overlap with virtual objects if it's inside or touches NFP + // @return 1 if current item overlaps with virtual objects, 0 otherwise + bool overlapWithVirtObject(const Item& item, const Box& binbb){ + if (items_.empty()) return 0; + Shapes nfps = calcnfp(item, binbb, Lvl()); + auto v = item.referenceVertex(); + for (const RawShape &nfp : nfps) { + if (sl::isInside(v, nfp) || sl::touches(v, nfp)) { return false; } + } + return true; + }; + template> PackResult _trypack(Item& item, const Range& remaining = Range()) { @@ -757,19 +769,13 @@ private: }; } - bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; }); + for (auto &it : items_) { + config_.progressFunc((boost::format("_trypack: plate: %4%, existing object: %1%, pos: (%2%, %3%)") % it.get().name % unscale_(it.get().translation()[0]) % + unscale_(it.get().translation()[1]) % plateID()) + .str()); + } - // item won't overlap with virtual objects if it's inside or touches NFP - // @return 1 if current item overlaps with virtual objects, 0 otherwise - 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; - }; + bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; }); if (first_object) { setInitialPosition(item); @@ -780,21 +786,23 @@ private: // try normal inflation first, then 0 inflation if not fit. See STUDIO-5566. // Note for by-object printing, bed is expanded by -config_.bed_shrink.x(). Coord inflation_back = item.inflation(); - Coord inflations[2]={inflation_back, std::abs(config_.bed_shrink.x())}; + Coord inflations[2]={inflation_back, 0}; for (size_t i = 0; i < 2; i++) { item.inflation(inflations[i]); for (auto rot : item.allowed_rotations) { item.translation(initial_tr); item.rotation(initial_rot + rot); setInitialPosition(item); - double of = overfit(item.transformedShape(), bin_); - if (of + overlapWithVirtObject() < best_overfit) { - best_overfit = of; - best_tr = item.translation(); - best_rot = item.rotation(); - if (best_overfit <= 0) { - config_.progressFunc("First object can fit with rot="+std::to_string(rot)); - break; + if (!overlapWithVirtObject(item, binbb)) { + double of = overfit(item.transformedShape(), bin_); + if (of < best_overfit) { + best_overfit = of; + best_tr = item.translation(); + best_rot = item.rotation(); + if (best_overfit <= 0) { + config_.progressFunc("First object " + item.name + " can fit with rot=" + std::to_string(rot)); + break; + } } } } @@ -1005,41 +1013,7 @@ private: item.rotation(final_rot); } -#ifdef SVGTOOLS_HPP - if (config_.save_svg) { - svg::SVGWriter svgwriter; - Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside - svgwriter.setSize(binbb2); - svgwriter.conf_.x0 = binbb.width(); - svgwriter.conf_.y0 = -binbb.height() / 2; // origin is top left corner - svgwriter.add_comment("bed"); - svgwriter.writeShape(box2RawShape(binbb), "none", "black"); - svgwriter.add_comment("nfps"); - for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "none", "blue"); - for (int i = 0; i < items_.size(); i++) { - svgwriter.add_comment(items_[i].get().name); - svgwriter.writeItem(items_[i], "none", "black"); - } - svgwriter.add_comment("merged_pile_"); - for (int i = 0; i < merged_pile_.size(); i++) svgwriter.writeShape(merged_pile_[i], "none", "yellow"); - svgwriter.add_comment("current item"); - svgwriter.writeItem(item, "red", "red", 2); - - std::stringstream ss; - ss.setf(std::ios::fixed | std::ios::showpoint); - ss.precision(1); - ss << "t=" << round(item.translation().x() / 1e6) << "," - << round(item.translation().y() / 1e6) - //<< "-rot=" << round(item.rotation().toDegrees()) - << "-sco=" << round(global_score); - svgwriter.draw_text(20, 20, ss.str(), "blue", 20); - ss.str(""); - ss << "items.size=" << items_.size() << "-merged_pile.size=" << merged_pile_.size(); - svgwriter.draw_text(20, 40, ss.str(), "blue", 20); - svgwriter.save(boost::filesystem::path("C:/Users/arthur.tang/AppData/Roaming/BambuStudioInternal/SVG") / - ("nfpplacer_" + std::to_string(plate_id) + "_" + ss.str() + "_" + item.name + ".svg")); - } -#endif + if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack); if(can_pack) { ret = PackResult(item); @@ -1068,26 +1042,18 @@ private: auto binbb = sl::boundingBox(bin_); - for (auto &it : items_) { config_.progressFunc("existing object: " + it.get().name); } + for (auto &it : items_) { + config_.progressFunc((boost::format("_trypack_with_original_pos: plate: %4%, existing object: %1%, pos: (%2%, %3%)") % it.get().name % unscale_(it.get().translation()[0]) % + unscale_(it.get().translation()[1]) % plateID()) + .str()); + } - // item won't overlap with virtual objects if it's inside or touches NFP - // @return 1 if current item overlaps with virtual objects, 0 otherwise - 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; - }; - { for (auto rot : item.allowed_rotations) { item.translation(initial_tr); item.rotation(initial_rot + rot); - if (0==overlapWithVirtObject()) { + if (!overlapWithVirtObject(item, binbb)) { can_pack = true; final_tr = initial_tr; final_rot = initial_rot + rot; @@ -1100,46 +1066,13 @@ private: item.rotation(final_rot); } -#ifdef SVGTOOLS_HPP - if (config_.save_svg) { - svg::SVGWriter svgwriter; - Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside - svgwriter.setSize(binbb2); - svgwriter.conf_.x0 = binbb.width(); - svgwriter.conf_.y0 = -binbb.height() / 2; // origin is top left corner - svgwriter.add_comment("bed"); - svgwriter.writeShape(box2RawShape(binbb), "none", "black"); - svgwriter.add_comment("nfps"); - for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "none", "blue"); - for (int i = 0; i < items_.size(); i++) { - svgwriter.add_comment(items_[i].get().name); - svgwriter.writeItem(items_[i], "none", "black"); - } - svgwriter.add_comment("merged_pile_"); - for (int i = 0; i < merged_pile_.size(); i++) svgwriter.writeShape(merged_pile_[i], "none", "yellow"); - svgwriter.add_comment("current item"); - svgwriter.writeItem(item, "red", "red", 2); - - std::stringstream ss; - ss.setf(std::ios::fixed | std::ios::showpoint); - ss.precision(1); - ss << "t=" << round(item.translation().x() / 1e6) << "," - << round(item.translation().y() / 1e6) - //<< "-rot=" << round(item.rotation().toDegrees()) - << "-sco=" << round(global_score); - svgwriter.draw_text(20, 20, ss.str(), "blue", 20); - ss.str(""); - ss << "items.size=" << items_.size() << "-merged_pile.size=" << merged_pile_.size(); - svgwriter.draw_text(20, 40, ss.str(), "blue", 20); - svgwriter.save(boost::filesystem::path("C:/Users/arthur.tang/AppData/Roaming/BambuStudioInternal/SVG") / - ("nfpplacer_" + std::to_string(plate_id) + "_" + ss.str() + "_" + item.name + ".svg")); - } -#endif + if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack); if (can_pack) { ret = PackResult(item); ret.score_ = global_score; // merged_pile_ = nfp::merge(merged_pile_, item.transformedShape()); + config_.progressFunc((boost::format("_trypack_with_original_pos: item %1% can pack") % item.name).str()); } else { ret = PackResult(best_overfit); } @@ -1147,6 +1080,33 @@ private: return ret; } + void saveSVG(Box &binbb, Shapes &nfps, Item &item, double global_score, bool can_pack) + { + svg::SVGWriter svgwriter; + Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside + svgwriter.setSize(binbb2); + svgwriter.conf_.x0 = binbb.width(); + svgwriter.conf_.y0 = -binbb.height() / 2; // origin is top left corner + svgwriter.writeShape(box2RawShape(binbb), "bed", "none", "black"); + for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "nfp_" + std::to_string(i), "none", "blue", 0.2); + for (int i = 0; i < items_.size(); i++) { svgwriter.writeItem(items_[i], items_[i].get().name, "none", "black", 0.2); } + for (int i = 0; i < merged_pile_.size(); i++) svgwriter.writeShape(merged_pile_[i], "merged_pile_" + std::to_string(i), "none", "yellow", 0.2); + svgwriter.writeItem(item, item.name, "red", "red", 0.3); + + std::stringstream ss; + ss.setf(std::ios::fixed | std::ios::showpoint); + ss.precision(1); + ss << "t=" << round(item.translation().x() / 1e6) << "," + << round(item.translation().y() / 1e6) + //<< "-rot=" << round(item.rotation().toDegrees()) + << "-sco=" << round(global_score); + svgwriter.draw_text(20, 20, ss.str(), "blue", 10); + ss.str(""); + ss << "items.size=" << items_.size() << "-merged_pile.size=" << merged_pile_.size(); + svgwriter.draw_text(20, 40, ss.str(), "blue", 10); + svgwriter.save(boost::filesystem::path("SVG") / ("plate_" + std::to_string(plate_id) + "_" + ss.str() + "_" + item.name + "_canPack=" + std::to_string(can_pack) + ".svg")); + } + RawShape box2RawShape(Box& bbin) { RawShape binrsh; @@ -1260,17 +1220,7 @@ private: auto d = cb - ci; // BBS make sure the item won't clash with excluded regions - // do we have wipe tower after arranging? size_t n_objs = 0; - std::set extruders; - for (const Item& item : items_) { - if (!item.is_virt_object) { - extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); - n_objs++; - } - } - bool need_wipe_tower = extruders.size() > 1; - std::vector objs,excludes; for (Item &item : items_) { if (item.isFixed()) { diff --git a/src/libnest2d/include/libnest2d/selections/firstfit.hpp b/src/libnest2d/include/libnest2d/selections/firstfit.hpp index 532419e07..9ce68e7ee 100644 --- a/src/libnest2d/include/libnest2d/selections/firstfit.hpp +++ b/src/libnest2d/include/libnest2d/selections/firstfit.hpp @@ -41,7 +41,7 @@ public: std::vector placers; placers.reserve(last-first); - + typename Base::PackGroup fixed_bins; std::for_each(first, last, [this, &fixed_bins](Item& itm) { if (itm.isFixed()) { @@ -67,7 +67,7 @@ public: std::for_each(first, last, [this,&svgwriter](Item &itm) { svgwriter.writeShape(itm, "none", "blue"); }); svgwriter.save(boost::filesystem::path("SVG") / "all_items.svg"); #endif - + std::function sortfunc; if (pconfig.sortfunc) sortfunc = pconfig.sortfunc; @@ -93,6 +93,21 @@ public: if (this->unfitindicator_) this->unfitindicator_(ss.str()); } + // debug: write down fixed items + for (size_t i = 0; i < fixed_bins.size(); i++) { + if (fixed_bins[i].empty()) + continue; + std::stringstream ss; + ss << "fixed bin " << i << ": "; + for (auto it = fixed_bins[i].begin(); it != fixed_bins[i].end(); ++it) { + ss << it->get().name << ", p=" << it->get().priority() << ", bed_temp=" << it->get().bed_temp << ", height=" << it->get().height + << ", area=" << it->get().area() << ", allowed_rotations="; + for(auto r: it->get().allowed_rotations) ss << r << ", "; + ss << "; "; + } + if (this->unfitindicator_) + this->unfitindicator_(ss.str()); + } int item_id = 0; auto makeProgress = [this, &item_id](Placer &placer, size_t bin_idx) { @@ -102,8 +117,8 @@ public: }; auto& cancelled = this->stopcond_; - - this->template remove_unpackable_items(store_, bin, pconfig); + + //this->template remove_unpackable_items(store_, bin, pconfig); for (auto it = store_.begin(); it != store_.end() && !cancelled(); ++it) { // skip unpackable item @@ -116,8 +131,8 @@ public: double score_all_plates = 0, score_all_plates_best = std::numeric_limits::max(); typename Placer::PackResult result, result_best, result_firstfit; int j = 0; - while(!was_packed && !cancelled()) { - for(; j < placers.size() && !was_packed && !cancelled(); j++) { + while (!was_packed && !cancelled() && placers.size() <= MAX_NUM_PLATES) { + for(; j < placers.size() && !was_packed && !cancelled() && jget().is_wipe_tower && it->get().binId() != placers[j].plateID()) { if (this->unfitindicator_) this->unfitindicator_(it->get().name + " cant be placed in plate_id=" + std::to_string(j) + "/" + std::to_string(placers.size()) + ", continue to next plate"); @@ -127,7 +142,10 @@ public: score = result.score(); score_all_plates = score; for (int i = 0; i < placers.size(); i++) { score_all_plates += placers[i].score();} - if (this->unfitindicator_) this->unfitindicator_(it->get().name + " bed_id="+std::to_string(j) + ",score=" + std::to_string(score)+", score_all_plates="+std::to_string(score_all_plates)); + if (this->unfitindicator_) + this->unfitindicator_((boost::format("item %1% bed_id=%2%, score=%3%, score_all_plates=%4%, pos=(%5%, %6%)") % it->get().name % j % score % + score_all_plates % unscale_(it->get().translation()[0]) % unscale_(it->get().translation()[1])) + .str()); if(score >= 0 && score < LARGE_COST_TO_REJECT) { if (bed_id_firstfit == -1) { @@ -167,42 +185,42 @@ public: makeProgress(placers[j], j); } - if (was_packed && it->get().has_tried_with_excluded) { - placers[j].clearItems([](const Item &itm) { return itm.isFixed() && !itm.is_wipe_tower; }); - if (fixed_bins.size() >= placers.size()) - placers[j].preload(fixed_bins[placers.size() - 1]); - } - bool placer_not_packed = !was_packed && !placers.empty() && j == placers.size() && placers[j - 1].getPackedSize() == 0; // large item is not placed into the bin + // if the object can't be packed, try to pack it without extrusion calibration object + bool placer_not_packed = !was_packed && j > 0 && j == placers.size() && placers[j - 1].getPackedSize() == 0; // large item is not placed into the bin if (placer_not_packed) { - if (it->get().has_tried_with_excluded == false) { - it->get().has_tried_with_excluded = true; - placers[j - 1].clearItems([](const Item &itm) { return itm.isFixed()&&!itm.is_wipe_tower; }); - placers[j - 1].preload(pconfig.m_excluded_items); + if (it->get().has_tried_without_extrusion_cali_obj == false) { + it->get().has_tried_without_extrusion_cali_obj = true; + placers[j - 1].clearItems([](const Item &itm) { return itm.is_extrusion_cali_object; }); j = j - 1; continue; - } else { - placers[j - 1].clearItems([](const Item &itm) { return itm.isFixed() && !itm.is_wipe_tower; }); - placers[j - 1].preload(fixed_bins[placers.size() - 1]); } } if(!was_packed){ if (this->unfitindicator_ && !placers.empty()) - this->unfitindicator_(it->get().name + " not fit! height=" +std::to_string(it->get().height) - + " ,plate_id=" + std::to_string(j) - + ", score=" + std::to_string(score) - + ", best_bed_id=" + std::to_string(best_bed_id) - + ", score_all_plates=" + std::to_string(score_all_plates) - +", item.bed_id=" + std::to_string(it->get().binId())); - - placers.emplace_back(bin); - placers.back().plateID(placers.size() - 1); - placers.back().configure(pconfig); - if (fixed_bins.size() >= placers.size()) - placers.back().preload(fixed_bins[placers.size() - 1]); - //placers.back().preload(pconfig.m_excluded_items); - packed_bins_.emplace_back(); - j = placers.size() - 1; + this->unfitindicator_(it->get().name + " not fit! plate_id=" + std::to_string(placers.back().plateID()) + ", score=" + std::to_string(score) + + ", best_bed_id=" + std::to_string(best_bed_id) + ", score_all_plates=" + std::to_string(score_all_plates) + + ", item.bed_id=" + std::to_string(it->get().binId())); + if (!placers.empty() && placers.back().getItems().empty()) { + it->get().binId(BIN_ID_UNFIT); + if (this->unfitindicator_) this->unfitindicator_(it->get().name + " can't fit into a new bin. Can't fit!"); + // remove the last empty placer to force next item to be fit in existing plates first + if (placers.size() > 1) placers.pop_back(); + break; + } + if (placers.size() < MAX_NUM_PLATES) { + placers.emplace_back(bin); + placers.back().plateID(placers.size() - 1); + placers.back().configure(pconfig); + if (fixed_bins.size() >= placers.size()) placers.back().preload(fixed_bins[placers.size() - 1]); + // placers.back().preload(pconfig.m_excluded_items); + packed_bins_.emplace_back(); + j = placers.size() - 1; + } else { + it->get().binId(BIN_ID_UNFIT); + if (this->unfitindicator_) this->unfitindicator_(it->get().name + " can't fit into any bin. Can't fit!"); + break; + } } } } diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp index c98161f17..960a948de 100644 --- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp +++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp @@ -443,7 +443,7 @@ inline void offset(PolygonImpl& sh, bp2d::Coord distance) #ifndef DISABLE_BOOST_SERIALIZE template<> inline std::string serialize( - const PolygonImpl& sh, double scale, std::string fill, std::string stroke, float stroke_width) + const PolygonImpl& sh, const std::string& name, double scale, std::string fill, std::string stroke, float stroke_width) { std::stringstream ss; std::string style = "fill: "+fill+"; stroke: "+stroke+"; stroke-width: "+std::to_string(stroke_width)+"px; "; @@ -478,7 +478,14 @@ template<> inline std::string serialize( ss << svg_data << std::endl; - return ss.str(); + std::string svg_content = ss.str(); + if (!name.empty()) { + size_t pos = svg_content.find_first_of("(box.height() + conf_.y0*2) / conf_.mm_in_coord_units; conf_.width = static_cast(box.width() + conf_.x0*2) / conf_.mm_in_coord_units; } - void writeShape(RawShape tsh, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) { + void writeShape(RawShape tsh, const std::string &name = "", std::string fill = "none", std::string stroke = "black", float stroke_width = 1) + { if(svg_layers_.empty()) addLayer(); if(conf_.origo_location == BOTTOMLEFT) { auto d = static_cast( @@ -74,13 +75,14 @@ public: } } currentLayer() += - shapelike::serialize(tsh, + shapelike::serialize(tsh, name, 1.0 / conf_.mm_in_coord_units, fill, stroke, stroke_width) + "\n"; } - void writeItem(const Item& item, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) { - writeShape(item.transformedShape(), fill, stroke, stroke_width); + void writeItem(const Item &item, const std::string &name = "", std::string fill = "none", std::string stroke = "black", float stroke_width = 1) + { + writeShape(item.transformedShape(), name, fill, stroke, stroke_width); } void writePackGroup(const PackGroup& result) { @@ -97,7 +99,7 @@ public: auto it = from; PackGroup pg; while(it != to) { - if(it->binId() == BIN_ID_UNSET) continue; + if (it->binId() == BIN_ID_UNFIT) continue; while(pg.size() <= size_t(it->binId())) pg.emplace_back(); pg[it->binId()].emplace_back(*it); ++it; @@ -159,6 +161,8 @@ public: currentLayer() += "\n"; } + void clear() { svg_layers_.clear(); } + private: std::string& currentLayer() { return svg_layers_.back(); } diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 301f38b08..037e819c2 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -192,6 +192,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { // Allow parallel execution. pcfg.parallel = params.parallel; + pcfg.save_svg = params.save_svg; // BBS: excluded regions in BBS bed for (auto& poly : params.excluded_regions) @@ -548,18 +549,18 @@ protected: score += height_score / valid_items_cnt; } - std::set extruder_ids; + std::map extruder_id_types; std::set tpu_extruder_ids; for (int i = 0; i < m_items.size(); i++) { Item& p = m_items[i]; if (p.is_virt_object) continue; - extruder_ids.insert(p.extrude_ids.begin(),p.extrude_ids.end()); - for (int j = 0; j < p.extrude_ids.size(); j++) { - if (p.filament_types[j] == "TPU") tpu_extruder_ids.insert(p.extrude_ids[j]); + extruder_id_types.insert(p.extrude_id_filament_types.begin(), p.extrude_id_filament_types.end()); + for (auto id_type : p.extrude_id_filament_types) { + if (id_type.second == "TPU") tpu_extruder_ids.insert(id_type.first); } } - for (int j = 0; j < item.extrude_ids.size(); j++) { - if (item.filament_types[j] == "TPU") tpu_extruder_ids.insert(item.extrude_ids[j]); + for (auto id_type : item.extrude_id_filament_types) { + if (id_type.second == "TPU") tpu_extruder_ids.insert(id_type.first); } // do not allow more than 1 TPU extruder on same plate @@ -567,17 +568,17 @@ protected: // add a large cost if not multi materials on same plate is not allowed else if (!params.allow_multi_materials_on_same_plate) { // it's the first object, which can be multi-color - bool first_object = extruder_ids.empty(); + bool first_object = extruder_id_types.empty(); // the two objects (previously packed items and the current item) are considered having same color if either one's colors are a subset of the other - std::set item_extruder_ids(item.extrude_ids.begin(), item.extrude_ids.end()); - bool same_color_with_previous_items = std::includes(extruder_ids.begin(), extruder_ids.end(), item_extruder_ids.begin(), item_extruder_ids.end()); + bool same_color_with_previous_items = std::includes(extruder_id_types.begin(), extruder_id_types.end(), item.extrude_id_filament_types.begin(), + item.extrude_id_filament_types.end()); if (!(first_object || same_color_with_previous_items)) score += LARGE_COST_TO_REJECT * 1.3; } // for layered printing, we want extruder change as few as possible // this has very weak effect, CAN NOT use a large weight - int last_extruder_cnt = extruder_ids.size(); - extruder_ids.insert(item.extrude_ids.begin(), item.extrude_ids.end()); - int new_extruder_cnt= extruder_ids.size(); + int last_extruder_cnt = extruder_id_types.size(); + extruder_id_types.insert(item.extrude_id_filament_types.begin(), item.extrude_id_filament_types.end()); + int new_extruder_cnt = extruder_id_types.size(); if (!params.is_seq_print) { score += 1 * (new_extruder_cnt-last_extruder_cnt); } @@ -701,19 +702,19 @@ public: return i1.bed_temp != i2.bed_temp ? (i1.bed_temp > i2.bed_temp) : i1.height != i2.height ? (i1.height < i2.height) : std::abs(i1.area() / i2.area() - 1) > 0.2 ? (i1.area() > i2.area()) : - i1.extrude_ids.front() < i2.extrude_ids.front(); + i1.extrude_id_filament_types.begin()->first < i2.extrude_id_filament_types.begin()->first; } else { // single color objects first, then objects with more colors - if (i1.extrude_ids.size() != i2.extrude_ids.size()) { - if (i1.extrude_ids.size() == 1 || i2.extrude_ids.size() == 1) - return i1.extrude_ids.size() == 1; + if (i1.extrude_id_filament_types.size() != i2.extrude_id_filament_types.size()) { + if (i1.extrude_id_filament_types.size() == 1 || i2.extrude_id_filament_types.size() == 1) + return i1.extrude_id_filament_types.size() == 1; else - return i1.extrude_ids.size() > i2.extrude_ids.size(); + return i1.extrude_id_filament_types.size() > i2.extrude_id_filament_types.size(); } else return i1.bed_temp != i2.bed_temp ? (i1.bed_temp > i2.bed_temp) : - i1.extrude_ids != i2.extrude_ids ? (i1.extrude_ids.front() < i2.extrude_ids.front()) : + i1.extrude_id_filament_types != i2.extrude_id_filament_types ? (i1.extrude_id_filament_types.begin()->first < i2.extrude_id_filament_types.begin()->first) : std::abs(i1.height/params.printable_height - i2.height/params.printable_height)>0.05 ? i1.height > i2.height: (i1.area() > i2.area()); } @@ -883,7 +884,8 @@ void _arrange( try { auto bbox = minAreaBoundingBox, boost::rational>(itm.transformedShape()); auto w = bbox.width(), h = bbox.height(); - if (w > h * 1.1 || h > w * 1.1) { itm.allowed_rotations = {bbox.angleToX() + PI / 2, 0.0}; + if (w > h * 1.1 || h > w * 1.1) { + itm.allowed_rotations = {bbox.angleToX() + PI / 2, 0.0}; } } catch (const std::exception &e) { // min_area_boundingbox_rotation may throw exception of dividing 0 if the object is already perfectly aligned to X @@ -916,8 +918,6 @@ void _arrange( AutoArranger arranger{corrected_bin, mod_params, progressfn, stopfn}; - remove_large_items(excludes, corrected_bin); - // If there is something on the plate if (!excludes.empty()) arranger.preload(excludes); @@ -992,13 +992,13 @@ static void process_arrangeable(const ArrangePolygon &arrpoly, item.binId(arrpoly.bed_idx); item.priority(arrpoly.priority); item.itemId(arrpoly.itemid); - item.extrude_ids = arrpoly.extrude_ids; - item.filament_types = arrpoly.filament_types; + item.extrude_id_filament_types = arrpoly.extrude_id_filament_types; item.height = arrpoly.height; item.name = arrpoly.name; //BBS: add virtual object logic item.is_virt_object = arrpoly.is_virt_object; item.is_wipe_tower = arrpoly.is_wipe_tower; + item.is_extrusion_cali_object = arrpoly.is_extrusion_cali_object; item.bed_temp = arrpoly.first_bed_temp; item.print_temp = arrpoly.print_temp; item.vitrify_temp = arrpoly.vitrify_temp; diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index 741d3b41d..99de6c895 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -61,8 +61,7 @@ struct ArrangePolygon { //BBS: add row/col for sudoku-style layout int row{0}; int col{0}; - std::vector extrude_ids{}; /// extruder_id for least extruder switch - std::vector filament_types{}; /// filament type for different material judge + std::map extrude_id_filament_types; /// extruder_id for least extruder switch, filament type for different material judge int filament_temp_type{ -1 }; int bed_temp{0}; ///bed temperature for different material judge int print_temp{0}; ///print temperature for different material judge @@ -127,6 +126,7 @@ struct ArrangeParams { bool avoid_extrusion_cali_region = true; bool is_seq_print = false; bool align_to_y_axis = false; + bool save_svg = false; float bed_shrink_x = 0.1; float bed_shrink_y = 0.1; float brim_skirt_distance = 0; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 011158204..f95c7df69 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -76,6 +76,7 @@ namespace Slic3r { //! return same string #define L(s) (s) #define _(s) Slic3r::I18N::translate(s) +#define _L(s) Slic3r::I18N::translate(s) static const float g_min_purge_volume = 100.f; static const float g_purge_volume_one_time = 135.f; @@ -2888,7 +2889,7 @@ void GCode::process_layers( else { tbb::parallel_pipeline(12, generator & parsing & cooling & build_node); std::string message; - message = L("Smoothing z direction speed"); + message = _L("Smoothing z direction speed"); m_print->set_status(85, message); //append data for (const LayerResult &res : layers_results) { @@ -2900,7 +2901,7 @@ void GCode::process_layers( } smooth_calculator.smooth_layer_speed(); - message = L("Exporting G-code"); + message = _L("Exporting G-code"); m_print->set_status(90, message); tbb::parallel_pipeline(12, calculate_layer_time & write_gocde & output); } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index a28d02b1c..6ca7571e3 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -3596,12 +3596,13 @@ void Model::setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConf } // find temperature of heatend and bed and matierial of an given extruder -void Model::setExtruderParams(const DynamicPrintConfig& config, int extruders_count) { +void Model::setExtruderParams(const DynamicPrintConfig &config, int filament_count) +{ extruderParamsMap.clear(); //Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config(); // BBS //int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); - for (unsigned int i = 0; i != extruders_count; ++i) { + for (unsigned int i = 0; i != filament_count; ++i) { std::string matName = ""; // BBS int bedTemp = 35; @@ -3973,6 +3974,9 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf ret.rotation = 0; // BBS: add materials related information + auto get_filament_name = [](int id) { + return Model::extruderParamsMap.find(id) != Model::extruderParamsMap.end() ? Model::extruderParamsMap.at(id).materialName : "PLA"; + }; ModelVolume *volume = NULL; for (size_t i = 0; i < object->volumes.size(); ++i) { if (object->volumes[i]->is_model_part()) { @@ -3982,7 +3986,9 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf return; } auto ve = object->volumes[i]->get_extruders(); - ret.extrude_ids.insert(ret.extrude_ids.end(), ve.begin(), ve.end()); + for (auto id : ve) { + ret.extrude_id_filament_types.insert({id, get_filament_name(id)}); + } } } @@ -3994,16 +4000,12 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf auto op2 = object->get_config_value(config_global, "support_interface_filament"); int extruder_id; // id==0 means follow previous material, so need not be recorded - if (op1 && (extruder_id = op1->getInt()) > 0) ret.extrude_ids.push_back(extruder_id); - if (op2 && (extruder_id = op2->getInt()) > 0) ret.extrude_ids.push_back(extruder_id); + if (op1 && (extruder_id = op1->getInt()) > 0) ret.extrude_id_filament_types.insert({extruder_id, get_filament_name(extruder_id)}); + if (op2 && (extruder_id = op2->getInt()) > 0) ret.extrude_id_filament_types.insert({extruder_id, get_filament_name(extruder_id)}); } - ret.extrude_ids.erase(std::unique(ret.extrude_ids.begin(), ret.extrude_ids.end()), ret.extrude_ids.end()); - if (ret.extrude_ids.empty()) // the default extruder - ret.extrude_ids.push_back(1); - - // filament types must be same size as extrude_ids - ret.filament_types.resize(ret.extrude_ids.size(), "PLA"); + if (ret.extrude_id_filament_types.empty()) // the default extruder + ret.extrude_id_filament_types.insert({1, get_filament_name(1)}); } void ModelInstance::apply_arrange_result(const Vec2d &offs, double rotation) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a5064eafe..deb2afd93 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1623,7 +1623,7 @@ public: static Polygon getBedPolygon() { return Model::printSpeedMap.bed_poly; } //BBS static functions that update extruder params and speed table static void setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConfig& print_config); - static void setExtruderParams(const DynamicPrintConfig& config, int extruders_count); + static void setExtruderParams(const DynamicPrintConfig& config, int filament_count); // BBS: backup static Model read_from_archive( diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 964e12946..8acb36533 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -119,7 +119,7 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst, const Slic3r:: ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::DynamicPrintConfig& config) { ArrangePolygon ap = get_arrange_poly(PtrWrapper{ instance }, config); - + int first_extruder_id = ap.extrude_id_filament_types.begin()->first - 1; //BBS: add temperature information if (config.has("curr_bed_type")) { ap.bed_temp = 0; @@ -127,29 +127,28 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r:: BedType curr_bed_type = config.opt_enum("curr_bed_type"); const ConfigOptionInts* bed_opt = config.option(get_bed_temp_key(curr_bed_type)); - if (bed_opt != nullptr) - ap.bed_temp = bed_opt->get_at(ap.extrude_ids.front()-1); + if (bed_opt != nullptr) ap.bed_temp = bed_opt->get_at(first_extruder_id); const ConfigOptionInts* bed_opt_1st_layer = config.option(get_bed_temp_1st_layer_key(curr_bed_type)); if (bed_opt_1st_layer != nullptr) - ap.first_bed_temp = bed_opt_1st_layer->get_at(ap.extrude_ids.front()-1); + ap.first_bed_temp = bed_opt_1st_layer->get_at(first_extruder_id); } if (config.has("nozzle_temperature")) //get the print temperature - ap.print_temp = config.opt_int_nullable("nozzle_temperature", ap.extrude_ids.front() - 1); + ap.print_temp = config.opt_int_nullable("nozzle_temperature", first_extruder_id); if (config.has("nozzle_temperature_initial_layer")) //get the nozzle_temperature_initial_layer - ap.first_print_temp = config.opt_int_nullable("nozzle_temperature_initial_layer", ap.extrude_ids.front() - 1); + ap.first_print_temp = config.opt_int_nullable("nozzle_temperature_initial_layer", first_extruder_id); if (config.has("temperature_vitrification")) { - ap.vitrify_temp = config.opt_int("temperature_vitrification", ap.extrude_ids.front() - 1); + ap.vitrify_temp = config.opt_int("temperature_vitrification", first_extruder_id); } // get filament temp types auto* filament_types_opt = dynamic_cast(config.option("filament_type")); if (filament_types_opt) { std::set filament_temp_types; - for (auto i : ap.extrude_ids) { - std::string type_str = filament_types_opt->get_at(i-1); + for (auto id : ap.extrude_id_filament_types) { + std::string type_str = filament_types_opt->get_at(id.first-1); int temp_type = Print::get_filament_temp_type(type_str); filament_temp_types.insert(temp_type); } diff --git a/src/libslic3r/VectorFormatter.hpp b/src/libslic3r/VectorFormatter.hpp index d29eddb6c..bf7bba8f0 100644 --- a/src/libslic3r/VectorFormatter.hpp +++ b/src/libslic3r/VectorFormatter.hpp @@ -1,31 +1,38 @@ #pragma once -#include #include #include // custom vector wrapper for outputting to log -template struct VectorFormatter +template struct VectorFormatter { - const std::vector* vec = nullptr; - const Eigen::Matrix* mat = nullptr; - explicit VectorFormatter(const std::vector& v) : vec(&v) {} - explicit VectorFormatter(const Eigen::Matrix& m) : mat(&m) {} + const Container &vec; + explicit VectorFormatter(const Container& v) : vec(v) {} - friend std::ostream& operator<<(std::ostream& os, const VectorFormatter& vf) + friend std::ostream &operator<<(std::ostream &os, const VectorFormatter &vf) { os << "["; - if (vf.vec) { - for (size_t i = 0; i < vf.vec->size(); ++i) { - os << (*vf.vec)[i]; - if (i != vf.vec->size() - 1) { os << ", "; } - } - } - else { - for (int i = 0; i < vf.mat->size(); ++i) { - os << (*vf.mat)(i); - if (i != vf.mat->size() - 1) { os << ", "; } - } + for (auto it = vf.vec.begin(); it != vf.vec.end();it++) { + os << *it; + if (std::next(it) != vf.vec.end()) { os << ", "; } + } + os << "]"; + return os; + } +}; + +// custom vector wrapper for outputting to log +template struct MapFormatter +{ + const std::map &vec; + explicit MapFormatter(const std::map &v) : vec(v) {} + + friend std::ostream &operator<<(std::ostream &os, const MapFormatter &vf) + { + os << "["; + for (auto it = vf.vec.begin(); it != vf.vec.end(); it++) { + os << it->first << " : " << it->second; + if (std::next(it) != vf.vec.end()) { os << ", "; } } os << "]"; return os; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f3461c067..20984abca 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3535,6 +3535,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) int keyCode = evt.GetKeyCode(); int ctrlMask = wxMOD_CONTROL; int shiftMask = wxMOD_SHIFT; + int altMask = wxMOD_ALT; auto imgui = wxGetApp().imgui(); if (imgui->update_key_data(evt)) { @@ -3758,6 +3759,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) { if ((evt.GetModifiers() & shiftMask) != 0) post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE_PARTPLATE)); + else if ((evt.GetModifiers() & altMask) != 0) + post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE_OUTPLATE)); else post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; @@ -6117,6 +6120,7 @@ bool GLCanvas3D::_render_arrange_menu(float left, float right, float bottom, flo std::string multi_material_key = "allow_multi_materials_on_same_plate"; std::string avoid_extrusion_key = "avoid_extrusion_cali_region"; std::string align_to_y_axis_key = "align_to_y_axis"; + std::string save_svg_key = "save_svg"; std::string postfix = settings.postfix; //BBS: bool seq_print = settings.is_seq_print; @@ -6144,6 +6148,13 @@ bool GLCanvas3D::_render_arrange_menu(float left, float right, float bottom, flo imgui->text(_L("0 means auto spacing.")); ImGui::Separator(); +#if !BBL_RELEASE_TO_PUBLIC + if (imgui->bbl_checkbox(_L("Save SVG"), settings.save_svg)) { + settings_out.save_svg = settings.save_svg; + appcfg->set("arrange", save_svg_key.c_str(), settings_out.save_svg ? "1" : "0"); + settings_changed = true; + } +#endif if (imgui->bbl_checkbox(_L("Auto rotate for arrangement"), settings.enable_rotation)) { settings_out.enable_rotation = settings.enable_rotation; appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0"); @@ -11179,6 +11190,10 @@ const SLAPrint* GLCanvas3D::sla_print() const void GLCanvas3D::WipeTowerInfo::apply_wipe_tower() const { + if (m_plate_idx >= wxGetApp().plater()->get_partplate_list().get_plate_count()) { + BOOST_LOG_TRIVIAL(error) << "Invalid plate index: " << m_plate_idx << ">=" << wxGetApp().plater()->get_partplate_list().get_plate_count(); + return; + } // BBS: add partplate logic DynamicConfig& proj_cfg = wxGetApp().preset_bundle->project_config; Vec3d plate_origin = wxGetApp().plater()->get_partplate_list().get_plate(m_plate_idx)->get_origin(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 21670e002..11548df6f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -528,6 +528,7 @@ public: //BBS: add more arrangeSettings bool is_seq_print = false; bool align_to_y_axis = false; + bool save_svg = false; // for debug std::string postfix; void reset() { diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index e33752081..0174f949c 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -111,26 +111,6 @@ ArrangePolygon ArrangeJob::prepare_arrange_polygon(void *model_instance) auto preset_bundle = wxGetApp().preset_bundle; const Slic3r::DynamicPrintConfig& config = preset_bundle->full_config(); ArrangePolygon ap = get_instance_arrange_poly(instance, config); - - // get filament types such as PLA, ABS, etc. - ap.filament_types.clear(); - for (size_t i = 0; i < preset_bundle->filament_presets.size(); ++i) { - auto iter = std::find(ap.extrude_ids.begin(), ap.extrude_ids.end(), i + 1); - if (iter == ap.extrude_ids.end()) continue; - - std::string filament_name = preset_bundle->filament_presets[i]; - for (int f_index = 0; f_index < preset_bundle->filaments.size(); f_index++) { - PresetCollection *filament_presets = &preset_bundle->filaments; - Preset *preset = &filament_presets->preset(f_index); - int size = preset_bundle->filaments.size(); - if (preset && filament_name.compare(preset->name) == 0) { - std::string display_filament_type; - std::string filament_type = preset->config.get_filament_type(display_filament_type); - ap.filament_types.push_back(filament_type); - } - } - } - return ap; } @@ -328,9 +308,7 @@ void ArrangeJob::prepare_wipe_tower(bool select) // estimate if we need wipe tower for all plates: // need wipe tower if some object has multiple extruders (has paint-on colors or support material) for (const auto& item : m_selected) { - std::set obj_extruders; - obj_extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); - if (obj_extruders.size() > 1) { + if (item.extrude_id_filament_types.size() > 1) { need_wipe_tower = true; ARRANGE_LOG(info) << "need wipe tower because object " << item.name << " has multiple extruders (has paint-on colors)"; break; @@ -342,7 +320,7 @@ void ArrangeJob::prepare_wipe_tower(bool select) if (params.allow_multi_materials_on_same_plate) { std::map> bedTemp2extruderIds; for (const auto& item : m_selected) - for (auto id : item.extrude_ids) { bedTemp2extruderIds[item.bed_temp].insert(id); } + for (auto id : item.extrude_id_filament_types) { bedTemp2extruderIds[item.bed_temp].insert(id.first); } for (const auto& be : bedTemp2extruderIds) { if (be.second.size() > 1) { need_wipe_tower = true; @@ -432,11 +410,9 @@ void ArrangeJob::prepare_partplate() { bool in_plate = plate->contain_instance(oidx, inst_idx) || plate->intersect_instance(oidx, inst_idx); ArrangePolygon&& ap = prepare_arrange_polygon(mo->instances[inst_idx]); - ArrangePolygons& cont = mo->instances[inst_idx]->printable ? - (in_plate ? m_selected : m_unselected) : - m_unprintable; + ArrangePolygons &cont = mo->instances[inst_idx]->printable ? m_selected : m_unprintable; bool locked = plate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate); - if (!locked) + if (!locked && in_plate) { ap.itemid = cont.size(); cont.emplace_back(std::move(ap)); @@ -510,9 +486,10 @@ void ArrangeJob::prepare_outside_plate() { } if (iter2 != all_outside_objects.end()) { outside_plate = true; + ARRANGE_LOG(debug) << object->name << " is outside!"; } ArrangePolygon&& ap = prepare_arrange_polygon(instance); - ArrangePolygons &cont = instance->printable ? (outside_plate ? m_selected : m_locked) : m_unprintable; + ArrangePolygons &cont = instance->printable ? (outside_plate ? m_selected : m_unselected) : m_unprintable; ap.itemid = cont.size(); if (!outside_plate) { plate_list.preprocess_arrange_polygon(obj_idx, inst_idx, ap, false); @@ -538,9 +515,9 @@ void ArrangeJob::prepare() const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); auto& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); auto print_config = print.config(); - int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); + int filament_count = wxGetApp().preset_bundle->filament_presets.size(); - Model::setExtruderParams(config, numExtruders); + Model::setExtruderParams(config, filament_count); Model::setPrintSpeedTable(config, print_config); int state = m_plater->get_prepare_state(); @@ -602,7 +579,7 @@ void ArrangeJob::prepare() if (!m_selected.empty()) { m_plater->get_notification_manager()->push_notification(NotificationType::ArrangeOngoing, NotificationManager::NotificationLevel::RegularNotificationLevel, - _u8L("Arranging...")); + _u8L("Arranging") + "..."); m_plater->get_notification_manager()->bbl_close_plateinfo_notification(); } } @@ -667,36 +644,34 @@ void ArrangeJob::process() update_status(num_finished, _L("Arranging") + " "+ wxString::FromUTF8(str)); }; - ArrangePolygons unselected_and_locked = m_unselected; - append(unselected_and_locked, m_locked); { ARRANGE_LOG(warning)<< "full params: "<< params.to_json(); ARRANGE_LOG(info) << boost::format("items selected before arranging: %1%") % m_selected.size(); for (auto selected : m_selected) { - ARRANGE_LOG(debug) << selected.name << ", extruder: " << VectorFormatter(selected.extrude_ids) - << ", filament types: " << VectorFormatter(selected.filament_types) << ", bed: " << selected.bed_idx - << ", filemant_type:" << selected.filament_temp_type << ", trans: " << unscale(selected.translation(X)) << "," - << unscale(selected.translation(Y)) << ", rotation: " << selected.rotation; + ARRANGE_LOG(debug) << selected.name << ", extruder: " << MapFormatter(selected.extrude_id_filament_types) << ", bed: " << selected.bed_idx + << ", filemant_type:" << selected.filament_temp_type << ", trans: " << unscale(selected.translation(X)) << "," + << unscale(selected.translation(Y)) << ", rotation: " << selected.rotation; } - ARRANGE_LOG(debug) << "items unselected before arrange: " << unselected_and_locked.size(); - for (auto item : unselected_and_locked) - ARRANGE_LOG(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale(item.translation(X)) << "," << unscale(item.translation(Y)); + ARRANGE_LOG(debug) << "items unselected before arrange: " << m_unselected.size(); + for (auto item : m_unselected) + BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale(item.translation(X)) << "," + << unscale(item.translation(Y)); } - arrangement::arrange(m_selected, unselected_and_locked, bedpts, params); + arrangement::arrange(m_selected, m_unselected, bedpts, params); // sort by item id std::sort(m_selected.begin(), m_selected.end(), [](auto a, auto b) {return a.itemid < b.itemid; }); { ARRANGE_LOG(info) << boost::format("items selected after arranging: %1%") % m_selected.size(); for (auto selected : m_selected) - ARRANGE_LOG(debug) << selected.name << ", extruder: " << VectorFormatter(selected.extrude_ids) << ", bed: " << selected.bed_idx + ARRANGE_LOG(debug) << selected.name << ", extruder: " << MapFormatter(selected.extrude_id_filament_types) << ", bed: " << selected.bed_idx << ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp << ", trans: " << unscale(selected.translation(X)) << "," << unscale(selected.translation(Y)) << ", rotation: " << selected.rotation; - ARRANGE_LOG(debug) << "items unselected after arrange: " << unselected_and_locked.size(); - for (auto item : unselected_and_locked) - ARRANGE_LOG(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale(item.translation(X)) << "," << unscale(item.translation(Y)); + ARRANGE_LOG(debug) << "items unselected after arrange: " << m_unselected.size(); + for (auto item : m_unselected) + BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale(item.translation(X)) << "," << unscale(item.translation(Y)); } // put unpackable items to m_unprintable so they goes outside @@ -752,7 +727,7 @@ void ArrangeJob::finalize() beds = std::max(ap.bed_idx, beds); - ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": selected %4%: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": selected %4%: bed_id %1%, trans {%2%, %3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; } //BBS: adjust the bed_index, create new plates, get the max bed_index @@ -765,7 +740,7 @@ void ArrangeJob::finalize() plate_list.postprocess_bed_index_for_unselected(ap); beds = std::max(ap.bed_idx, beds); - ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": unselected %4%: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": unselected %4%: bed_id %1%, trans {%2%, %3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; } for (ArrangePolygon& ap : m_locked) { @@ -893,6 +868,9 @@ arrangement::ArrangeParams init_arrange_params(Plater *p) params.is_seq_print = settings.is_seq_print; params.min_obj_distance = scaled(settings.distance); params.align_to_y_axis = settings.align_to_y_axis; +#if !BBL_RELEASE_TO_PUBLIC + params.save_svg = settings.save_svg; +#endif int state = p->get_prepare_state(); if (state == Job::JobPrepareState::PREPARE_STATE_MENU) { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2093e61ae..8e83282e5 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4844,9 +4844,9 @@ void Plater::priv::select_view_3D(const std::string& name, bool no_slice) const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); auto& print = q->get_partplate_list().get_current_fff_print(); auto print_config = print.config(); - int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); + int filament_count = wxGetApp().preset_bundle->filament_presets.size(); - Model::setExtruderParams(config, numExtruders); + Model::setExtruderParams(config, filament_count); Model::setPrintSpeedTable(config, print_config); set_current_panel(preview, no_slice); } @@ -5740,7 +5740,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ // BBS BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_LOAD_MODEL_OBJECTS \n"); - wxString msg = wxString::Format("Loading file: %s", from_path(real_filename)); + wxString msg = wxString::Format(_L("Loading file: %s"), from_path(real_filename)); model_idx++; dlg_cont = dlg.Update(progress_percent, msg); if (!dlg_cont) { @@ -8666,9 +8666,9 @@ void Plater::priv::on_action_slice_plate(SimpleEvent&) const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); auto& print = q->get_partplate_list().get_current_fff_print(); auto print_config = print.config(); - int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); + int filament_count = wxGetApp().preset_bundle->filament_presets.size(); - Model::setExtruderParams(config, numExtruders); + Model::setExtruderParams(config, filament_count); Model::setPrintSpeedTable(config, print_config); m_slice_all = false; q->reslice(); @@ -8685,9 +8685,9 @@ void Plater::priv::on_action_slice_all(SimpleEvent&) const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); auto& print = q->get_partplate_list().get_current_fff_print(); auto print_config = print.config(); - int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); + int filament_count = wxGetApp().preset_bundle->filament_presets.size(); - Model::setExtruderParams(config, numExtruders); + Model::setExtruderParams(config, filament_count); Model::setPrintSpeedTable(config, print_config); m_slice_all = true; m_slice_all_only_has_gcode = true;