FIX: auto arranging crash

1. Use map<int, std::string> extrude_id_filament_types to avoid mismatching of extruder ids and filament types.
  jira: STUDIO-10708
2. fix plate level arranging not working
  jira: STUDIO-10733, STUDIO-10721
3. fix auto arranging may put objects overlapping with fixed ones when
  changing printer profile.
3. fix auto arranging puts large objects overlapping with occlusion area
4. add alt+a to trigger auto arranging for out of plate objects
4. fix several texts not translated.

Change-Id: Ie43624cb20304f27649d3ce24efa01394f30188e
This commit is contained in:
Arthur 2025-03-06 11:09:40 +08:00 committed by lane.wei
parent e02f44d8dd
commit 2fd184f754
19 changed files with 277 additions and 292 deletions

View File

@ -4422,6 +4422,10 @@ int CLI::run(int argc, char **argv)
oriented_or_arranged |= need_arrange; 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; 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) if (need_arrange || filament_color_changed)
{ {
for (int index = 0; index < partplate_list.get_plate_count(); index ++) 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) << "Arrange full params: " << arrange_cfg.to_json();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % selected.size(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % selected.size();
for (auto item : selected) 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(); << ", trans: " << item.translation.transpose();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size();
for (auto item : unselected) 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(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)<< "Arrange full params: "<< arrange_cfg.to_json();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size();
for (auto item : selected) for (auto item : selected) BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose();
BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx
<< ", trans: " << item.translation.transpose();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size();
for (auto item : unselected) for (auto item : unselected) BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose();
BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose();
} }
arrange_cfg.progressind= [](unsigned st, std::string str = "") { arrange_cfg.progressind= [](unsigned st, std::string str = "") {
//boost::nowide::cout << "st=" << st << ", " << str << std::endl; //boost::nowide::cout << "st=" << st << ", " << str << std::endl;

View File

@ -656,7 +656,7 @@ inline std::string toString(const S& /*sh*/)
} }
template<Formats, class S> template<Formats, class S>
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<S>::value, static_assert(always_false<S>::value,
"shapelike::serialize() unimplemented!"); "shapelike::serialize() unimplemented!");

View File

@ -75,8 +75,7 @@ class _Item {
public: public:
int itemid_{ 0 }; int itemid_{ 0 };
std::vector<int> extrude_ids; std::map<int, std::string> extrude_id_filament_types; // extrude id to filament type
std::vector<std::string> filament_types{}; /// filament type for different material judge
int filament_temp_type = -1; // -1 means unset. otherwise should be one of FilamentTempType ie {0,1,2} int filament_temp_type = -1; // -1 means unset. otherwise should be one of FilamentTempType ie {0,1,2}
double height{ 0 }; double height{ 0 };
double print_temp{ 0 }; double print_temp{ 0 };
@ -86,7 +85,8 @@ public:
//BBS: virtual object to mark unprintable region on heatbed //BBS: virtual object to mark unprintable region on heatbed
bool is_virt_object{ false }; bool is_virt_object{ false };
bool is_wipe_tower{ 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<double> allowed_rotations{0.}; std::vector<double> allowed_rotations{0.};
/// The type of the shape which was handed over as the template argument. /// The type of the shape which was handed over as the template argument.

View File

@ -18,8 +18,8 @@
#include "placer_boilerplate.hpp" #include "placer_boilerplate.hpp"
// temporary // temporary
//#include "../tools/svgtools.hpp" #include "../tools/svgtools.hpp"
//#include <iomanip> // setprecision #include <iomanip> // setprecision
#include <libnest2d/parallel.hpp> #include <libnest2d/parallel.hpp>
@ -690,6 +690,18 @@ private:
using Edges = EdgeCache<RawShape>; using Edges = EdgeCache<RawShape>;
// 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<MaxNfpLevel::value>());
auto v = item.referenceVertex();
for (const RawShape &nfp : nfps) {
if (sl::isInside(v, nfp) || sl::touches(v, nfp)) { return false; }
}
return true;
};
template<class Range = ConstItemRange<typename Base::DefaultIter>> template<class Range = ConstItemRange<typename Base::DefaultIter>>
PackResult _trypack(Item& item, const Range& remaining = Range()) { 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 bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; });
// @return 1 if current item overlaps with virtual objects, 0 otherwise
auto overlapWithVirtObject = [&]() -> double {
if (items_.empty()) return 0;
nfps = calcnfp(item, binbb, Lvl<MaxNfpLevel::value>());
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) { if (first_object) {
setInitialPosition(item); setInitialPosition(item);
@ -780,21 +786,23 @@ private:
// try normal inflation first, then 0 inflation if not fit. See STUDIO-5566. // 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(). // Note for by-object printing, bed is expanded by -config_.bed_shrink.x().
Coord inflation_back = item.inflation(); 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++) { for (size_t i = 0; i < 2; i++) {
item.inflation(inflations[i]); item.inflation(inflations[i]);
for (auto rot : item.allowed_rotations) { for (auto rot : item.allowed_rotations) {
item.translation(initial_tr); item.translation(initial_tr);
item.rotation(initial_rot + rot); item.rotation(initial_rot + rot);
setInitialPosition(item); setInitialPosition(item);
double of = overfit(item.transformedShape(), bin_); if (!overlapWithVirtObject(item, binbb)) {
if (of + overlapWithVirtObject() < best_overfit) { double of = overfit(item.transformedShape(), bin_);
best_overfit = of; if (of < best_overfit) {
best_tr = item.translation(); best_overfit = of;
best_rot = item.rotation(); best_tr = item.translation();
if (best_overfit <= 0) { best_rot = item.rotation();
config_.progressFunc("First object can fit with rot="+std::to_string(rot)); if (best_overfit <= 0) {
break; config_.progressFunc("First object " + item.name + " can fit with rot=" + std::to_string(rot));
break;
}
} }
} }
} }
@ -1005,41 +1013,7 @@ private:
item.rotation(final_rot); item.rotation(final_rot);
} }
#ifdef SVGTOOLS_HPP if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack);
if (config_.save_svg) {
svg::SVGWriter<RawShape> 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(can_pack) { if(can_pack) {
ret = PackResult(item); ret = PackResult(item);
@ -1068,26 +1042,18 @@ private:
auto binbb = sl::boundingBox(bin_); 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<MaxNfpLevel::value>());
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) { for (auto rot : item.allowed_rotations) {
item.translation(initial_tr); item.translation(initial_tr);
item.rotation(initial_rot + rot); item.rotation(initial_rot + rot);
if (0==overlapWithVirtObject()) { if (!overlapWithVirtObject(item, binbb)) {
can_pack = true; can_pack = true;
final_tr = initial_tr; final_tr = initial_tr;
final_rot = initial_rot + rot; final_rot = initial_rot + rot;
@ -1100,46 +1066,13 @@ private:
item.rotation(final_rot); item.rotation(final_rot);
} }
#ifdef SVGTOOLS_HPP if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack);
if (config_.save_svg) {
svg::SVGWriter<RawShape> 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 (can_pack) { if (can_pack) {
ret = PackResult(item); ret = PackResult(item);
ret.score_ = global_score; ret.score_ = global_score;
// merged_pile_ = nfp::merge(merged_pile_, item.transformedShape()); // merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
config_.progressFunc((boost::format("_trypack_with_original_pos: item %1% can pack") % item.name).str());
} else { } else {
ret = PackResult(best_overfit); ret = PackResult(best_overfit);
} }
@ -1147,6 +1080,33 @@ private:
return ret; return ret;
} }
void saveSVG(Box &binbb, Shapes &nfps, Item &item, double global_score, bool can_pack)
{
svg::SVGWriter<RawShape> 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 box2RawShape(Box& bbin)
{ {
RawShape binrsh; RawShape binrsh;
@ -1260,17 +1220,7 @@ private:
auto d = cb - ci; auto d = cb - ci;
// BBS make sure the item won't clash with excluded regions // BBS make sure the item won't clash with excluded regions
// do we have wipe tower after arranging?
size_t n_objs = 0; size_t n_objs = 0;
std::set<int> 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<RawShape> objs,excludes; std::vector<RawShape> objs,excludes;
for (Item &item : items_) { for (Item &item : items_) {
if (item.isFixed()) { if (item.isFixed()) {

View File

@ -41,7 +41,7 @@ public:
std::vector<Placer> placers; std::vector<Placer> placers;
placers.reserve(last-first); placers.reserve(last-first);
typename Base::PackGroup fixed_bins; typename Base::PackGroup fixed_bins;
std::for_each(first, last, [this, &fixed_bins](Item& itm) { std::for_each(first, last, [this, &fixed_bins](Item& itm) {
if (itm.isFixed()) { if (itm.isFixed()) {
@ -67,7 +67,7 @@ public:
std::for_each(first, last, [this,&svgwriter](Item &itm) { svgwriter.writeShape(itm, "none", "blue"); }); std::for_each(first, last, [this,&svgwriter](Item &itm) { svgwriter.writeShape(itm, "none", "blue"); });
svgwriter.save(boost::filesystem::path("SVG") / "all_items.svg"); svgwriter.save(boost::filesystem::path("SVG") / "all_items.svg");
#endif #endif
std::function<bool(Item& i1, Item& i2)> sortfunc; std::function<bool(Item& i1, Item& i2)> sortfunc;
if (pconfig.sortfunc) if (pconfig.sortfunc)
sortfunc = pconfig.sortfunc; sortfunc = pconfig.sortfunc;
@ -93,6 +93,21 @@ public:
if (this->unfitindicator_) if (this->unfitindicator_)
this->unfitindicator_(ss.str()); 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; int item_id = 0;
auto makeProgress = [this, &item_id](Placer &placer, size_t bin_idx) { auto makeProgress = [this, &item_id](Placer &placer, size_t bin_idx) {
@ -102,8 +117,8 @@ public:
}; };
auto& cancelled = this->stopcond_; auto& cancelled = this->stopcond_;
this->template remove_unpackable_items<Placer>(store_, bin, pconfig); //this->template remove_unpackable_items<Placer>(store_, bin, pconfig);
for (auto it = store_.begin(); it != store_.end() && !cancelled(); ++it) { for (auto it = store_.begin(); it != store_.end() && !cancelled(); ++it) {
// skip unpackable item // skip unpackable item
@ -116,8 +131,8 @@ public:
double score_all_plates = 0, score_all_plates_best = std::numeric_limits<double>::max(); double score_all_plates = 0, score_all_plates_best = std::numeric_limits<double>::max();
typename Placer::PackResult result, result_best, result_firstfit; typename Placer::PackResult result, result_best, result_firstfit;
int j = 0; int j = 0;
while(!was_packed && !cancelled()) { while (!was_packed && !cancelled() && placers.size() <= MAX_NUM_PLATES) {
for(; j < placers.size() && !was_packed && !cancelled(); j++) { for(; j < placers.size() && !was_packed && !cancelled() && j<MAX_NUM_PLATES; j++) {
if (it->get().is_wipe_tower && it->get().binId() != placers[j].plateID()) { if (it->get().is_wipe_tower && it->get().binId() != placers[j].plateID()) {
if (this->unfitindicator_) 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"); 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 = result.score();
score_all_plates = score; score_all_plates = score;
for (int i = 0; i < placers.size(); i++) { score_all_plates += placers[i].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(score >= 0 && score < LARGE_COST_TO_REJECT) {
if (bed_id_firstfit == -1) { if (bed_id_firstfit == -1) {
@ -167,42 +185,42 @@ public:
makeProgress(placers[j], j); makeProgress(placers[j], j);
} }
if (was_packed && it->get().has_tried_with_excluded) { // if the object can't be packed, try to pack it without extrusion calibration object
placers[j].clearItems([](const Item &itm) { return itm.isFixed() && !itm.is_wipe_tower; }); 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 (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 (placer_not_packed) { if (placer_not_packed) {
if (it->get().has_tried_with_excluded == false) { if (it->get().has_tried_without_extrusion_cali_obj == false) {
it->get().has_tried_with_excluded = true; it->get().has_tried_without_extrusion_cali_obj = true;
placers[j - 1].clearItems([](const Item &itm) { return itm.isFixed()&&!itm.is_wipe_tower; }); placers[j - 1].clearItems([](const Item &itm) { return itm.is_extrusion_cali_object; });
placers[j - 1].preload(pconfig.m_excluded_items);
j = j - 1; j = j - 1;
continue; 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(!was_packed){
if (this->unfitindicator_ && !placers.empty()) if (this->unfitindicator_ && !placers.empty())
this->unfitindicator_(it->get().name + " not fit! height=" +std::to_string(it->get().height) this->unfitindicator_(it->get().name + " not fit! plate_id=" + std::to_string(placers.back().plateID()) + ", score=" + std::to_string(score) +
+ " ,plate_id=" + std::to_string(j) ", best_bed_id=" + std::to_string(best_bed_id) + ", score_all_plates=" + std::to_string(score_all_plates) +
+ ", score=" + std::to_string(score) ", item.bed_id=" + std::to_string(it->get().binId()));
+ ", best_bed_id=" + std::to_string(best_bed_id) if (!placers.empty() && placers.back().getItems().empty()) {
+ ", score_all_plates=" + std::to_string(score_all_plates) it->get().binId(BIN_ID_UNFIT);
+", item.bed_id=" + std::to_string(it->get().binId())); 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
placers.emplace_back(bin); if (placers.size() > 1) placers.pop_back();
placers.back().plateID(placers.size() - 1); break;
placers.back().configure(pconfig); }
if (fixed_bins.size() >= placers.size()) if (placers.size() < MAX_NUM_PLATES) {
placers.back().preload(fixed_bins[placers.size() - 1]); placers.emplace_back(bin);
//placers.back().preload(pconfig.m_excluded_items); placers.back().plateID(placers.size() - 1);
packed_bins_.emplace_back(); placers.back().configure(pconfig);
j = placers.size() - 1; 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;
}
} }
} }
} }

View File

@ -443,7 +443,7 @@ inline void offset(PolygonImpl& sh, bp2d::Coord distance)
#ifndef DISABLE_BOOST_SERIALIZE #ifndef DISABLE_BOOST_SERIALIZE
template<> inline std::string serialize<libnest2d::Formats::SVG>( template<> inline std::string serialize<libnest2d::Formats::SVG>(
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::stringstream ss;
std::string style = "fill: "+fill+"; stroke: "+stroke+"; stroke-width: "+std::to_string(stroke_width)+"px; "; std::string style = "fill: "+fill+"; stroke: "+stroke+"; stroke-width: "+std::to_string(stroke_width)+"px; ";
@ -478,7 +478,14 @@ template<> inline std::string serialize<libnest2d::Formats::SVG>(
ss << svg_data << std::endl; 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("<g ");
if (pos != std::string::npos) { svg_content.insert(pos + 3, "id=\"" + name + "\" ");
}
}
return svg_content;
} }
#endif #endif

View File

@ -38,6 +38,8 @@ public:
inline Radians angleToX() const { inline Radians angleToX() const {
double ret = std::atan2(getY(axis_), getX(axis_)); double ret = std::atan2(getY(axis_), getX(axis_));
// horizontal or vertical up-right rectangles are not distinguished, but we need to get the horizontal one
if (abs(ret) < EPSILON && abs(bottom_) < abs(right_)) ret += Pi / 2;
auto s = std::signbit(ret); auto s = std::signbit(ret);
if(s) ret += Pi_2; if(s) ret += Pi_2;
return -ret; return -ret;

View File

@ -31,7 +31,7 @@ public:
double x0, y0; double x0, y0;
Config(): Config():
origo_location(BOTTOMLEFT), mm_in_coord_units(1000000), origo_location(BOTTOMLEFT), mm_in_coord_units(1000000),
width(500), height(500),x0(100) {} width(500), height(500),x0(100),y0(0) {}
}; };
@ -47,14 +47,15 @@ public:
void setSize(const Box &box) { void setSize(const Box &box) {
conf_.x0 = box.width() / 5; conf_.x0 = box.width() / 5;
conf_.x0 = box.height() / 5; conf_.y0 = box.height() / 5;
conf_.height = static_cast<double>(box.height() + conf_.y0*2) / conf_.height = static_cast<double>(box.height() + conf_.y0*2) /
conf_.mm_in_coord_units; conf_.mm_in_coord_units;
conf_.width = static_cast<double>(box.width() + conf_.x0*2) / conf_.width = static_cast<double>(box.width() + conf_.x0*2) /
conf_.mm_in_coord_units; 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(svg_layers_.empty()) addLayer();
if(conf_.origo_location == BOTTOMLEFT) { if(conf_.origo_location == BOTTOMLEFT) {
auto d = static_cast<Coord>( auto d = static_cast<Coord>(
@ -74,13 +75,14 @@ public:
} }
} }
currentLayer() += currentLayer() +=
shapelike::serialize<Formats::SVG>(tsh, shapelike::serialize<Formats::SVG>(tsh, name,
1.0 / conf_.mm_in_coord_units, fill, stroke, stroke_width) + 1.0 / conf_.mm_in_coord_units, fill, stroke, stroke_width) +
"\n"; "\n";
} }
void writeItem(const Item& item, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) { void writeItem(const Item &item, const std::string &name = "", std::string fill = "none", std::string stroke = "black", float stroke_width = 1)
writeShape(item.transformedShape(), fill, stroke, stroke_width); {
writeShape(item.transformedShape(), name, fill, stroke, stroke_width);
} }
void writePackGroup(const PackGroup& result) { void writePackGroup(const PackGroup& result) {
@ -97,7 +99,7 @@ public:
auto it = from; auto it = from;
PackGroup pg; PackGroup pg;
while(it != to) { 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(); while(pg.size() <= size_t(it->binId())) pg.emplace_back();
pg[it->binId()].emplace_back(*it); pg[it->binId()].emplace_back(*it);
++it; ++it;
@ -159,6 +161,8 @@ public:
currentLayer() += "<!-- " + comment + " -->\n"; currentLayer() += "<!-- " + comment + " -->\n";
} }
void clear() { svg_layers_.clear(); }
private: private:
std::string& currentLayer() { return svg_layers_.back(); } std::string& currentLayer() { return svg_layers_.back(); }

View File

@ -192,6 +192,7 @@ void fill_config(PConf& pcfg, const ArrangeParams &params) {
// Allow parallel execution. // Allow parallel execution.
pcfg.parallel = params.parallel; pcfg.parallel = params.parallel;
pcfg.save_svg = params.save_svg;
// BBS: excluded regions in BBS bed // BBS: excluded regions in BBS bed
for (auto& poly : params.excluded_regions) for (auto& poly : params.excluded_regions)
@ -548,18 +549,18 @@ protected:
score += height_score / valid_items_cnt; score += height_score / valid_items_cnt;
} }
std::set<int> extruder_ids; std::map<int, std::string> extruder_id_types;
std::set<int> tpu_extruder_ids; std::set<int> tpu_extruder_ids;
for (int i = 0; i < m_items.size(); i++) { for (int i = 0; i < m_items.size(); i++) {
Item& p = m_items[i]; Item& p = m_items[i];
if (p.is_virt_object) continue; if (p.is_virt_object) continue;
extruder_ids.insert(p.extrude_ids.begin(),p.extrude_ids.end()); extruder_id_types.insert(p.extrude_id_filament_types.begin(), p.extrude_id_filament_types.end());
for (int j = 0; j < p.extrude_ids.size(); j++) { for (auto id_type : p.extrude_id_filament_types) {
if (p.filament_types[j] == "TPU") tpu_extruder_ids.insert(p.extrude_ids[j]); if (id_type.second == "TPU") tpu_extruder_ids.insert(id_type.first);
} }
} }
for (int j = 0; j < item.extrude_ids.size(); j++) { for (auto id_type : item.extrude_id_filament_types) {
if (item.filament_types[j] == "TPU") tpu_extruder_ids.insert(item.extrude_ids[j]); if (id_type.second == "TPU") tpu_extruder_ids.insert(id_type.first);
} }
// do not allow more than 1 TPU extruder on same plate // 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 // add a large cost if not multi materials on same plate is not allowed
else if (!params.allow_multi_materials_on_same_plate) { else if (!params.allow_multi_materials_on_same_plate) {
// it's the first object, which can be multi-color // 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 // 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<int> item_extruder_ids(item.extrude_ids.begin(), item.extrude_ids.end()); bool same_color_with_previous_items = std::includes(extruder_id_types.begin(), extruder_id_types.end(), item.extrude_id_filament_types.begin(),
bool same_color_with_previous_items = std::includes(extruder_ids.begin(), extruder_ids.end(), item_extruder_ids.begin(), item_extruder_ids.end()); item.extrude_id_filament_types.end());
if (!(first_object || same_color_with_previous_items)) score += LARGE_COST_TO_REJECT * 1.3; 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 // for layered printing, we want extruder change as few as possible
// this has very weak effect, CAN NOT use a large weight // this has very weak effect, CAN NOT use a large weight
int last_extruder_cnt = extruder_ids.size(); int last_extruder_cnt = extruder_id_types.size();
extruder_ids.insert(item.extrude_ids.begin(), item.extrude_ids.end()); extruder_id_types.insert(item.extrude_id_filament_types.begin(), item.extrude_id_filament_types.end());
int new_extruder_cnt= extruder_ids.size(); int new_extruder_cnt = extruder_id_types.size();
if (!params.is_seq_print) { if (!params.is_seq_print) {
score += 1 * (new_extruder_cnt-last_extruder_cnt); 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) : return i1.bed_temp != i2.bed_temp ? (i1.bed_temp > i2.bed_temp) :
i1.height != i2.height ? (i1.height < i2.height) : i1.height != i2.height ? (i1.height < i2.height) :
std::abs(i1.area() / i2.area() - 1) > 0.2 ? (i1.area() > i2.area()) : 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 { else {
// single color objects first, then objects with more colors // single color objects first, then objects with more colors
if (i1.extrude_ids.size() != i2.extrude_ids.size()) { if (i1.extrude_id_filament_types.size() != i2.extrude_id_filament_types.size()) {
if (i1.extrude_ids.size() == 1 || i2.extrude_ids.size() == 1) if (i1.extrude_id_filament_types.size() == 1 || i2.extrude_id_filament_types.size() == 1)
return i1.extrude_ids.size() == 1; return i1.extrude_id_filament_types.size() == 1;
else else
return i1.extrude_ids.size() > i2.extrude_ids.size(); return i1.extrude_id_filament_types.size() > i2.extrude_id_filament_types.size();
} }
else else
return i1.bed_temp != i2.bed_temp ? (i1.bed_temp > i2.bed_temp) : 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: std::abs(i1.height/params.printable_height - i2.height/params.printable_height)>0.05 ? i1.height > i2.height:
(i1.area() > i2.area()); (i1.area() > i2.area());
} }
@ -883,7 +884,8 @@ void _arrange(
try { try {
auto bbox = minAreaBoundingBox<ExPolygon, TCompute<ExPolygon>, boost::rational<LargeInt>>(itm.transformedShape()); auto bbox = minAreaBoundingBox<ExPolygon, TCompute<ExPolygon>, boost::rational<LargeInt>>(itm.transformedShape());
auto w = bbox.width(), h = bbox.height(); 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) { } catch (const std::exception &e) {
// min_area_boundingbox_rotation may throw exception of dividing 0 if the object is already perfectly aligned to X // 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<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn}; AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn};
remove_large_items(excludes, corrected_bin);
// If there is something on the plate // If there is something on the plate
if (!excludes.empty()) arranger.preload(excludes); if (!excludes.empty()) arranger.preload(excludes);
@ -992,13 +992,13 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
item.binId(arrpoly.bed_idx); item.binId(arrpoly.bed_idx);
item.priority(arrpoly.priority); item.priority(arrpoly.priority);
item.itemId(arrpoly.itemid); item.itemId(arrpoly.itemid);
item.extrude_ids = arrpoly.extrude_ids; item.extrude_id_filament_types = arrpoly.extrude_id_filament_types;
item.filament_types = arrpoly.filament_types;
item.height = arrpoly.height; item.height = arrpoly.height;
item.name = arrpoly.name; item.name = arrpoly.name;
//BBS: add virtual object logic //BBS: add virtual object logic
item.is_virt_object = arrpoly.is_virt_object; item.is_virt_object = arrpoly.is_virt_object;
item.is_wipe_tower = arrpoly.is_wipe_tower; 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.bed_temp = arrpoly.first_bed_temp;
item.print_temp = arrpoly.print_temp; item.print_temp = arrpoly.print_temp;
item.vitrify_temp = arrpoly.vitrify_temp; item.vitrify_temp = arrpoly.vitrify_temp;

View File

@ -61,8 +61,7 @@ struct ArrangePolygon {
//BBS: add row/col for sudoku-style layout //BBS: add row/col for sudoku-style layout
int row{0}; int row{0};
int col{0}; int col{0};
std::vector<int> extrude_ids{}; /// extruder_id for least extruder switch std::map<int, std::string> extrude_id_filament_types; /// extruder_id for least extruder switch, filament type for different material judge
std::vector<std::string> filament_types{}; /// filament type for different material judge
int filament_temp_type{ -1 }; int filament_temp_type{ -1 };
int bed_temp{0}; ///bed temperature for different material judge int bed_temp{0}; ///bed temperature for different material judge
int print_temp{0}; ///print 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 avoid_extrusion_cali_region = true;
bool is_seq_print = false; bool is_seq_print = false;
bool align_to_y_axis = false; bool align_to_y_axis = false;
bool save_svg = false;
float bed_shrink_x = 0.1; float bed_shrink_x = 0.1;
float bed_shrink_y = 0.1; float bed_shrink_y = 0.1;
float brim_skirt_distance = 0; float brim_skirt_distance = 0;

View File

@ -76,6 +76,7 @@ namespace Slic3r {
//! return same string //! return same string
#define L(s) (s) #define L(s) (s)
#define _(s) Slic3r::I18N::translate(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_min_purge_volume = 100.f;
static const float g_purge_volume_one_time = 135.f; static const float g_purge_volume_one_time = 135.f;
@ -2888,7 +2889,7 @@ void GCode::process_layers(
else { else {
tbb::parallel_pipeline(12, generator & parsing & cooling & build_node); tbb::parallel_pipeline(12, generator & parsing & cooling & build_node);
std::string message; std::string message;
message = L("Smoothing z direction speed"); message = _L("Smoothing z direction speed");
m_print->set_status(85, message); m_print->set_status(85, message);
//append data //append data
for (const LayerResult &res : layers_results) { for (const LayerResult &res : layers_results) {
@ -2900,7 +2901,7 @@ void GCode::process_layers(
} }
smooth_calculator.smooth_layer_speed(); smooth_calculator.smooth_layer_speed();
message = L("Exporting G-code"); message = _L("Exporting G-code");
m_print->set_status(90, message); m_print->set_status(90, message);
tbb::parallel_pipeline(12, calculate_layer_time & write_gocde & output); tbb::parallel_pipeline(12, calculate_layer_time & write_gocde & output);
} }

View File

@ -3596,12 +3596,13 @@ void Model::setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConf
} }
// find temperature of heatend and bed and matierial of an given extruder // 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(); extruderParamsMap.clear();
//Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config(); //Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
// BBS // BBS
//int numExtruders = wxGetApp().preset_bundle->filament_presets.size(); //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 = ""; std::string matName = "";
// BBS // BBS
int bedTemp = 35; int bedTemp = 35;
@ -3973,6 +3974,9 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf
ret.rotation = 0; ret.rotation = 0;
// BBS: add materials related information // 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; ModelVolume *volume = NULL;
for (size_t i = 0; i < object->volumes.size(); ++i) { for (size_t i = 0; i < object->volumes.size(); ++i) {
if (object->volumes[i]->is_model_part()) { if (object->volumes[i]->is_model_part()) {
@ -3982,7 +3986,9 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf
return; return;
} }
auto ve = object->volumes[i]->get_extruders(); 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<ConfigOptionInt>(config_global, "support_interface_filament"); auto op2 = object->get_config_value<ConfigOptionInt>(config_global, "support_interface_filament");
int extruder_id; int extruder_id;
// id==0 means follow previous material, so need not be recorded // 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 (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_ids.push_back(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_id_filament_types.empty()) // the default extruder
if (ret.extrude_ids.empty()) // the default extruder ret.extrude_id_filament_types.insert({1, get_filament_name(1)});
ret.extrude_ids.push_back(1);
// filament types must be same size as extrude_ids
ret.filament_types.resize(ret.extrude_ids.size(), "PLA");
} }
void ModelInstance::apply_arrange_result(const Vec2d &offs, double rotation) void ModelInstance::apply_arrange_result(const Vec2d &offs, double rotation)

View File

@ -1623,7 +1623,7 @@ public:
static Polygon getBedPolygon() { return Model::printSpeedMap.bed_poly; } static Polygon getBedPolygon() { return Model::printSpeedMap.bed_poly; }
//BBS static functions that update extruder params and speed table //BBS static functions that update extruder params and speed table
static void setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConfig& print_config); 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 // BBS: backup
static Model read_from_archive( static Model read_from_archive(

View File

@ -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 get_instance_arrange_poly(ModelInstance* instance, const Slic3r::DynamicPrintConfig& config)
{ {
ArrangePolygon ap = get_arrange_poly(PtrWrapper{ instance }, 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 //BBS: add temperature information
if (config.has("curr_bed_type")) { if (config.has("curr_bed_type")) {
ap.bed_temp = 0; ap.bed_temp = 0;
@ -127,29 +127,28 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::
BedType curr_bed_type = config.opt_enum<BedType>("curr_bed_type"); BedType curr_bed_type = config.opt_enum<BedType>("curr_bed_type");
const ConfigOptionInts* bed_opt = config.option<ConfigOptionInts>(get_bed_temp_key(curr_bed_type)); const ConfigOptionInts* bed_opt = config.option<ConfigOptionInts>(get_bed_temp_key(curr_bed_type));
if (bed_opt != nullptr) if (bed_opt != nullptr) ap.bed_temp = bed_opt->get_at(first_extruder_id);
ap.bed_temp = bed_opt->get_at(ap.extrude_ids.front()-1);
const ConfigOptionInts* bed_opt_1st_layer = config.option<ConfigOptionInts>(get_bed_temp_1st_layer_key(curr_bed_type)); const ConfigOptionInts* bed_opt_1st_layer = config.option<ConfigOptionInts>(get_bed_temp_1st_layer_key(curr_bed_type));
if (bed_opt_1st_layer != nullptr) 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 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 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")) { 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 // get filament temp types
auto* filament_types_opt = dynamic_cast<const ConfigOptionStrings*>(config.option("filament_type")); auto* filament_types_opt = dynamic_cast<const ConfigOptionStrings*>(config.option("filament_type"));
if (filament_types_opt) { if (filament_types_opt) {
std::set<int> filament_temp_types; std::set<int> filament_temp_types;
for (auto i : ap.extrude_ids) { for (auto id : ap.extrude_id_filament_types) {
std::string type_str = filament_types_opt->get_at(i-1); std::string type_str = filament_types_opt->get_at(id.first-1);
int temp_type = Print::get_filament_temp_type(type_str); int temp_type = Print::get_filament_temp_type(type_str);
filament_temp_types.insert(temp_type); filament_temp_types.insert(temp_type);
} }

View File

@ -1,31 +1,38 @@
#pragma once #pragma once
#include <Eigen/Core>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
// custom vector wrapper for outputting to log // custom vector wrapper for outputting to log
template<typename T> struct VectorFormatter template<typename Container> struct VectorFormatter
{ {
const std::vector<T>* vec = nullptr; const Container &vec;
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>* mat = nullptr; explicit VectorFormatter(const Container& v) : vec(v) {}
explicit VectorFormatter(const std::vector<T>& v) : vec(&v) {}
explicit VectorFormatter(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) : mat(&m) {}
friend std::ostream& operator<<(std::ostream& os, const VectorFormatter<T>& vf) friend std::ostream &operator<<(std::ostream &os, const VectorFormatter<Container> &vf)
{ {
os << "["; os << "[";
if (vf.vec) { for (auto it = vf.vec.begin(); it != vf.vec.end();it++) {
for (size_t i = 0; i < vf.vec->size(); ++i) { os << *it;
os << (*vf.vec)[i]; if (std::next(it) != vf.vec.end()) { os << ", "; }
if (i != vf.vec->size() - 1) { os << ", "; } }
} os << "]";
} return os;
else { }
for (int i = 0; i < vf.mat->size(); ++i) { };
os << (*vf.mat)(i);
if (i != vf.mat->size() - 1) { os << ", "; } // custom vector wrapper for outputting to log
} template<typename T1, typename T2> struct MapFormatter
{
const std::map<T1, T2> &vec;
explicit MapFormatter(const std::map<T1, T2> &v) : vec(v) {}
friend std::ostream &operator<<(std::ostream &os, const MapFormatter<T1,T2> &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 << "]"; os << "]";
return os; return os;

View File

@ -3535,6 +3535,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
int keyCode = evt.GetKeyCode(); int keyCode = evt.GetKeyCode();
int ctrlMask = wxMOD_CONTROL; int ctrlMask = wxMOD_CONTROL;
int shiftMask = wxMOD_SHIFT; int shiftMask = wxMOD_SHIFT;
int altMask = wxMOD_ALT;
auto imgui = wxGetApp().imgui(); auto imgui = wxGetApp().imgui();
if (imgui->update_key_data(evt)) { if (imgui->update_key_data(evt)) {
@ -3758,6 +3759,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
{ {
if ((evt.GetModifiers() & shiftMask) != 0) if ((evt.GetModifiers() & shiftMask) != 0)
post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE_PARTPLATE)); post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE_PARTPLATE));
else if ((evt.GetModifiers() & altMask) != 0)
post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE_OUTPLATE));
else else
post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE));
break; 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 multi_material_key = "allow_multi_materials_on_same_plate";
std::string avoid_extrusion_key = "avoid_extrusion_cali_region"; std::string avoid_extrusion_key = "avoid_extrusion_cali_region";
std::string align_to_y_axis_key = "align_to_y_axis"; std::string align_to_y_axis_key = "align_to_y_axis";
std::string save_svg_key = "save_svg";
std::string postfix = settings.postfix; std::string postfix = settings.postfix;
//BBS: //BBS:
bool seq_print = settings.is_seq_print; 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->text(_L("0 means auto spacing."));
ImGui::Separator(); 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)) { if (imgui->bbl_checkbox(_L("Auto rotate for arrangement"), settings.enable_rotation)) {
settings_out.enable_rotation = settings.enable_rotation; settings_out.enable_rotation = settings.enable_rotation;
appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0"); 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 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 // BBS: add partplate logic
DynamicConfig& proj_cfg = wxGetApp().preset_bundle->project_config; DynamicConfig& proj_cfg = wxGetApp().preset_bundle->project_config;
Vec3d plate_origin = wxGetApp().plater()->get_partplate_list().get_plate(m_plate_idx)->get_origin(); Vec3d plate_origin = wxGetApp().plater()->get_partplate_list().get_plate(m_plate_idx)->get_origin();

View File

@ -528,6 +528,7 @@ public:
//BBS: add more arrangeSettings //BBS: add more arrangeSettings
bool is_seq_print = false; bool is_seq_print = false;
bool align_to_y_axis = false; bool align_to_y_axis = false;
bool save_svg = false; // for debug
std::string postfix; std::string postfix;
void reset() void reset()
{ {

View File

@ -111,26 +111,6 @@ ArrangePolygon ArrangeJob::prepare_arrange_polygon(void *model_instance)
auto preset_bundle = wxGetApp().preset_bundle; auto preset_bundle = wxGetApp().preset_bundle;
const Slic3r::DynamicPrintConfig& config = preset_bundle->full_config(); const Slic3r::DynamicPrintConfig& config = preset_bundle->full_config();
ArrangePolygon ap = get_instance_arrange_poly(instance, 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; return ap;
} }
@ -328,9 +308,7 @@ void ArrangeJob::prepare_wipe_tower(bool select)
// estimate if we need wipe tower for all plates: // 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) // need wipe tower if some object has multiple extruders (has paint-on colors or support material)
for (const auto& item : m_selected) { for (const auto& item : m_selected) {
std::set<int> obj_extruders; if (item.extrude_id_filament_types.size() > 1) {
obj_extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end());
if (obj_extruders.size() > 1) {
need_wipe_tower = true; need_wipe_tower = true;
ARRANGE_LOG(info) << "need wipe tower because object " << item.name << " has multiple extruders (has paint-on colors)"; ARRANGE_LOG(info) << "need wipe tower because object " << item.name << " has multiple extruders (has paint-on colors)";
break; break;
@ -342,7 +320,7 @@ void ArrangeJob::prepare_wipe_tower(bool select)
if (params.allow_multi_materials_on_same_plate) { if (params.allow_multi_materials_on_same_plate) {
std::map<int, std::set<int>> bedTemp2extruderIds; std::map<int, std::set<int>> bedTemp2extruderIds;
for (const auto& item : m_selected) 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) { for (const auto& be : bedTemp2extruderIds) {
if (be.second.size() > 1) { if (be.second.size() > 1) {
need_wipe_tower = true; 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); bool in_plate = plate->contain_instance(oidx, inst_idx) || plate->intersect_instance(oidx, inst_idx);
ArrangePolygon&& ap = prepare_arrange_polygon(mo->instances[inst_idx]); ArrangePolygon&& ap = prepare_arrange_polygon(mo->instances[inst_idx]);
ArrangePolygons& cont = mo->instances[inst_idx]->printable ? ArrangePolygons &cont = mo->instances[inst_idx]->printable ? m_selected : m_unprintable;
(in_plate ? m_selected : m_unselected) :
m_unprintable;
bool locked = plate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate); 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(); ap.itemid = cont.size();
cont.emplace_back(std::move(ap)); cont.emplace_back(std::move(ap));
@ -510,9 +486,10 @@ void ArrangeJob::prepare_outside_plate() {
} }
if (iter2 != all_outside_objects.end()) { if (iter2 != all_outside_objects.end()) {
outside_plate = true; outside_plate = true;
ARRANGE_LOG(debug) << object->name << " is outside!";
} }
ArrangePolygon&& ap = prepare_arrange_polygon(instance); 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(); ap.itemid = cont.size();
if (!outside_plate) { if (!outside_plate) {
plate_list.preprocess_arrange_polygon(obj_idx, inst_idx, ap, false); 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(); const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
auto& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); auto& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print();
auto print_config = print.config(); 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); Model::setPrintSpeedTable(config, print_config);
int state = m_plater->get_prepare_state(); int state = m_plater->get_prepare_state();
@ -602,7 +579,7 @@ void ArrangeJob::prepare()
if (!m_selected.empty()) { if (!m_selected.empty()) {
m_plater->get_notification_manager()->push_notification(NotificationType::ArrangeOngoing, NotificationManager::NotificationLevel::RegularNotificationLevel, 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(); 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)); 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(warning)<< "full params: "<< params.to_json();
ARRANGE_LOG(info) << boost::format("items selected before arranging: %1%") % m_selected.size(); ARRANGE_LOG(info) << boost::format("items selected before arranging: %1%") % m_selected.size();
for (auto selected : m_selected) { for (auto selected : m_selected) {
ARRANGE_LOG(debug) << selected.name << ", extruder: " << VectorFormatter(selected.extrude_ids) ARRANGE_LOG(debug) << selected.name << ", extruder: " << MapFormatter(selected.extrude_id_filament_types) << ", bed: " << selected.bed_idx
<< ", filament types: " << VectorFormatter(selected.filament_types) << ", bed: " << selected.bed_idx << ", filemant_type:" << selected.filament_temp_type << ", trans: " << unscale<double>(selected.translation(X)) << ","
<< ", filemant_type:" << selected.filament_temp_type << ", trans: " << unscale<double>(selected.translation(X)) << "," << unscale<double>(selected.translation(Y)) << ", rotation: " << selected.rotation;
<< unscale<double>(selected.translation(Y)) << ", rotation: " << selected.rotation;
} }
ARRANGE_LOG(debug) << "items unselected before arrange: " << unselected_and_locked.size(); ARRANGE_LOG(debug) << "items unselected before arrange: " << m_unselected.size();
for (auto item : unselected_and_locked) for (auto item : m_unselected)
ARRANGE_LOG(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale<double>(item.translation(X)) << "," << unscale<double>(item.translation(Y)); BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale<double>(item.translation(X)) << ","
<< unscale<double>(item.translation(Y));
} }
arrangement::arrange(m_selected, unselected_and_locked, bedpts, params); arrangement::arrange(m_selected, m_unselected, bedpts, params);
// sort by item id // sort by item id
std::sort(m_selected.begin(), m_selected.end(), [](auto a, auto b) {return a.itemid < b.itemid; }); 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(); ARRANGE_LOG(info) << boost::format("items selected after arranging: %1%") % m_selected.size();
for (auto selected : m_selected) 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 << ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp
<< ", trans: " << unscale<double>(selected.translation(X)) << "," << unscale<double>(selected.translation(Y)) << ", trans: " << unscale<double>(selected.translation(X)) << "," << unscale<double>(selected.translation(Y))
<< ", rotation: " << selected.rotation; << ", rotation: " << selected.rotation;
ARRANGE_LOG(debug) << "items unselected after arrange: " << unselected_and_locked.size(); ARRANGE_LOG(debug) << "items unselected after arrange: " << m_unselected.size();
for (auto item : unselected_and_locked) for (auto item : m_unselected)
ARRANGE_LOG(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale<double>(item.translation(X)) << "," << unscale<double>(item.translation(Y)); BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << unscale<double>(item.translation(X)) << "," << unscale<double>(item.translation(Y));
} }
// put unpackable items to m_unprintable so they goes outside // put unpackable items to m_unprintable so they goes outside
@ -752,7 +727,7 @@ void ArrangeJob::finalize()
beds = std::max(ap.bed_idx, beds); 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<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name; ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": selected %4%: bed_id %1%, trans {%2%, %3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
} }
//BBS: adjust the bed_index, create new plates, get the max bed_index //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); plate_list.postprocess_bed_index_for_unselected(ap);
beds = std::max(ap.bed_idx, beds); 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<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name; ARRANGE_LOG(debug) << __FUNCTION__ << boost::format(": unselected %4%: bed_id %1%, trans {%2%, %3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
} }
for (ArrangePolygon& ap : m_locked) { 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.is_seq_print = settings.is_seq_print;
params.min_obj_distance = scaled(settings.distance); params.min_obj_distance = scaled(settings.distance);
params.align_to_y_axis = settings.align_to_y_axis; 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(); int state = p->get_prepare_state();
if (state == Job::JobPrepareState::PREPARE_STATE_MENU) { if (state == Job::JobPrepareState::PREPARE_STATE_MENU) {

View File

@ -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(); const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
auto& print = q->get_partplate_list().get_current_fff_print(); auto& print = q->get_partplate_list().get_current_fff_print();
auto print_config = print.config(); 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); Model::setPrintSpeedTable(config, print_config);
set_current_panel(preview, no_slice); set_current_panel(preview, no_slice);
} }
@ -5740,7 +5740,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// BBS // BBS
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_LOAD_MODEL_OBJECTS \n"); 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++; model_idx++;
dlg_cont = dlg.Update(progress_percent, msg); dlg_cont = dlg.Update(progress_percent, msg);
if (!dlg_cont) { if (!dlg_cont) {
@ -8666,9 +8666,9 @@ void Plater::priv::on_action_slice_plate(SimpleEvent&)
const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
auto& print = q->get_partplate_list().get_current_fff_print(); auto& print = q->get_partplate_list().get_current_fff_print();
auto print_config = print.config(); 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); Model::setPrintSpeedTable(config, print_config);
m_slice_all = false; m_slice_all = false;
q->reslice(); q->reslice();
@ -8685,9 +8685,9 @@ void Plater::priv::on_action_slice_all(SimpleEvent&)
const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config(); const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
auto& print = q->get_partplate_list().get_current_fff_print(); auto& print = q->get_partplate_list().get_current_fff_print();
auto print_config = print.config(); 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); Model::setPrintSpeedTable(config, print_config);
m_slice_all = true; m_slice_all = true;
m_slice_all_only_has_gcode = true; m_slice_all_only_has_gcode = true;