From dd473bdc3f0953b14a3d2a9433d7e043cf8ada96 Mon Sep 17 00:00:00 2001 From: manch1n Date: Fri, 7 Apr 2023 21:52:59 +0800 Subject: [PATCH] FIX: avoid wipe tower conflict with objects Use a more accurate way to estimate wipe tower: 1. read wipe configure from front-end (the positions may be different at different plates). 2. when depth is unavailable, use all materials to estimate depth (the estimated wipe tower may be larger than the actual generated one). Change-Id: I42ffd03d9817b57f5023a6820cda0032509c6fe5 (cherry picked from commit 77ba9757023afb9160c996eeea6ead8a27b50ce4) --- .../include/libnest2d/placers/nfpplacer.hpp | 32 +++++++------------ src/libslic3r/Arrange.cpp | 10 +++--- src/libslic3r/Model.cpp | 12 ++++--- src/slic3r/GUI/GLCanvas3D.cpp | 30 +++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 3 ++ src/slic3r/GUI/Jobs/ArrangeJob.cpp | 19 ++++++++--- 6 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 56aa3fdd8..863dcb43c 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -1064,27 +1064,9 @@ private: if (!item.is_virt_object) bb = sl::boundingBox(item.boundingBox(), bb); - // if move to center is infeasible, move to topright corner instead - auto alignment = config_.alignment; - if (!config_.m_excluded_regions.empty() && alignment== Config::Alignment::CENTER) { - Box bb2 = bb; - auto d = bbin.center() - bb2.center(); - d.x() = std::max(d.x(), 0); - d.y() = std::max(d.y(), 0); - bb2.minCorner() += d; - bb2.maxCorner() += d; - for (auto& region : config_.m_excluded_regions) { - auto region_bb = region.boundingBox(); - if (bb2.intersection(region_bb).area()>0) { - alignment = Config::Alignment::TOP_RIGHT; - break; - } - } - } - Vertex ci, cb; - switch(alignment) { + switch(config_.alignment) { case Config::Alignment::CENTER: { ci = bb.center(); cb = bbin.center(); @@ -1118,6 +1100,13 @@ private: // BBS make sure the item won't clash with excluded regions if(1) { + // do we have wipe tower after arranging? + std::set extruders; + for (const Item& item : items_) { + if (!item.is_virt_object) { extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); } + } + bool need_wipe_tower = extruders.size() > 1; + std::vector objs,excludes; for (const Item &item : items_) { if (item.isFixed()) continue; @@ -1127,7 +1116,10 @@ private: if (objs.size() != 0) { for (const Item &item : config_.m_excluded_regions) { excludes.push_back(item.transformedShape()); } for (const Item &item : items_) { - if (item.isFixed()) { excludes.push_back(item.transformedShape()); } + if (item.isFixed()) { + if (!(item.is_wipe_tower && !need_wipe_tower)) + excludes.push_back(item.transformedShape()); + } } Box binbb = sl::boundingBox(bin_); auto allowShifts = calcnfp(objs_convex_hull, excludes, binbb, Lvl()); diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index ca462269b..eeb385676 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -545,11 +545,11 @@ public: auto binbb = sl::boundingBox(m_bin); // BBS: excluded region (virtual object but not wipe tower) should not affect final alignment - bool all_is_excluded_region = std::all_of(items.begin(), items.end(), [](Item &itm) { return itm.is_virt_object && !itm.is_wipe_tower; }); - if (!all_is_excluded_region) - cfg.alignment = PConfig::Alignment::DONT_ALIGN; - else - cfg.alignment = PConfig::Alignment::CENTER; + //bool all_is_excluded_region = std::all_of(items.begin(), items.end(), [](Item &itm) { return itm.is_virt_object && !itm.is_wipe_tower; }); + //if (!all_is_excluded_region) + // cfg.alignment = PConfig::Alignment::DONT_ALIGN; + //else + // cfg.alignment = PConfig::Alignment::CENTER; auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? binbb.minCorner() : binbb.center(); // if we have wipe tower, items should be arranged around wipe tower diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index f1031ee12..0af344e87 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -3360,18 +3360,20 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf return; } ret.extrude_ids = volume->get_extruders(); - if (ret.extrude_ids.empty()) //the default extruder - ret.extrude_ids.push_back(1); - // get per-object support extruders auto op = object->get_config_value(config_global, "enable_support"); bool is_support_enabled = op && op->getBool(); if (is_support_enabled) { auto op1 = object->get_config_value(config_global, "support_filament"); auto op2 = object->get_config_value(config_global, "support_interface_filament"); - if (op1) ret.extrude_ids.push_back(op1->getInt()); - if (op2) ret.extrude_ids.push_back(op2->getInt()); + 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 (ret.extrude_ids.empty()) //the default extruder + ret.extrude_ids.push_back(1); } indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4aa80e018..50224cdb9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1718,6 +1718,36 @@ bool GLCanvas3D::make_current_for_postinit() { return _set_current(); } +Points GLCanvas3D::estimate_wipe_tower_points(int plate_index) const +{ + PartPlateList & ppl = wxGetApp().plater()->get_partplate_list(); + DynamicPrintConfig &proj_cfg = wxGetApp().preset_bundle->project_config; + auto & print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); + int plate_count = ppl.get_plate_count(); + float x = dynamic_cast(proj_cfg.option("wipe_tower_x"))->get_at(plate_index); + float y = dynamic_cast(proj_cfg.option("wipe_tower_y"))->get_at(plate_index); + if (plate_index >= plate_count) { plate_index = 0; } + float w = dynamic_cast(m_config->option("prime_tower_width"))->value; + float v = dynamic_cast(m_config->option("prime_volume"))->value; + Vec3d wipe_tower_size = ppl.get_plate(plate_index)->estimate_wipe_tower_size(w, v); + + if (wipe_tower_size(1) == 0) { + // when depth is unavailable (no items on this plate), we have to estimate the depth using the extruder number of all plates + std::set extruder_ids; + auto pl = ppl.get_plate_list(); + for (const auto& p : pl) { + auto es = p->get_extruders(); + extruder_ids.insert(es.begin(), es.end()); + } + int extruder_size = extruder_ids.size(); + wipe_tower_size(1) = extruder_size * print.wipe_tower_data(extruder_size).depth + 2 * print.wipe_tower_data().brim_width; + } + Vec3d plate_origin = ppl.get_plate(plate_index)->get_origin(); + Point wt_min_corner{scale_(x), scale_(y)}; + Point wt_max_corner(scale_(x + wipe_tower_size(0)), scale_(y + wipe_tower_size(1))); + return {wt_min_corner, {wt_max_corner.x(), wt_min_corner.y()}, wt_max_corner, {wt_min_corner.x(),wt_max_corner.y()}}; +} + void GLCanvas3D::render(bool only_init) { if (m_in_render) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 0325cf6e2..37f61d071 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1058,6 +1058,9 @@ public: bool make_current_for_postinit(); + //BBS + Points estimate_wipe_tower_points(int plate_index) const; + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index dc2a5016c..b81b01516 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -241,9 +241,15 @@ void ArrangeJob::prepare_all() { } // 准备料塔。逻辑如下: -// 1. 如果料塔被禁用,或是逐件打印,则不需要料塔 -// 2. 以下两种情况需要料塔:1)某对象是多色对象;2)打开了支撑,且支撑体与接触面使用的是不同材料 -// 3. 如果允许不同材料落在相同盘,则以下情况也需要料塔:1)所有选定对象中使用了多种热床温度相同的材料(比如颜色不同的PLA) +// 1. 以下几种情况不需要料塔: +// 1)料塔被禁用, +// 2)逐件打印, +// 3)不允许不同材料落在相同盘,且没有多色对象 +// 2. 以下情况需要料塔: +// 1)某对象是多色对象; +// 2)打开了支撑,且支撑体与接触面使用的是不同材料 +// 3)允许不同材料落在相同盘,且所有选定对象中使用了多种热床温度相同的材料 +// (所有对象都是单色的,但不同对象的材料不同,例如:对象A使用红色PLA,对象B使用白色PLA) void ArrangeJob::prepare_wipe_tower() { bool need_wipe_tower = false; @@ -257,7 +263,7 @@ void ArrangeJob::prepare_wipe_tower() // need wipe tower if some object has multiple extruders (has paint-on colors or support material) for (const auto &item : m_selected) { std::set obj_extruders; - for (int id : item.extrude_ids) obj_extruders.insert(id); + obj_extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); if (obj_extruders.size() > 1) { need_wipe_tower = true; BOOST_LOG_TRIVIAL(info) << "arrange: need wipe tower because object " << item.name << " has multiple extruders (has paint-on colors)"; @@ -266,6 +272,7 @@ void ArrangeJob::prepare_wipe_tower() } // if multile extruders have same bed temp, we need wipe tower + // 允许不同材料落在相同盘,且所有选定对象中使用了多种热床温度相同的材料 if (params.allow_multi_materials_on_same_plate) { std::map> bedTemp2extruderIds; for (const auto &item : m_selected) @@ -301,9 +308,11 @@ void ArrangeJob::prepare_wipe_tower() wipe_tower_ap.is_virt_object = true; wipe_tower_ap.is_wipe_tower = true; } - + const GLCanvas3D* canvas3D=static_cast(m_plater->canvas3D()); for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) { if (!plates_have_wipe_tower[bedid]) { + wipe_tower_ap.translation = {0, 0}; + wipe_tower_ap.poly.contour.points = canvas3D->estimate_wipe_tower_points(bedid); wipe_tower_ap.bed_idx = bedid; m_unselected.emplace_back(wipe_tower_ap); }