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:
parent
e02f44d8dd
commit
2fd184f754
|
@ -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;
|
||||
|
|
|
@ -656,7 +656,7 @@ inline std::string toString(const S& /*sh*/)
|
|||
}
|
||||
|
||||
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,
|
||||
"shapelike::serialize() unimplemented!");
|
||||
|
|
|
@ -75,8 +75,7 @@ class _Item {
|
|||
|
||||
public:
|
||||
int itemid_{ 0 };
|
||||
std::vector<int> extrude_ids;
|
||||
std::vector<std::string> filament_types{}; /// filament type for different material judge
|
||||
std::map<int, std::string> 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<double> allowed_rotations{0.};
|
||||
|
||||
/// The type of the shape which was handed over as the template argument.
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "placer_boilerplate.hpp"
|
||||
|
||||
// temporary
|
||||
//#include "../tools/svgtools.hpp"
|
||||
//#include <iomanip> // setprecision
|
||||
#include "../tools/svgtools.hpp"
|
||||
#include <iomanip> // setprecision
|
||||
|
||||
#include <libnest2d/parallel.hpp>
|
||||
|
||||
|
@ -690,6 +690,18 @@ private:
|
|||
|
||||
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>>
|
||||
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<MaxNfpLevel::value>());
|
||||
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<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 (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<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) {
|
||||
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<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 (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<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 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<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;
|
||||
for (Item &item : items_) {
|
||||
if (item.isFixed()) {
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
|
||||
std::vector<Placer> 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<bool(Item& i1, Item& i2)> 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<Placer>(store_, bin, pconfig);
|
||||
|
||||
//this->template remove_unpackable_items<Placer>(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<double>::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() && j<MAX_NUM_PLATES; j++) {
|
||||
if (it->get().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -443,7 +443,7 @@ inline void offset(PolygonImpl& sh, bp2d::Coord distance)
|
|||
|
||||
#ifndef DISABLE_BOOST_SERIALIZE
|
||||
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::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;
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
|
||||
inline Radians angleToX() const {
|
||||
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);
|
||||
if(s) ret += Pi_2;
|
||||
return -ret;
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
double x0, y0;
|
||||
Config():
|
||||
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) {
|
||||
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_.mm_in_coord_units;
|
||||
conf_.width = static_cast<double>(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<Coord>(
|
||||
|
@ -74,13 +75,14 @@ public:
|
|||
}
|
||||
}
|
||||
currentLayer() +=
|
||||
shapelike::serialize<Formats::SVG>(tsh,
|
||||
shapelike::serialize<Formats::SVG>(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() += "<!-- " + comment + " -->\n";
|
||||
}
|
||||
|
||||
void clear() { svg_layers_.clear(); }
|
||||
|
||||
private:
|
||||
|
||||
std::string& currentLayer() { return svg_layers_.back(); }
|
||||
|
|
|
@ -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<int> extruder_ids;
|
||||
std::map<int, std::string> extruder_id_types;
|
||||
std::set<int> 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<int> 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<ExPolygon, TCompute<ExPolygon>, boost::rational<LargeInt>>(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<BinT> 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;
|
||||
|
|
|
@ -61,8 +61,7 @@ struct ArrangePolygon {
|
|||
//BBS: add row/col for sudoku-style layout
|
||||
int row{0};
|
||||
int col{0};
|
||||
std::vector<int> extrude_ids{}; /// extruder_id for least extruder switch
|
||||
std::vector<std::string> filament_types{}; /// filament type for different material judge
|
||||
std::map<int, std::string> 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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<ConfigOptionInt>(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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<BedType>("curr_bed_type");
|
||||
|
||||
const ConfigOptionInts* bed_opt = config.option<ConfigOptionInts>(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<ConfigOptionInts>(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<const ConfigOptionStrings*>(config.option("filament_type"));
|
||||
if (filament_types_opt) {
|
||||
std::set<int> 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);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// custom vector wrapper for outputting to log
|
||||
template<typename T> struct VectorFormatter
|
||||
template<typename Container> struct VectorFormatter
|
||||
{
|
||||
const std::vector<T>* vec = nullptr;
|
||||
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>* mat = nullptr;
|
||||
explicit VectorFormatter(const std::vector<T>& v) : vec(&v) {}
|
||||
explicit VectorFormatter(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) : mat(&m) {}
|
||||
const Container &vec;
|
||||
explicit VectorFormatter(const Container& v) : vec(v) {}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const VectorFormatter<T>& vf)
|
||||
friend std::ostream &operator<<(std::ostream &os, const VectorFormatter<Container> &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<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 << "]";
|
||||
return os;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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<int> 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<int, std::set<int>> 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<double>(selected.translation(X)) << ","
|
||||
<< unscale<double>(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<double>(selected.translation(X)) << ","
|
||||
<< unscale<double>(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<double>(item.translation(X)) << "," << unscale<double>(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<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
|
||||
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<double>(selected.translation(X)) << "," << unscale<double>(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<double>(item.translation(X)) << "," << unscale<double>(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<double>(item.translation(X)) << "," << unscale<double>(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<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
|
||||
|
@ -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<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) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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<size_t> Plater::priv::load_files(const std::vector<fs::path>& 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;
|
||||
|
|
Loading…
Reference in New Issue